#pragma once #include "RTOCRTypes.h" #include "RTOCRDetector.h" #include "RTOCRClassifier.h" #include "RTOCRRecognizer.h" #include #include #include #include #include #include #include #include "ANSLicense.h" namespace ANSCENTER { namespace rtocr { class PaddleOCRV5RTEngine { public: PaddleOCRV5RTEngine() = default; ~PaddleOCRV5RTEngine() = default; PaddleOCRV5RTEngine(const PaddleOCRV5RTEngine&) = delete; PaddleOCRV5RTEngine& operator=(const PaddleOCRV5RTEngine&) = delete; // Initialize all components // clsModelPath can be empty to skip classifier bool Initialize(const std::string& detModelPath, const std::string& clsModelPath, const std::string& recModelPath, const std::string& dictPath, int gpuId = 0, const std::string& engineCacheDir = ""); // Run full OCR pipeline: detect → crop → [classify →] recognize std::vector ocr(const cv::Mat& image); // Run recognizer only on a pre-cropped text image (no detection step) TextLine recognizeOnly(const cv::Mat& croppedImage); // Configuration setters void SetDetMaxSideLen(int v) { detMaxSideLen_ = v; } void SetDetDbThresh(float v) { detDbThresh_ = v; } void SetDetBoxThresh(float v) { detBoxThresh_ = v; } void SetDetUnclipRatio(float v) { detUnclipRatio_ = v; } void SetClsThresh(float v) { clsThresh_ = v; } void SetUseDilation(bool v) { useDilation_ = v; } void SetRecImageHeight(int v) { recImgH_ = v; } void SetRecImageMaxWidth(int v) { recImgMaxW_ = v; } void SetGpuId(int v) { gpuId_ = v; } void SetEngineCacheDir(const std::string& v) { engineCacheDir_ = v; } private: std::unique_ptr detector_; std::unique_ptr classifier_; // optional std::unique_ptr recognizer_; // Configuration int detMaxSideLen_ = kDetMaxSideLen; float detDbThresh_ = kDetDbThresh; float detBoxThresh_ = kDetBoxThresh; float detUnclipRatio_ = kDetUnclipRatio; float clsThresh_ = kClsThresh; bool useDilation_ = false; int recImgH_ = kRecImgH; int recImgMaxW_ = kRecImgMaxW; int gpuId_ = 0; std::string engineCacheDir_; std::recursive_mutex _mutex; std::atomic _modelLoading{ false }; struct ModelLoadingGuard { std::atomic& flag; explicit ModelLoadingGuard(std::atomic& f) : flag(f) { flag.store(true); } ~ModelLoadingGuard() { flag.store(false); } ModelLoadingGuard(const ModelLoadingGuard&) = delete; ModelLoadingGuard& operator=(const ModelLoadingGuard&) = delete; }; std::unique_lock TryLockWithTimeout( const char* caller, unsigned int timeoutMs = 5000) { const auto deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeoutMs); std::unique_lock lk(_mutex, std::defer_lock); while (!lk.try_lock()) { if (std::chrono::steady_clock::now() >= deadline) { std::cerr << "[" << caller << "] Mutex acquisition timed out after " << timeoutMs << " ms" << (_modelLoading.load() ? " (model loading in progress)" : "") << std::endl; return lk; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } return lk; } }; } // namespace rtocr } // namespace ANSCENTER