// dllmain.cpp : Defines the entry point for the DLL application. #include "pch.h" #include "ANSOCRBase.h" #include "ANSCpuOCR.h" #include "ANSOnnxOCR.h" #include "ANSRtOCR.h" #include "ANSLibsLoader.h" #include "ANSGpuFrameRegistry.h" #include "NV12PreprocessHelper.h" #include #include #include // Handle registry with refcount — prevents use-after-free when // ReleaseANSOCRHandle is called while inference is still running. static std::unordered_map& OCRHandleRegistry() { static std::unordered_map s; return s; } static std::mutex& OCRHandleRegistryMutex() { static std::mutex m; return m; } static std::condition_variable& OCRHandleRegistryCV() { static std::condition_variable cv; return cv; } static void RegisterOCRHandle(ANSCENTER::ANSOCRBase* h) { std::lock_guard lk(OCRHandleRegistryMutex()); OCRHandleRegistry()[h] = 1; // refcount = 1 } static ANSCENTER::ANSOCRBase* AcquireOCRHandle(ANSCENTER::ANSOCRBase* h) { std::lock_guard lk(OCRHandleRegistryMutex()); auto it = OCRHandleRegistry().find(h); if (it == OCRHandleRegistry().end()) return nullptr; it->second++; return h; } static bool ReleaseOCRHandleRef(ANSCENTER::ANSOCRBase* h) { std::lock_guard lk(OCRHandleRegistryMutex()); auto it = OCRHandleRegistry().find(h); if (it == OCRHandleRegistry().end()) return false; it->second--; if (it->second <= 0) { OCRHandleRegistry().erase(it); OCRHandleRegistryCV().notify_all(); return true; } return false; } static bool UnregisterOCRHandle(ANSCENTER::ANSOCRBase* h) { std::unique_lock lk(OCRHandleRegistryMutex()); auto it = OCRHandleRegistry().find(h); if (it == OCRHandleRegistry().end()) return false; it->second--; bool ok = OCRHandleRegistryCV().wait_for(lk, std::chrono::seconds(5), [&]() { auto it2 = OCRHandleRegistry().find(h); return it2 == OCRHandleRegistry().end() || it2->second <= 0; }); if (!ok) { OutputDebugStringA("WARNING: UnregisterOCRHandle timed out waiting for in-flight inference\n"); } OCRHandleRegistry().erase(h); return true; } // RAII guard — ensures ReleaseOCRHandleRef is always called, preventing // refcount leaks that would cause UnregisterOCRHandle to deadlock. class OCRHandleGuard { ANSCENTER::ANSOCRBase* engine; public: explicit OCRHandleGuard(ANSCENTER::ANSOCRBase* e) : engine(e) {} ~OCRHandleGuard() { if (engine) ReleaseOCRHandleRef(engine); } ANSCENTER::ANSOCRBase* get() const { return engine; } explicit operator bool() const { return engine != nullptr; } OCRHandleGuard(const OCRHandleGuard&) = delete; OCRHandleGuard& operator=(const OCRHandleGuard&) = delete; }; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } // Extended version with limitSideLen parameter — new callers should use this. extern "C" ANSOCR_API int CreateANSOCRHandleEx(ANSCENTER::ANSOCRBase** Handle, const char* licenseKey, const char* modelFilePath, const char* modelFileZipPassword, int language, int engineMode, // 0: autodetect, 1 gpu, 2 cpu int gpuId, double detectorDBThreshold, double detectorDBBoxThreshold, double detectorDBUnclipRatio, double classifierThreshold, int useDilation, int limitSideLen) { try { // Ensure all shared DLLs (OpenCV, OpenVINO, TRT, ORT) are pre-loaded ANSCENTER::ANSLibsLoader::Initialize(); ANSCENTER::EngineType engineType = ANSCENTER::ANSLicenseHelper::CheckHardwareInformation(); // Release existing handle if called twice (prevents leak from LabVIEW) if (*Handle) { if (UnregisterOCRHandle(*Handle)) { (*Handle)->Destroy(); delete *Handle; } *Handle = nullptr; } // Validate limitSideLen: must be in (0, 20000], default to 960 if (limitSideLen <= 0 || limitSideLen > 20000) limitSideLen = 960; // Backward compatibility: legacy PaddleOCR model uses CPU OCR engine std::string modelPath(modelFilePath ? modelFilePath : ""); bool isLegacyModel = (modelPath.find("ANS_GenericOCR_v1.0") != std::string::npos); if (isLegacyModel) { (*Handle) = new ANSCENTER::ANSCPUOCR(); } else { switch (engineMode) { case 0:// Auto-detect, always use ONNX for better compatibility, especially on AMD GPUs and high-res images (*Handle) = new ANSCENTER::ANSONNXOCR(); break; case 1:// GPU — use TensorRT engine. limitSideLen = 960; (*Handle) = new ANSCENTER::ANSRTOCR(); break; case 2:// CPU (*Handle) = new ANSCENTER::ANSONNXOCR(); break; default: (*Handle) = new ANSCENTER::ANSONNXOCR(); break; } } if (*Handle == nullptr) return 0; else { RegisterOCRHandle(*Handle); ANSCENTER::OCRModelConfig modelConfig; switch (language) { case 0: { modelConfig.ocrLanguage = ANSCENTER::OCRLanguage::ENGLISH; break; } case 1: { modelConfig.ocrLanguage = ANSCENTER::OCRLanguage::CHINESE; break; } case 2: { modelConfig.ocrLanguage = ANSCENTER::OCRLanguage::FRENCH; break; } case 3: { modelConfig.ocrLanguage = ANSCENTER::OCRLanguage::GERMANY; break; } case 4: { modelConfig.ocrLanguage = ANSCENTER::OCRLanguage::JAPANESE; break; } case 5: { modelConfig.ocrLanguage = ANSCENTER::OCRLanguage::KOREAN; break; } case 6: { modelConfig.ocrLanguage = ANSCENTER::OCRLanguage::CUSTOM; break; } default: { modelConfig.ocrLanguage = ANSCENTER::OCRLanguage::ENGLISH; break; } } modelConfig.useDetector = true; modelConfig.useRecognizer = true; modelConfig.useCLS = true; modelConfig.useLayout = false; modelConfig.useTable = false; modelConfig.useTensorRT = false; modelConfig.enableMKLDNN = false; modelConfig.useDilation = false; modelConfig.useAngleCLS = false; modelConfig.gpuId = gpuId; modelConfig.detectionDBThreshold = detectorDBThreshold; modelConfig.detectionBoxThreshold = detectorDBBoxThreshold; modelConfig.detectionDBUnclipRatio = detectorDBUnclipRatio; modelConfig.clsThreshold = classifierThreshold; if (useDilation == 1)modelConfig.useDilation = true; modelConfig.limitSideLen = limitSideLen; int result = (*Handle)->Initialize(licenseKey, modelConfig, modelFilePath, modelFileZipPassword, engineMode); return result; } } catch (std::exception& e) { return 0; } catch (...) { return 0; } } // Original signature (without limitSideLen) — kept for backward compatibility // with third-party apps already built against the old DLL. extern "C" ANSOCR_API int CreateANSOCRHandle(ANSCENTER::ANSOCRBase** Handle, const char* licenseKey, const char* modelFilePath, const char* modelFileZipPassword, int language, int engineMode, // 0: autodetect, 1 gpu, 2 cpu int gpuId, double detectorDBThreshold, double detectorDBBoxThreshold, double detectorDBUnclipRatio, double classifierThreshold, int useDilation) { return CreateANSOCRHandleEx(Handle, licenseKey, modelFilePath, modelFileZipPassword, language, engineMode, gpuId, detectorDBThreshold, detectorDBBoxThreshold, detectorDBUnclipRatio, classifierThreshold, useDilation, 960); } extern "C" ANSOCR_API std::string RunInference(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_string, int32 bufferLength) { if (!Handle || !*Handle) return ""; OCRHandleGuard guard(AcquireOCRHandle(*Handle)); if (!guard) return ""; auto* engine = guard.get(); try { cv::Mat frame = cv::imdecode(cv::Mat(1, bufferLength, CV_8UC1, jpeg_string), cv::IMREAD_COLOR); if (frame.empty()) return ""; std::vector outputs = engine->RunInference(frame); std::string stResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(outputs); frame.release(); outputs.clear(); return stResult; } catch (...) { return ""; } } extern "C" ANSOCR_API std::string RunInferenceWithCamID(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_string, int32 bufferLength, const char* cameraId) { if (!Handle || !*Handle) return ""; OCRHandleGuard guard(AcquireOCRHandle(*Handle)); if (!guard) return ""; auto* engine = guard.get(); try { cv::Mat frame = cv::imdecode(cv::Mat(1, bufferLength, CV_8UC1, jpeg_string), cv::IMREAD_COLOR); if (frame.empty()) return ""; std::vector outputs = engine->RunInference(frame, cameraId); std::string stResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(outputs); frame.release(); outputs.clear(); return stResult; } catch (...) { return ""; } } extern "C" ANSOCR_API int RunInferenceCV(ANSCENTER::ANSOCRBase** Handle, const cv::Mat& image, std::string& ocrResult) { if (!Handle || !*Handle) return -1; OCRHandleGuard guard(AcquireOCRHandle(*Handle)); if (!guard) return -3; auto* engine = guard.get(); try { if (image.empty()) return 0; std::vector outputs = engine->RunInference(image, "cameraId"); ocrResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(outputs); return 1; } catch (...) { return -2; } } extern "C" ANSOCR_API std::string RunInferenceBinary(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_bytes, unsigned int width, unsigned int height) { if (!Handle || !*Handle || !jpeg_bytes || width == 0 || height == 0) return ""; OCRHandleGuard guard(AcquireOCRHandle(*Handle)); if (!guard) return ""; auto* engine = guard.get(); try { cv::Mat frame = cv::Mat(height, width, CV_8UC3, jpeg_bytes).clone(); if (frame.empty()) return ""; std::vector outputs = engine->RunInference(frame); std::string stResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(outputs); frame.release(); outputs.clear(); return stResult; } catch (...) { return ""; } } static int ReleaseANSOCRHandle_Impl(ANSCENTER::ANSOCRBase** Handle) { try { if (!Handle || !*Handle) return 0; if (!UnregisterOCRHandle(*Handle)) { *Handle = nullptr; return 0; // Not in registry — already freed } (*Handle)->Destroy(); delete *Handle; *Handle = nullptr; return 0; } catch (...) { if (Handle) *Handle = nullptr; return 1; } } extern "C" ANSOCR_API int ReleaseANSOCRHandle(ANSCENTER::ANSOCRBase** Handle) { __try { return ReleaseANSOCRHandle_Impl(Handle); } __except (EXCEPTION_EXECUTE_HANDLER) { return 1; } } extern "C" ANSOCR_API std::string RunInferenceImagePath(ANSCENTER::ANSOCRBase** Handle, const char* imageFilePath) { if (!Handle || !*Handle) return ""; OCRHandleGuard guard(AcquireOCRHandle(*Handle)); if (!guard) return ""; auto* engine = guard.get(); try { std::string stImageFileName(imageFilePath); cv::Mat frame = cv::imread(stImageFileName, cv::ImreadModes::IMREAD_COLOR); if (frame.empty()) return ""; std::vector outputs = engine->RunInference(frame); std::string stResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(outputs); frame.release(); outputs.clear(); return stResult; } catch (...) { return ""; } } extern "C" ANSOCR_API std::string RunInferenceInCroppedImages(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_string, int32 bufferLength, const char* strBboxes) { if (!Handle || !*Handle) return ""; OCRHandleGuard guard(AcquireOCRHandle(*Handle)); if (!guard) return ""; auto* engine = guard.get(); try { cv::Mat frame = cv::imdecode(cv::Mat(1, bufferLength, CV_8UC1, jpeg_string), cv::IMREAD_COLOR); if (frame.empty()) return ""; std::vector bBoxes = ANSCENTER::ANSOCRUtility::GetBoundingBoxes(strBboxes); std::vector outputs = engine->RunInference(frame, bBoxes); std::string stResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(outputs); frame.release(); outputs.clear(); return stResult; } catch (...) { return ""; } } extern "C" ANSOCR_API std::string RunInferenceInCroppedImagesWithCamID(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_string, int32 bufferLength, const char* strBboxes, const char* cameraId) { if (!Handle || !*Handle) return ""; OCRHandleGuard guard(AcquireOCRHandle(*Handle)); if (!guard) return ""; auto* engine = guard.get(); try { cv::Mat frame = cv::imdecode(cv::Mat(1, bufferLength, CV_8UC1, jpeg_string), cv::IMREAD_COLOR); if (frame.empty()) return ""; std::vector bBoxes = ANSCENTER::ANSOCRUtility::GetBoundingBoxes(strBboxes); std::vector outputs = engine->RunInference(frame, bBoxes, cameraId); std::string stResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(outputs); frame.release(); outputs.clear(); return stResult; } catch (...) { return ""; } } //// For LabVIEW API extern "C" ANSOCR_API int RunInference_LV(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_string, int32 bufferLength, LStrHandle detectionResult) { try { std::string st = RunInference(Handle, jpeg_string, bufferLength); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error; error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (std::exception& e) { return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInference_LVWithCamID(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_string, int32 bufferLength, const char* cameraId, LStrHandle detectionResult) { try { std::string st = RunInferenceWithCamID(Handle, jpeg_string, bufferLength, cameraId); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error; error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (std::exception& e) { return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceBinary_LV(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_bytes, unsigned int width, unsigned int height, LStrHandle detectionResult) { try { std::string st = RunInferenceBinary(Handle, jpeg_bytes, width, height); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error; error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (std::exception& e) { return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceImagePath_LV(ANSCENTER::ANSOCRBase** Handle, const char* imageFilePath, LStrHandle detectionResult) { try { std::string st = RunInferenceImagePath(Handle, imageFilePath); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error; error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (std::exception& e) { return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int ANSOCRUnitTest(const char* modelFilePath, const char* imageFilePath, LStrHandle detectionResult) { try { ANSCENTER::ANSOCRBase* infHandle; std::string licenseKey = ""; int language = 0;// English int engine = 0; int createResult = CreateANSOCRHandle(&infHandle, licenseKey.c_str(), modelFilePath, "", language, engine); std::string st = RunInferenceImagePath(&infHandle, imageFilePath); ReleaseANSOCRHandle(&infHandle); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error; error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (std::exception& e) { return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceInCroppedImages_LV(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_string, int32 bufferLength, const char* strBboxes, LStrHandle detectionResult) { try { std::string st = RunInferenceInCroppedImages(Handle, jpeg_string, bufferLength, strBboxes); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error; error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (std::exception& e) { return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceInCroppedImages_LVWithCamID(ANSCENTER::ANSOCRBase** Handle, unsigned char* jpeg_string, int32 bufferLength, const char* strBboxes, const char* cameraId, LStrHandle detectionResult) { try { std::string st = RunInferenceInCroppedImagesWithCamID(Handle, jpeg_string, bufferLength, strBboxes, cameraId); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error; error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (std::exception& e) { return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceComplete_LV( ANSCENTER::ANSOCRBase** Handle, cv::Mat** cvImage, const char* cameraId, int getJpegString, int jpegImageSize, LStrHandle detectionResult, LStrHandle imageStr) { if (!Handle || !*Handle) return -1; if (!cvImage || !(*cvImage) || (*cvImage)->empty()) return -2; OCRHandleGuard guard(AcquireOCRHandle(*Handle)); if (!guard) return -3; auto* engine = guard.get(); try { // Lookup NV12 frame BEFORE cloning (clone creates new cv::Mat*) GpuFrameData* gpuFrame = ANSGpuFrameRegistry::instance().lookup(*cvImage); cv::Mat localImage = (**cvImage).clone(); int originalWidth = localImage.cols; int originalHeight = localImage.rows; if (originalWidth == 0 || originalHeight == 0) return -2; tl_currentGpuFrame() = gpuFrame; std::vector outputs = engine->RunInference(localImage, cameraId); tl_currentGpuFrame() = nullptr; bool getJpeg = (getJpegString == 1); std::string stImage; int maxImageSize = originalWidth; bool resizeNeeded = (jpegImageSize > 0) && (jpegImageSize < maxImageSize); float ratio = 1.0f; int newWidth = originalWidth; int newHeight = originalHeight; if (resizeNeeded) { newWidth = jpegImageSize; newHeight = static_cast(std::round(newWidth * static_cast(originalHeight) / originalWidth)); ratio = static_cast(newWidth) / originalWidth; for (auto& obj : outputs) { obj.box.x = std::max(0, std::min(static_cast(obj.box.x * ratio), newWidth - 1)); obj.box.y = std::max(0, std::min(static_cast(obj.box.y * ratio), newHeight - 1)); obj.box.width = std::max(1, std::min(static_cast(obj.box.width * ratio), newWidth - obj.box.x)); obj.box.height = std::max(1, std::min(static_cast(obj.box.height * ratio), newHeight - obj.box.y)); } } else { for (auto& obj : outputs) { obj.box.x = std::max(0, std::min(static_cast(obj.box.x), originalWidth - 1)); obj.box.y = std::max(0, std::min(static_cast(obj.box.y), originalHeight - 1)); obj.box.width = std::max(1, std::min(static_cast(obj.box.width), originalWidth - obj.box.x)); obj.box.height = std::max(1, std::min(static_cast(obj.box.height), originalHeight - obj.box.y)); } } if (getJpeg) { cv::Mat processedImage = localImage; if (resizeNeeded) { cv::resize(localImage, processedImage, cv::Size(newWidth, newHeight), 0, 0, cv::INTER_AREA); } std::vector buf; if (cv::imencode(".jpg", processedImage, buf, { cv::IMWRITE_JPEG_QUALITY, 50 })) { stImage.assign(buf.begin(), buf.end()); } } std::string stDetectionResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(outputs); if (stDetectionResult.empty()) return 0; int size = static_cast(stDetectionResult.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error != noErr) return 0; (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, stDetectionResult.c_str(), size); if (getJpeg) { if (stImage.empty()) return 0; size = static_cast(stImage.length()); error = DSSetHandleSize(imageStr, sizeof(int32) + size * sizeof(uChar)); if (error != noErr) return 0; (*imageStr)->cnt = size; memcpy((*imageStr)->str, stImage.c_str(), size); } return 1; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferencesComplete_LV(ANSCENTER::ANSOCRBase** Handle, cv::Mat** cvImage, const char* cameraId, int maxImageSize, const char* strBboxes, LStrHandle detectionResult) { if (!Handle || !*Handle) return -1; if (!cvImage || !(*cvImage) || (*cvImage)->empty()) return -2; OCRHandleGuard guard(AcquireOCRHandle(*Handle)); if (!guard) return -3; auto* engine = guard.get(); try { // Lookup NV12 frame BEFORE cloning (clone creates new cv::Mat*) GpuFrameData* gpuFrame = ANSGpuFrameRegistry::instance().lookup(*cvImage); cv::Mat localImage = (**cvImage).clone(); std::vector objectDetectionResults; std::vector bBox = ANSCENTER::ANSOCRUtility::GetBoundingBoxes(strBboxes); const int originalWidth = localImage.cols; const int originalHeight = localImage.rows; const double scaleFactor = (maxImageSize > 0) ? static_cast(originalWidth) / maxImageSize : 1.0; tl_currentGpuFrame() = gpuFrame; if (bBox.empty()) { objectDetectionResults = engine->RunInference(localImage, cameraId); } else { for (const auto& rect : bBox) { cv::Rect scaledRect; scaledRect.x = static_cast(rect.x * scaleFactor); scaledRect.y = static_cast(rect.y * scaleFactor); scaledRect.width = static_cast(rect.width * scaleFactor); scaledRect.height = static_cast(rect.height * scaleFactor); scaledRect &= cv::Rect(0, 0, originalWidth, originalHeight); if (scaledRect.width <= 0 || scaledRect.height <= 0) continue; const cv::Mat croppedImage = localImage(scaledRect); std::vector croppedDetectionResults = engine->RunInference(croppedImage, cameraId); for (auto& obj : croppedDetectionResults) { obj.box.x = (obj.box.x + scaledRect.x) / scaleFactor; obj.box.y = (obj.box.y + scaledRect.y) / scaleFactor; obj.box.width /= scaleFactor; obj.box.height /= scaleFactor; objectDetectionResults.push_back(std::move(obj)); } } } tl_currentGpuFrame() = nullptr; std::string stDetectionResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(objectDetectionResults); if (stDetectionResult.empty()) return 0; const int size = static_cast(stDetectionResult.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error != noErr) return 0; (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, stDetectionResult.c_str(), size); return 1; } catch (...) { return 0; } } // ============================================================================ // V2 LabVIEW API — Accept handle as uint64_t by value. // Eliminates Handle** pointer-to-pointer instability when LabVIEW calls // concurrently from multiple tasks. // LabVIEW CLFN: set Handle parameter to Numeric / Unsigned Pointer-sized Integer / Pass: Value // ============================================================================ // Helper: cast uint64_t handle to ANSOCRBase** for delegation to existing functions #define OCR_V2_HANDLE_SETUP(handleVal) \ ANSCENTER::ANSOCRBase* _v2Direct = reinterpret_cast(handleVal); \ if (_v2Direct == nullptr) return 0; \ ANSCENTER::ANSOCRBase* _v2Arr[1] = { _v2Direct }; \ ANSCENTER::ANSOCRBase** Handle = &_v2Arr[0]; extern "C" ANSOCR_API int RunInference_LV_V2(uint64_t handleVal, unsigned char* jpeg_string, int32 bufferLength, LStrHandle detectionResult) { try { OCR_V2_HANDLE_SETUP(handleVal); std::string st = RunInference(Handle, jpeg_string, bufferLength); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInference_LVWithCamID_V2(uint64_t handleVal, unsigned char* jpeg_string, int32 bufferLength, const char* cameraId, LStrHandle detectionResult) { try { OCR_V2_HANDLE_SETUP(handleVal); std::string st = RunInferenceWithCamID(Handle, jpeg_string, bufferLength, cameraId); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceBinary_LV_V2(uint64_t handleVal, unsigned char* jpeg_bytes, unsigned int width, unsigned int height, LStrHandle detectionResult) { try { OCR_V2_HANDLE_SETUP(handleVal); std::string st = RunInferenceBinary(Handle, jpeg_bytes, width, height); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceImagePath_LV_V2(uint64_t handleVal, const char* imageFilePath, LStrHandle detectionResult) { try { OCR_V2_HANDLE_SETUP(handleVal); std::string st = RunInferenceImagePath(Handle, imageFilePath); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceInCroppedImages_LV_V2(uint64_t handleVal, unsigned char* jpeg_string, int32 bufferLength, const char* strBboxes, LStrHandle detectionResult) { try { OCR_V2_HANDLE_SETUP(handleVal); std::string st = RunInferenceInCroppedImages(Handle, jpeg_string, bufferLength, strBboxes); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceInCroppedImages_LVWithCamID_V2(uint64_t handleVal, unsigned char* jpeg_string, int32 bufferLength, const char* strBboxes, const char* cameraId, LStrHandle detectionResult) { try { OCR_V2_HANDLE_SETUP(handleVal); std::string st = RunInferenceInCroppedImagesWithCamID(Handle, jpeg_string, bufferLength, strBboxes, cameraId); if (st.empty()) return 0; int size = static_cast(st.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error == noErr) { (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, st.c_str(), size); return 1; } else return 0; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferenceComplete_LV_V2( uint64_t handleVal, cv::Mat** cvImage, const char* cameraId, int getJpegString, int jpegImageSize, LStrHandle detectionResult, LStrHandle imageStr) { ANSCENTER::ANSOCRBase* directHandle = reinterpret_cast(handleVal); if (directHandle == nullptr) return -1; if (!cvImage || !(*cvImage) || (*cvImage)->empty()) return -2; OCRHandleGuard guard(AcquireOCRHandle(directHandle)); if (!guard) return -3; auto* engine = guard.get(); try { // Lookup NV12 frame BEFORE cloning (clone creates new cv::Mat*) GpuFrameData* gpuFrame = ANSGpuFrameRegistry::instance().lookup(*cvImage); cv::Mat localImage = (**cvImage).clone(); int originalWidth = localImage.cols; int originalHeight = localImage.rows; if (originalWidth == 0 || originalHeight == 0) return -2; tl_currentGpuFrame() = gpuFrame; std::vector outputs = engine->RunInference(localImage, cameraId); tl_currentGpuFrame() = nullptr; bool getJpeg = (getJpegString == 1); std::string stImage; int maxImageSize = originalWidth; bool resizeNeeded = (jpegImageSize > 0) && (jpegImageSize < maxImageSize); float ratio = 1.0f; int newWidth = originalWidth; int newHeight = originalHeight; if (resizeNeeded) { newWidth = jpegImageSize; newHeight = static_cast(std::round(newWidth * static_cast(originalHeight) / originalWidth)); ratio = static_cast(newWidth) / originalWidth; for (auto& obj : outputs) { obj.box.x = std::max(0, std::min(static_cast(obj.box.x * ratio), newWidth - 1)); obj.box.y = std::max(0, std::min(static_cast(obj.box.y * ratio), newHeight - 1)); obj.box.width = std::max(1, std::min(static_cast(obj.box.width * ratio), newWidth - obj.box.x)); obj.box.height = std::max(1, std::min(static_cast(obj.box.height * ratio), newHeight - obj.box.y)); } } else { for (auto& obj : outputs) { obj.box.x = std::max(0, std::min(static_cast(obj.box.x), originalWidth - 1)); obj.box.y = std::max(0, std::min(static_cast(obj.box.y), originalHeight - 1)); obj.box.width = std::max(1, std::min(static_cast(obj.box.width), originalWidth - obj.box.x)); obj.box.height = std::max(1, std::min(static_cast(obj.box.height), originalHeight - obj.box.y)); } } if (getJpeg) { cv::Mat processedImage = localImage; if (resizeNeeded) { cv::resize(localImage, processedImage, cv::Size(newWidth, newHeight), 0, 0, cv::INTER_AREA); } std::vector buf; if (cv::imencode(".jpg", processedImage, buf, { cv::IMWRITE_JPEG_QUALITY, 50 })) { stImage.assign(buf.begin(), buf.end()); } } std::string stDetectionResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(outputs); if (stDetectionResult.empty()) return 0; int size = static_cast(stDetectionResult.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error != noErr) return 0; (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, stDetectionResult.c_str(), size); if (getJpeg) { if (stImage.empty()) return 0; size = static_cast(stImage.length()); error = DSSetHandleSize(imageStr, sizeof(int32) + size * sizeof(uChar)); if (error != noErr) return 0; (*imageStr)->cnt = size; memcpy((*imageStr)->str, stImage.c_str(), size); } return 1; } catch (...) { return 0; } } extern "C" ANSOCR_API int RunInferencesComplete_LV_V2(uint64_t handleVal, cv::Mat** cvImage, const char* cameraId, int maxImageSize, const char* strBboxes, LStrHandle detectionResult) { ANSCENTER::ANSOCRBase* directHandle = reinterpret_cast(handleVal); if (directHandle == nullptr) return -1; if (!cvImage || !(*cvImage) || (*cvImage)->empty()) return -2; OCRHandleGuard guard(AcquireOCRHandle(directHandle)); if (!guard) return -3; auto* engine = guard.get(); try { // Lookup NV12 frame BEFORE cloning (clone creates new cv::Mat*) GpuFrameData* gpuFrame = ANSGpuFrameRegistry::instance().lookup(*cvImage); cv::Mat localImage = (**cvImage).clone(); std::vector objectDetectionResults; std::vector bBox = ANSCENTER::ANSOCRUtility::GetBoundingBoxes(strBboxes); const int originalWidth = localImage.cols; const int originalHeight = localImage.rows; const double scaleFactor = (maxImageSize > 0) ? static_cast(originalWidth) / maxImageSize : 1.0; tl_currentGpuFrame() = gpuFrame; if (bBox.empty()) { objectDetectionResults = engine->RunInference(localImage, cameraId); } else { for (const auto& rect : bBox) { cv::Rect scaledRect; scaledRect.x = static_cast(rect.x * scaleFactor); scaledRect.y = static_cast(rect.y * scaleFactor); scaledRect.width = static_cast(rect.width * scaleFactor); scaledRect.height = static_cast(rect.height * scaleFactor); scaledRect &= cv::Rect(0, 0, originalWidth, originalHeight); if (scaledRect.width <= 0 || scaledRect.height <= 0) continue; const cv::Mat croppedImage = localImage(scaledRect); std::vector croppedDetectionResults = engine->RunInference(croppedImage, cameraId); for (auto& obj : croppedDetectionResults) { obj.box.x = (obj.box.x + scaledRect.x) / scaleFactor; obj.box.y = (obj.box.y + scaledRect.y) / scaleFactor; obj.box.width /= scaleFactor; obj.box.height /= scaleFactor; objectDetectionResults.push_back(std::move(obj)); } } } tl_currentGpuFrame() = nullptr; std::string stDetectionResult = ANSCENTER::ANSOCRUtility::OCRDetectionToJsonString(objectDetectionResults); if (stDetectionResult.empty()) return 0; const int size = static_cast(stDetectionResult.length()); MgErr error = DSSetHandleSize(detectionResult, sizeof(int32) + size * sizeof(uChar)); if (error != noErr) return 0; (*detectionResult)->cnt = size; memcpy((*detectionResult)->str, stDetectionResult.c_str(), size); return 1; } catch (...) { return 0; } } // ============================================================================ // V2 Create / Release — handle returned/passed as uint64_t by value. // ============================================================================ extern "C" ANSOCR_API uint64_t CreateANSOCRHandleEx_V2(const char* licenseKey, const char* modelFilePath, const char* modelFileZipPassword, int language, int engineMode, int gpuId, double detectorDBThreshold, double detectorDBBoxThreshold, double detectorDBUnclipRatio, double classifierThreshold, int useDilation, int limitSideLen) { try { ANSCENTER::ANSOCRBase* handle = nullptr; int result = CreateANSOCRHandleEx(&handle, licenseKey, modelFilePath, modelFileZipPassword, language, engineMode, gpuId, detectorDBThreshold, detectorDBBoxThreshold, detectorDBUnclipRatio, classifierThreshold, useDilation, limitSideLen); if (result == 0 || handle == nullptr) return 0; return reinterpret_cast(handle); } catch (...) { return 0; } } extern "C" ANSOCR_API uint64_t CreateANSOCRHandle_V2(const char* licenseKey, const char* modelFilePath, const char* modelFileZipPassword, int language, int engineMode, int gpuId, double detectorDBThreshold, double detectorDBBoxThreshold, double detectorDBUnclipRatio, double classifierThreshold, int useDilation) { return CreateANSOCRHandleEx_V2(licenseKey, modelFilePath, modelFileZipPassword, language, engineMode, gpuId, detectorDBThreshold, detectorDBBoxThreshold, detectorDBUnclipRatio, classifierThreshold, useDilation, 960); } extern "C" ANSOCR_API int ReleaseANSOCRHandle_V2(uint64_t handleVal) { try { ANSCENTER::ANSOCRBase* directHandle = reinterpret_cast(handleVal); if (directHandle == nullptr) return 0; if (!UnregisterOCRHandle(directHandle)) { return 0; // Not in registry — already freed } directHandle->Destroy(); delete directHandle; return 0; } catch (...) { return 1; } }