Skip to content

Commit

Permalink
Merge pull request #134 from HyperInspire/dev/pitch-2
Browse files Browse the repository at this point in the history
Dev/pitch 2
  • Loading branch information
tunmx authored Jan 2, 2025
2 parents 12dafef + cb593fa commit 4eda5d6
Show file tree
Hide file tree
Showing 9 changed files with 512 additions and 16 deletions.
40 changes: 30 additions & 10 deletions .github/workflows/release-sdks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ jobs:
# Step 6: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-linux-x86-ubuntu18-${{ env.VERSION }}.zip build/inspireface-linux-x86-ubuntu18-${{ env.VERSION }}
cd build
zip -r ../inspireface-linux-x86-ubuntu18-${{ env.VERSION }}.zip inspireface-linux-x86-ubuntu18-${{ env.VERSION }}
cd ..
stat inspireface-linux-x86-ubuntu18-${{ env.VERSION }}.zip
# Step 7: Upload the zipped SDK files for the next job
Expand Down Expand Up @@ -103,7 +105,9 @@ jobs:
# Step 8: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-linux-armv7-armhf-${{ env.VERSION }}.zip build/inspireface-linux-armv7-armhf-${{ env.VERSION }}
cd build
zip -r ../inspireface-linux-armv7-armhf-${{ env.VERSION }}.zip inspireface-linux-armv7-armhf-${{ env.VERSION }}
cd ..
stat inspireface-linux-armv7-armhf-${{ env.VERSION }}.zip
# Step 9: Upload the zipped SDK files for the next job
Expand Down Expand Up @@ -160,7 +164,9 @@ jobs:
# Step 8: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-linux-armv7-rv1109rv1126-armhf-${{ env.VERSION }}.zip build/inspireface-linux-armv7-rv1109rv1126-armhf-${{ env.VERSION }}
cd build
zip -r ../inspireface-linux-armv7-rv1109rv1126-armhf-${{ env.VERSION }}.zip inspireface-linux-armv7-rv1109rv1126-armhf-${{ env.VERSION }}
cd ..
stat inspireface-linux-armv7-rv1109rv1126-armhf-${{ env.VERSION }}.zip
# Step 9: Upload the zipped SDK files for the next job
Expand Down Expand Up @@ -217,7 +223,9 @@ jobs:
# Step 8: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-linux-aarch64-${{ env.VERSION }}.zip build/inspireface-linux-aarch64-${{ env.VERSION }}
cd build
zip -r ../inspireface-linux-aarch64-${{ env.VERSION }}.zip inspireface-linux-aarch64-${{ env.VERSION }}
cd ..
stat inspireface-linux-aarch64-${{ env.VERSION }}.zip
# Step 9: Upload the zipped SDK files for the next job
Expand Down Expand Up @@ -289,7 +297,9 @@ jobs:
# Step 10: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-android-${{ env.VERSION }}.zip build/inspireface-android-${{ env.VERSION }}
cd build
zip -r ../inspireface-android-${{ env.VERSION }}.zip inspireface-android-${{ env.VERSION }}
cd ..
stat inspireface-android-${{ env.VERSION }}.zip
# Step 11: Upload the zipped SDK files for the next job
Expand Down Expand Up @@ -328,7 +338,9 @@ jobs:
# Step 5: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-ios-${{ env.VERSION }}.zip build/inspireface-ios-${{ env.VERSION }}
cd build
zip -r ../inspireface-ios-${{ env.VERSION }}.zip inspireface-ios-${{ env.VERSION }}
cd ..
stat inspireface-ios-${{ env.VERSION }}.zip
# Step 6: Upload the zipped SDK files for the next job
Expand Down Expand Up @@ -373,7 +385,9 @@ jobs:
# Step 6: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-linux-x86-manylinux2014-${{ env.VERSION }}.zip build/inspireface-linux-x86-manylinux2014-${{ env.VERSION }}
cd build
zip -r ../inspireface-linux-x86-manylinux2014-${{ env.VERSION }}.zip inspireface-linux-x86-manylinux2014-${{ env.VERSION }}
cd ..
stat inspireface-linux-x86-manylinux2014-${{ env.VERSION }}.zip
# Step 7: Upload the zipped SDK files for the next job
Expand Down Expand Up @@ -429,7 +443,9 @@ jobs:
# Step 8: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-linux-armv7-rv1106-armhf-uclibc-${{ env.VERSION }}.zip build/inspireface-linux-armv7-rv1106-armhf-uclibc-${{ env.VERSION }}
cd build
zip -r ../inspireface-linux-armv7-rv1106-armhf-uclibc-${{ env.VERSION }}.zip inspireface-linux-armv7-rv1106-armhf-uclibc-${{ env.VERSION }}
cd ..
stat inspireface-linux-armv7-rv1106-armhf-uclibc-${{ env.VERSION }}.zip
# Step 9: Upload the zipped SDK files for the next job
Expand Down Expand Up @@ -473,7 +489,9 @@ jobs:
# Step 6: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-macos-apple-silicon-arm64-${{ env.VERSION }}.zip build/inspireface-macos-apple-silicon-arm64-${{ env.VERSION }}
cd build
zip -r ../inspireface-macos-apple-silicon-arm64-${{ env.VERSION }}.zip inspireface-macos-apple-silicon-arm64-${{ env.VERSION }}
cd ..
stat inspireface-macos-apple-silicon-arm64-${{ env.VERSION }}.zip
# Step 7: Upload the zipped SDK files for the next job
Expand Down Expand Up @@ -517,7 +535,9 @@ jobs:
# Step 6: Zip SDK directory
- name: Zip SDK directory
run: |
zip -r inspireface-macos-intel-x86-64-${{ env.VERSION }}.zip build/inspireface-macos-intel-x86-64-${{ env.VERSION }}
cd build
zip -r ../inspireface-macos-intel-x86-64-${{ env.VERSION }}.zip inspireface-macos-intel-x86-64-${{ env.VERSION }}
cd ..
stat inspireface-macos-intel-x86-64-${{ env.VERSION }}.zip
# Step 7: Upload the zipped SDK files for the next job
Expand Down
148 changes: 148 additions & 0 deletions cpp/inspireface/middleware/thread/resource_pool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#ifndef INSPIRE_RESOURCE_POOL_H
#define INSPIRE_RESOURCE_POOL_H

#include <iostream>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <memory>
#include <functional>

namespace inspire {
namespace parallel {

/**
* @brief ResourcePool is a thread-safe resource pool that can be used to manage resources in a multi-threaded environment.
* @tparam Resource The type of the resource to be managed.
*/
template <typename Resource>
class ResourcePool {
public:
using ResourceDeleter = std::function<void(Resource&)>;

class ResourceGuard {
public:
ResourceGuard(Resource& resource, ResourcePool& pool) : m_resource(resource), m_pool(pool), m_valid(true) {}

// Move constructor
ResourceGuard(ResourceGuard&& other) noexcept : m_resource(other.m_resource), m_pool(other.m_pool), m_valid(other.m_valid) {
other.m_valid = false;
}

// Disable copy
ResourceGuard(const ResourceGuard&) = delete;
ResourceGuard& operator=(const ResourceGuard&) = delete;

~ResourceGuard() {
if (m_valid) {
m_pool.ReturnResource(std::move(m_resource));
}
}

Resource* operator->() {
return &m_resource;
}

Resource& operator*() {
return m_resource;
}

private:
Resource& m_resource;
ResourcePool& m_pool;
bool m_valid;
};

explicit ResourcePool(size_t size, ResourceDeleter deleter = nullptr) : m_deleter(deleter) {
m_resources.reserve(size);
}

~ResourcePool() {
if (m_deleter) {
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& resource : m_resources) {
m_deleter(resource);
}
}
}

void AddResource(Resource&& resource) {
std::lock_guard<std::mutex> lock(m_mutex);
m_resources.push_back(std::move(resource));
m_available_resources.push(&m_resources.back());
m_cv.notify_one();
}

// Acquire resource (blocking mode)
ResourceGuard AcquireResource() {
std::unique_lock<std::mutex> lock(m_mutex);
m_cv.wait(lock, [this] { return !m_available_resources.empty(); });

Resource* resource = m_available_resources.front();
m_available_resources.pop();

return ResourceGuard(*resource, *this);
}

// Try to acquire resource (non-blocking mode), returns nullptr if no resource available
std::unique_ptr<ResourceGuard> TryAcquireResource() {
std::lock_guard<std::mutex> lock(m_mutex);
if (m_available_resources.empty()) {
return nullptr;
}

Resource* resource = m_available_resources.front();
m_available_resources.pop();

return std::unique_ptr<ResourceGuard>(new ResourceGuard(*resource, *this));
}

// Acquire resource with timeout, returns nullptr if timeout
std::unique_ptr<ResourceGuard> AcquireResource(std::chrono::milliseconds timeout) {
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_cv.wait_for(lock, timeout, [this] { return !m_available_resources.empty(); })) {
return nullptr;
}

Resource* resource = m_available_resources.front();
m_available_resources.pop();

return std::unique_ptr<ResourceGuard>(new ResourceGuard(*resource, *this));
}

size_t AvailableCount() const {
std::lock_guard<std::mutex> lock(m_mutex);
return m_available_resources.size();
}

size_t TotalCount() const {
std::lock_guard<std::mutex> lock(m_mutex);
return m_resources.size();
}

private:
void ReturnResource(Resource&& resource) {
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& stored_resource : m_resources) {
if (&stored_resource == &resource) {
m_available_resources.push(&stored_resource);
m_cv.notify_one();
break;
}
}
}

private:
mutable std::mutex m_mutex;
std::condition_variable m_cv;
std::vector<Resource> m_resources; // Store actual resources
std::queue<Resource*> m_available_resources; // Queue of available resources
ResourceDeleter m_deleter; // Resource cleanup callback

friend class ResourceGuard;
};

} // namespace parallel
} // namespace inspire

#endif // INSPIRE_RESOURCE_POOL_H
2 changes: 2 additions & 0 deletions cpp/test/settings/test_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ using namespace Catch::Detail;
#define TEST_PRINT_OUTPUT(open) TestMessageBroadcast test_msg_broadcast_##open(open)
// Set the log output level
#define LOG_OUTPUT_LEVEL(level) LogLevelBroadcast log_level_broadcast_##level(level);
// Print test error message
#define TEST_ERROR_PRINT(...) SPDLOG_LOGGER_CALL(spdlog::get("TEST"), spdlog::level::err, __VA_ARGS__)

// Get the test data directory
#define GET_DIR getTestDataDir()
Expand Down
4 changes: 2 additions & 2 deletions cpp/test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@ int main(int argc, char* argv[]) {
SET_RUNTIME_FULLPATH_NAME(fullPath);
}

std::cout << fullPath << std::endl;
TEST_PRINT("Launching InspireFace with path: {}", fullPath);
auto ret = HFLaunchInspireFace(fullPath.c_str());
if (ret != HSUCCEED) {
spdlog::error("An error occurred while starting InspireFace: {}", ret);
TEST_ERROR_PRINT("An error occurred while starting InspireFace: {}", ret);
return ret;
}

Expand Down
81 changes: 81 additions & 0 deletions cpp/test/unit/api/test_face_pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "settings/test_settings.h"
#include "inspireface/c_api/inspireface.h"
#include "../test_helper/test_tools.h"
#include "../test_helper/test_help.h"

TEST_CASE("test_FacePipelineAttribute", "[face_pipeline_attribute]") {
DRAW_SPLIT_LINE
Expand Down Expand Up @@ -396,3 +397,83 @@ TEST_CASE("test_FaceReaction", "[face_reaction]") {
ret = HFReleaseInspireFaceSession(session);
REQUIRE(ret == HSUCCEED);
}

TEST_CASE("test_TrackModeFaceAction", "[face_action]") {
DRAW_SPLIT_LINE
TEST_PRINT_OUTPUT(true);

HResult ret;
HFSessionCustomParameter parameter = {0};
parameter.enable_interaction_liveness = 1;
HFDetectMode detMode = HF_DETECT_MODE_LIGHT_TRACK;
HFSession session;
ret = HFCreateInspireFaceSession(parameter, detMode, 3, -1, -1, &session);
REQUIRE(ret == HSUCCEED);

SECTION("Action Blink") {
auto start = 130, end = 150;
std::vector<std::string> filenames = generateFilenames("frame-%04d.jpg", start, end);
int count = 0;
for (size_t i = 0; i < filenames.size(); i++) {
auto filename = filenames[i];
HFImageStream imgHandle;
auto image = inspirecv::Image::Create(GET_DATA("data/video_frames/" + filename));
ret = CVImageToImageStream(image, imgHandle);
REQUIRE(ret == HSUCCEED);

HFMultipleFaceData multipleFaceData = {0};
ret = HFExecuteFaceTrack(session, imgHandle, &multipleFaceData);
REQUIRE(ret == HSUCCEED);
REQUIRE(multipleFaceData.detectedNum > 0);

ret = HFMultipleFacePipelineProcessOptional(session, imgHandle, &multipleFaceData, HF_ENABLE_INTERACTION);
REQUIRE(ret == HSUCCEED);

HFFaceInteractionsActions result;
ret = HFGetFaceInteractionActionsResult(session, &result);
REQUIRE(ret == HSUCCEED);
REQUIRE(multipleFaceData.detectedNum == result.num);

count += result.blink[0];
ret = HFReleaseImageStream(imgHandle);
REQUIRE(ret == HSUCCEED);
}
// Blink at least once
REQUIRE(count > 0);
}

SECTION("Action Jaw Open") {
auto start = 110, end = 150;
std::vector<std::string> filenames = generateFilenames("frame-%04d.jpg", start, end);
int count = 0;
for (size_t i = 0; i < filenames.size(); i++) {
auto filename = filenames[i];
HFImageStream imgHandle;
auto image = inspirecv::Image::Create(GET_DATA("data/video_frames/" + filename));
ret = CVImageToImageStream(image, imgHandle);
REQUIRE(ret == HSUCCEED);

HFMultipleFaceData multipleFaceData = {0};
ret = HFExecuteFaceTrack(session, imgHandle, &multipleFaceData);
REQUIRE(ret == HSUCCEED);
REQUIRE(multipleFaceData.detectedNum > 0);

ret = HFMultipleFacePipelineProcessOptional(session, imgHandle, &multipleFaceData, HF_ENABLE_INTERACTION);
REQUIRE(ret == HSUCCEED);

HFFaceInteractionsActions result;
ret = HFGetFaceInteractionActionsResult(session, &result);
REQUIRE(ret == HSUCCEED);
REQUIRE(multipleFaceData.detectedNum == result.num);

count += result.jawOpen[0];
ret = HFReleaseImageStream(imgHandle);
REQUIRE(ret == HSUCCEED);
}
// Jaw open at least once
REQUIRE(count > 0);
}

ret = HFReleaseInspireFaceSession(session);
REQUIRE(ret == HSUCCEED);
}
2 changes: 1 addition & 1 deletion cpp/test/unit/api/test_face_track.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ TEST_CASE("test_FaceTrack", "[face_track]") {
HFDetectMode detMode = HF_DETECT_MODE_ALWAYS_DETECT;
HFSession session;
ret = HFCreateInspireFaceSession(parameter, detMode, 3, -1, -1, &session);
spdlog::error("error ret :{}", ret);
TEST_ERROR_PRINT("error ret :{}", ret);
REQUIRE(ret == HSUCCEED);

// Get a face picture
Expand Down
Loading

0 comments on commit 4eda5d6

Please sign in to comment.