Fix mixed UTF16 issue (LabVIEW) and fix ANSFR for Intel

This commit is contained in:
2026-04-08 08:47:10 +10:00
parent 866e0282e2
commit a4a8caaa86
10 changed files with 594 additions and 38 deletions

View File

@@ -372,6 +372,7 @@ namespace ANSCENTER {
bool ANSFacialRecognition::LoadEngine() {
try {
ANS_DBG("ANSFR", "LoadEngine: starting");
// Unload existing engine (handles its own locking)
UnloadEngine();
@@ -379,17 +380,23 @@ namespace ANSCENTER {
{
std::lock_guard<std::mutex> lock(_configMutex);
ANS_DBG("ANSFR", "LoadEngine: InitializeDetector...");
if (!InitializeDetector()) {
LogThreadSafe("ANSFacialRecognition::LoadEngine",
"Failed to initialize detector");
ANS_DBG("ANSFR", "LoadEngine: InitializeDetector FAILED");
return false;
}
ANS_DBG("ANSFR", "LoadEngine: InitializeDetector OK");
ANS_DBG("ANSFR", "LoadEngine: InitializeRecognizer...");
if (!InitializeRecognizer()) {
LogThreadSafe("ANSFacialRecognition::LoadEngine",
"Failed to initialize recognizer");
ANS_DBG("ANSFR", "LoadEngine: InitializeRecognizer FAILED");
return false;
}
ANS_DBG("ANSFR", "LoadEngine: InitializeRecognizer OK");
_recognizerModelFolder = _recognizer->GetModelFolder();
}
@@ -402,7 +409,9 @@ namespace ANSCENTER {
}
// Configure device
ANS_DBG("ANSFR", "LoadEngine: getting OpenVINO device...");
std::string deviceName = GetOpenVINODevice();
ANS_DBG("ANSFR", "LoadEngine: OpenVINO device=%s", deviceName.c_str());
if (deviceName == "NPU") {
// Configure NPU with GPU fallback
@@ -795,6 +804,7 @@ namespace ANSCENTER {
}
bool ANSFacialRecognition::InitializeRecognizer() {
try {
ANS_DBG("ANSFR", "InitializeRecognizer: starting, modelPath=%s", _recognizerFilePath.c_str());
// Create recognizer instance
_recognizer = std::make_unique<ANSFaceRecognizer>();
_recognizer->SetMaxSlotsPerGpu(m_maxSlotsPerGpu);
@@ -810,6 +820,9 @@ namespace ANSCENTER {
recognizerConfig.modelConfThreshold = 0.48f;
recognizerConfig.unknownPersonThreshold = _config._knownPersonThreshold;
ANS_DBG("ANSFR", "InitializeRecognizer: knownPersonThreshold=%.3f NMS=%.3f bbox=%.3f",
_config._knownPersonThreshold, _config._detThresholdNMS, _config._detThresholdBbox);
// LOCK DURING INITIALIZATION
std::string labelMap;
bool initSuccess;
@@ -817,6 +830,7 @@ namespace ANSCENTER {
{
std::lock_guard<std::mutex> lock(_recognitionMutex);
ANS_DBG("ANSFR", "InitializeRecognizer: calling _recognizer->Initialize...");
initSuccess = _recognizer->Initialize(
_licenseKey,
recognizerConfig,
@@ -829,12 +843,15 @@ namespace ANSCENTER {
if (!initSuccess) {
LogThreadSafe("ANSFacialRecognition::InitializeRecognizer",
"Failed to initialize recognizer - check file path: " + _recognizerFilePath);
ANS_DBG("ANSFR", "InitializeRecognizer: FAILED - path=%s", _recognizerFilePath.c_str());
return false;
}
ANS_DBG("ANSFR", "InitializeRecognizer: SUCCESS");
return true;
}
catch (const std::exception& e) {
ANS_DBG("ANSFR", "InitializeRecognizer EXCEPTION: %s", e.what());
LogThreadSafe("ANSFacialRecognition::InitializeRecognizer",
"Failed to initialize: " + std::string(e.what()));
return false;
@@ -2674,13 +2691,19 @@ namespace ANSCENTER {
std::string ANSFacialRecognition::GetOpenVINODevice() {
ov::Core core;
std::vector<std::string> available_devices = core.get_available_devices();
ANS_DBG("ANSFR", "GetOpenVINODevice: %zu devices available", available_devices.size());
for (const auto& d : available_devices) {
ANS_DBG("ANSFR", " OpenVINO device: %s", d.c_str());
}
// Prioritize devices: NPU > GPU > CPU
std::vector<std::string> priority_devices = { "NPU","GPU","CPU" };
for (const auto& device : priority_devices) {
if (std::find(available_devices.begin(), available_devices.end(), device) != available_devices.end()) {
ANS_DBG("ANSFR", "GetOpenVINODevice: selected %s", device.c_str());
return device; // Return the first available device based on priority
}
}
ANS_DBG("ANSFR", "GetOpenVINODevice: fallback to CPU");
return "CPU";
}

View File

@@ -363,6 +363,10 @@ extern "C" ANSFR_API int GetFaces(ANSCENTER::ANSFacialRecognition * *Handle,i
extern "C" ANSFR_API int DeleteFacesByUser(ANSCENTER::ANSFacialRecognition * *Handle,int userId);
extern "C" ANSFR_API double BlurCalculation(unsigned char* jpeg_string, unsigned int bufferLength);
// LStrHandle-based InsertUser/UpdateUser — handles UTF-16LE and UTF-8 input from LabVIEW
extern "C" ANSFR_API int InsertUser_LV(ANSCENTER::ANSFacialRecognition * *Handle, const char* userCode, LStrHandle userName);
extern "C" ANSFR_API int UpdateUser_LV(ANSCENTER::ANSFacialRecognition * *Handle, int userId, const char* userCode, LStrHandle userName);
// Unicode conversion utilities for LabVIEW wrapper classes
extern "C" ANSFR_API int ANSFR_ConvertUTF8ToUTF16LE(const char* utf8Str, LStrHandle result, int includeBOM = 1);
extern "C" ANSFR_API int ANSFR_ConvertUTF16LEToUTF8(const unsigned char* utf16leBytes, int byteLen, LStrHandle result);

View File

@@ -22,12 +22,19 @@ namespace ANSCENTER {
ov::Core core;
std::vector<std::string> available_devices = core.get_available_devices();
ANS_DBG("FaceRecognizer", "OpenVINO available devices: %zu", available_devices.size());
for (const auto& d : available_devices) {
ANS_DBG("FaceRecognizer", " OpenVINO device: %s", d.c_str());
}
std::vector<std::string> priority_devices = { "GPU", "CPU" };
for (const auto& device : priority_devices) {
if (std::find(available_devices.begin(), available_devices.end(), device) != available_devices.end()) {
ANS_DBG("FaceRecognizer", "OpenVINO selected device: %s", device.c_str());
return device;
}
}
ANS_DBG("FaceRecognizer", "OpenVINO fallback to CPU");
return "CPU";
}
@@ -37,12 +44,18 @@ namespace ANSCENTER {
const std::string& modelZipPassword,
std::string& labelMap)
{
ANS_DBG("FaceRecognizer", "Initialize: modelZip=%s", modelZipFilePath.c_str());
bool result = ANSFRBase::Initialize(licenseKey, modelConfig, modelZipFilePath, modelZipPassword, labelMap);
if (!result) return false;
if (!result) {
ANS_DBG("FaceRecognizer", "ANSFRBase::Initialize FAILED");
return false;
}
#ifdef CPU_MODE
engineType = EngineType::CPU;
ANS_DBG("FaceRecognizer", "CPU_MODE forced: engineType=CPU");
#else
engineType = ANSLicenseHelper::CheckHardwareInformation();
ANS_DBG("FaceRecognizer", "HW detection: engineType=%d", static_cast<int>(engineType));
#endif
try {
_modelConfig = modelConfig;
@@ -52,6 +65,12 @@ namespace ANSCENTER {
m_knownPersonThresh = _modelConfig.unknownPersonThreshold;
if (m_knownPersonThresh == 0.0f) m_knownPersonThresh = 0.35f;
ANS_DBG("FaceRecognizer", "engineType=%d (NVIDIA=%d, OPENVINO=%d, AMD=%d, CPU=%d)",
static_cast<int>(engineType),
static_cast<int>(EngineType::NVIDIA_GPU),
static_cast<int>(EngineType::OPENVINO_GPU),
static_cast<int>(EngineType::AMD_GPU),
static_cast<int>(EngineType::CPU));
if (engineType == EngineType::NVIDIA_GPU) {
// 1. Load ONNX model
std::string onnxfile = CreateFilePath(_modelFolder, "ansfacerecognizer.onnx");
@@ -97,6 +116,11 @@ namespace ANSCENTER {
_modelFilePath, __FILE__, __LINE__);
return false;
}
// Create CUDA stream for GPU preprocessing (lazy init)
if (!m_gpuStream) {
m_gpuStream = std::make_unique<cv::cuda::Stream>();
}
}
}
else {
@@ -112,10 +136,13 @@ namespace ANSCENTER {
_modelFilePath, __FILE__, __LINE__);
return false;
}
faceRecognizer = std::make_unique<GlintArcFace>(faceidModel);
ANS_DBG("FaceRecognizer", "Creating GlintArcFace with engineType=%d model=%s",
static_cast<int>(engineType), faceidModel.c_str());
faceRecognizer = std::make_unique<GlintArcFace>(faceidModel, engineType);
if (!faceRecognizer) {
_logger.LogFatal("ANSFaceRecognizer::Initialize",
"Failed to initialize ONNX face recognizer", __FILE__, __LINE__);
ANS_DBG("FaceRecognizer", "FAILED: GlintArcFace returned null");
return false;
}
#else
@@ -151,6 +178,7 @@ namespace ANSCENTER {
return true;
}
catch (const std::exception& e) {
ANS_DBG("FaceRecognizer", "Initialize EXCEPTION: %s", e.what());
_logger.LogFatal("ANSFaceRecognizer::Initialize", e.what(), __FILE__, __LINE__);
return false;
}
@@ -688,8 +716,8 @@ namespace ANSCENTER {
}
cv::Mat cpuRGB;
cv::cvtColor(cpuResized, cpuRGB, cv::COLOR_BGR2RGB);
m_gpuRgb.upload(cpuRGB, m_gpuStream);
m_gpuStream.waitForCompletion();
m_gpuRgb.upload(cpuRGB, *m_gpuStream);
m_gpuStream->waitForCompletion();
// Prepare inference inputs
std::vector<cv::cuda::GpuMat> inputVec;
@@ -703,7 +731,7 @@ namespace ANSCENTER {
bool succ = m_trtEngine->runInference(inputs, featureVectors);
// Synchronize stream
m_gpuStream.waitForCompletion();
m_gpuStream->waitForCompletion();
if (!succ) {
_logger.LogError("ANSFaceRecognizer::RunArcFace",
@@ -783,11 +811,11 @@ namespace ANSCENTER {
cv::cuda::GpuMat d_img = gpuFaceROIs[i]; // already on GPU
if (d_img.cols != GPU_FACE_WIDTH || d_img.rows != GPU_FACE_HEIGHT) {
cv::cuda::GpuMat d_resized;
cv::cuda::resize(d_img, d_resized, targetSize, 0, 0, cv::INTER_LINEAR, m_gpuStream);
cv::cuda::resize(d_img, d_resized, targetSize, 0, 0, cv::INTER_LINEAR, *m_gpuStream);
d_img = d_resized;
}
cv::cuda::GpuMat d_rgb;
cv::cuda::cvtColor(d_img, d_rgb, cv::COLOR_BGR2RGB, 0, m_gpuStream);
cv::cuda::cvtColor(d_img, d_rgb, cv::COLOR_BGR2RGB, 0, *m_gpuStream);
batchGpu.emplace_back(std::move(d_rgb));
} else {
const auto& roi = faceROIs[i];
@@ -807,7 +835,7 @@ namespace ANSCENTER {
cv::Mat cpuRGB;
cv::cvtColor(cpuResized, cpuRGB, cv::COLOR_BGR2RGB);
cv::cuda::GpuMat d_rgb;
d_rgb.upload(cpuRGB, m_gpuStream);
d_rgb.upload(cpuRGB, *m_gpuStream);
batchGpu.emplace_back(std::move(d_rgb));
}
}
@@ -823,7 +851,7 @@ namespace ANSCENTER {
FR_START_TIMER(trt_infer);
std::vector<std::vector<std::vector<float>>> featureVectors;
bool succ = m_trtEngine->runInference(inputs, featureVectors);
m_gpuStream.waitForCompletion();
m_gpuStream->waitForCompletion();
FR_END_TIMER(trt_infer, "RunArcFaceBatch TRT inference (batch=" + std::to_string(actualCount) + ")");
if (!succ) {

View File

@@ -112,7 +112,9 @@ namespace ANSCENTER {
const int CPU_FACE_HEIGHT = 160;
#endif
// Pooled GPU buffers to avoid per-frame allocation (Fix #8)
cv::cuda::Stream m_gpuStream;
// Lazy-initialized: only created when engineType == NVIDIA_GPU
// to avoid triggering CUDA init on non-NVIDIA systems.
std::unique_ptr<cv::cuda::Stream> m_gpuStream;
cv::cuda::GpuMat m_gpuImg;
cv::cuda::GpuMat m_gpuResized;
cv::cuda::GpuMat m_gpuRgb;