#include "ANSLPR_RT.h" namespace ANSCENTER { ANSALPR_RT::ANSALPR_RT() { _licenseValid = false; _globalViewId = 0; _focusedOnLPRId = 0; _platesTypesClassifierId = 0; } ANSALPR_RT::~ANSALPR_RT() { CloseReferences(); } bool ANSALPR_RT::Destroy() { CloseReferences(); return true; } bool ANSALPR_RT::CloseReferences() { try { bool session_closed = CloseDetector(_globalViewId); if (!session_closed) { this->_logger->LogFatal("ANSALPR_RT::CloseReferences", "Cannot close global view model reference", __FILE__, __LINE__); } else { _globalViewId = 0; } session_closed = CloseDetector(_focusedOnLPRId); if (!session_closed) { this->_logger->LogFatal("ANSALPR_RT::CloseReferences", "Cannot close focused on LRP model reference", __FILE__, __LINE__); } else { _focusedOnLPRId = 0; } session_closed = ClosePlatesTypesClassifier(_platesTypesClassifierId); if (!session_closed) { this->_logger->LogFatal("ANSALPR_RT::CloseReferences", "Cannot close plate type classifer model reference", __FILE__, __LINE__); } else { _platesTypesClassifierId = 0; } return true; } catch (std::exception& e) { this->_logger->LogFatal("ANSALPR_RT::CloseReferences", e.what(), __FILE__, __LINE__); return false; } } bool ANSALPR_RT::Initialize(const std::string& licenseKey, const std::string& modelZipFilePath, const std::string& modelZipPassword) { try { _licenseKey = licenseKey; _licenseValid = false; CheckLicense(); if (!_licenseValid) { this->_logger->LogError("ANSALPR::Initialize.", "License is not valid.", __FILE__, __LINE__); return false; } // Extract model folder // 0. Check if the modelZipFilePath exist? if (!FileExist(modelZipFilePath)) { this->_logger->LogFatal("ANSALPR::Initialize", "Model zip file is not exist", __FILE__, __LINE__); } // 1. Unzip model zip file to a special location with folder name as model file (and version) std::string outputFolder; std::vector passwordArray; if (!modelZipPassword.empty()) passwordArray.push_back(modelZipPassword); passwordArray.push_back("AnsDemoModels20@!"); passwordArray.push_back("Sh7O7nUe7vJ/417W0gWX+dSdfcP9hUqtf/fEqJGqxYL3PedvHubJag=="); passwordArray.push_back("3LHxGrjQ7kKDJBD9MX86H96mtKLJaZcTYXrYRdQgW8BKGt7enZHYMg=="); std::string modelName = GetFileNameWithoutExtension(modelZipFilePath); //this->_logger->LogInfo("ANSFDBase::Initialize. Model name", modelName); size_t vectorSize = passwordArray.size(); for (size_t i = 0; i < vectorSize; i++) { if (ExtractPasswordProtectedZip(modelZipFilePath, passwordArray[i], modelName, _modelFolder, false)) break; // Break the loop when the condition is met. } // 2. Check if the outputFolder exist if (!FolderExist(_modelFolder)) { this->_logger->LogError("ANSFDBase::Initialize. Output model folder is not exist", _modelFolder, __FILE__, __LINE__); return false; // That means the model file is not exist or the password is not correct } //3. Get License plate models _globalModelFileName = CreateFilePath(_modelFolder, "anslpr_alpr_focused_on_lp.onnx"); if (!FileExist(_globalModelFileName)) { this->_logger->LogError("ANSALPR::Initialize. Global view model does not exist", _globalModelFileName, __FILE__, __LINE__); return false; } _focusedOnLPRModelFileName = CreateFilePath(_modelFolder, "anslpr_alpr_global_view.onnx"); if (!FileExist(_focusedOnLPRModelFileName)) { this->_logger->LogError("ANSALPR::Initialize. Focused On LRP model does not exist", _focusedOnLPRModelFileName, __FILE__, __LINE__); return false; } _platesTypesClassifierFileName = CreateFilePath(_modelFolder, "plates_types_7.onnx"); if (!FileExist(_platesTypesClassifierFileName)) { this->_logger->LogError("ANSALPR::Initialize.LRP classifier model does not exist", _platesTypesClassifierFileName, __FILE__, __LINE__); return false; } _platesTypesLabelsFileName = CreateFilePath(_modelFolder, "plates_types_7.txt"); if (!FileExist(_platesTypesLabelsFileName)) { this->_logger->LogError("ANSALPR::Initialize.LRP classifier label model does not exist", _platesTypesLabelsFileName, __FILE__, __LINE__); return false; } // Load models size_t len = _globalModelFileName.size(); //step 1 : Initializes a new detector by loading its model file. In return, you get a unique id. The repo comes with two models namely anslpr_alpr_focused_on_lpand anslpr_alpr_global_view. //So you have to call this function twice to initialize both models. _globalViewId = InitYoloDetector(len, _globalModelFileName.c_str()); if (_globalViewId <= 0) { this->_logger->LogError("ANSALPR::Initialize.", "Global view model cannot be loaded", __FILE__, __LINE__); return false; } len = _focusedOnLPRModelFileName.size(); _focusedOnLPRId = InitYoloDetector(len, _focusedOnLPRModelFileName.c_str()); if (_focusedOnLPRId <= 0) { this->_logger->LogError("ANSALPR::Initialize.", "Focused on LPR model cannot be loaded", __FILE__, __LINE__); return false; } len = _platesTypesClassifierFileName.size(); _platesTypesClassifierId = InitPlatesClassifer(len, _platesTypesClassifierFileName.c_str(), _platesTypesLabelsFileName.size(), _platesTypesLabelsFileName.c_str()); if (_platesTypesClassifierId <= 0) { this->_logger->LogError("ANSALPR::Initialize.", "Plate type classifier model cannot be loaded", __FILE__, __LINE__); return false; } return true; } catch (std::exception& e) { this->_logger->LogFatal("ANSALPR::Initialize", e.what(), __FILE__, __LINE__); return false; } } bool ANSALPR_RT::Inference(const cv::Mat& input, std::string& lprResult) { if (!_licenseValid) { lprResult = ""; return false; } try { const size_t lpn_len = 15; char* lpn = new char[lpn_len + 1]; std::vector output; output.clear(); cv::Rect bbox; bool detected = TwoStageLPRPlatesTypeDetection( input.cols,//width of image input.rows,//height of image i.e. the specified dimensions of the image input.channels(),// pixel type : 1 (8 bpp greyscale image) 3 (RGB 24 bpp image) or 4 (RGBA 32 bpp image) input.data, input.step,// source image bytes buffer _globalViewId, _focusedOnLPRId,//id : unique interger to identify the detector to be used _platesTypesClassifierId,//unique id to identify the platestype classifier lpn_len, lpn, bbox); lprResult = lpn; if (detected) { ALPRObject result; result.classId = 0; result.className = lpn; result.confidence = 1.0; result.box = bbox; output.push_back(result); } lprResult = VectorDetectionToJsonString(output); return detected; } catch (std::exception& e) { this->_logger->LogFatal("ANSALPR::CheckStatus", e.what(), __FILE__, __LINE__); lprResult = ""; return false; }; } bool ANSALPR_RT::Inference(const cv::Mat& input, const std::vector& Bbox, std::string& lprResult) { if (!_licenseValid) { lprResult = ""; return false; } try { const size_t lpn_len = 15; char* lpn = new char[lpn_len + 1]; std::vector output; output.clear(); bool detected = false; if (Bbox.size() > 0) { cv::Mat frame = input.clone(); for (std::vector::iterator it = Bbox.begin(); it != Bbox.end(); it++) { int x1, y1, x2, y2; x1 = (*it).x; y1 = (*it).y; x2 = (*it).x + (*it).width; y2 = (*it).y + (*it).height; // Get cropped objects cv::Rect objectPos(cv::Point(x1, y1), cv::Point(x2, y2)); cv::Mat croppedObject = frame(objectPos); cv::Rect bbox; detected = TwoStageLPRPlatesTypeDetection( croppedObject.cols,//width of image croppedObject.rows,//height of image i.e. the specified dimensions of the image croppedObject.channels(),// pixel type : 1 (8 bpp greyscale image) 3 (RGB 24 bpp image) or 4 (RGBA 32 bpp image) croppedObject.data, croppedObject.step,// source image bytes buffer _globalViewId, _focusedOnLPRId,//id : unique interger to identify the detector to be used _platesTypesClassifierId,//unique id to identify the platestype classifier lpn_len, lpn, bbox); lprResult = lpn; if (detected) { ALPRObject result; result.classId = 0; result.className = lpn; result.confidence = 1.0; result.box.x = bbox.x + x1; result.box.y = bbox.y + y1; result.box.width = bbox.width; result.box.height = bbox.height; output.push_back(result); } } lprResult = VectorDetectionToJsonString(output); } else { cv::Rect bbox; detected = TwoStageLPRPlatesTypeDetection( input.cols,//width of image input.rows,//height of image i.e. the specified dimensions of the image input.channels(),// pixel type : 1 (8 bpp greyscale image) 3 (RGB 24 bpp image) or 4 (RGBA 32 bpp image) input.data, input.step,// source image bytes buffer _globalViewId, _focusedOnLPRId,//id : unique interger to identify the detector to be used _platesTypesClassifierId,//unique id to identify the platestype classifier lpn_len, lpn, bbox); lprResult = lpn; if (detected) { ALPRObject result; result.classId = 0; result.className = lpn; result.confidence = 1.0; result.box = bbox; output.push_back(result); } lprResult = VectorDetectionToJsonString(output); } return detected; } catch (std::exception& e) { this->_logger->LogFatal("ANSALPR::CheckStatus", e.what(), __FILE__, __LINE__); lprResult = ""; return false; }; } // Private: std::string ANSALPR_RT::VectorDetectionToJsonString(const std::vector& dets) { boost::property_tree::ptree root; boost::property_tree::ptree detectedObjects; for (int i = 0; i < dets.size(); i++) { boost::property_tree::ptree detectedNode; detectedNode.put("class_id", dets[i].classId); detectedNode.put("class_name", dets[i].className); detectedNode.put("prob", dets[i].confidence); detectedNode.put("x", dets[i].box.x); detectedNode.put("y", dets[i].box.y); detectedNode.put("width", dets[i].box.width); detectedNode.put("height", dets[i].box.height); detectedNode.put("mask", "");//Todo: convert masks to mask with comma seperated dets[i].mask); detectedNode.put("extra_info", ""); // we might add masks into this using comma seperated string detectedObjects.push_back(std::make_pair("", detectedNode)); } root.add_child("results", detectedObjects); std::ostringstream stream; boost::property_tree::write_json(stream, root, false); std::string trackingResult = stream.str(); return trackingResult; } void ANSALPR_RT::CheckStatus(OrtStatus* status) { try { if (status != nullptr) { const char* msg = g_ort->GetErrorMessage(status); this->_logger->LogError("ANSALPR::CheckStatus", msg, __FILE__, __LINE__); g_ort->ReleaseStatus(status); exit(1); } } catch (std::exception& e) { this->_logger->LogFatal("ANSALPR::CheckStatus", e.what(), __FILE__, __LINE__); } } std::list::const_iterator ANSALPR_RT::GetDetector(unsigned int id, const std::list& detectors, const std::list& detectors_ids) { assert(detectors_ids.size() == detectors.size()); std::list::const_iterator it(detectors.begin()); std::list::const_iterator it_id(detectors_ids.begin()); while (it != detectors.end() && it_id != detectors_ids.end()) { if (*it_id == id) { return it; } else { it_id++; it++; } } return detectors.end(); } std::list::const_iterator ANSALPR_RT::GetPlatesTypesClassifier(unsigned int id, const std::list& plates_types_classifiers, const std::list& plates_types_classifiers_ids) { assert(plates_types_classifiers_ids.size() == plates_types_classifiers.size()); std::list::const_iterator it(plates_types_classifiers.begin()); std::list::const_iterator it_id(plates_types_classifiers_ids.begin()); while (it != plates_types_classifiers.end() && it_id != plates_types_classifiers_ids.end()) { if (*it_id == id) { return it; } else { it_id++; it++; } } return plates_types_classifiers.end(); } unsigned int ANSALPR_RT::GetNewId(const std::list& detectors_ids) { if (detectors_ids.size()) { auto result = std::minmax_element(detectors_ids.begin(), detectors_ids.end()); return *result.second + 1; } else return 1; } bool ANSALPR_RT::CloseDetector(unsigned int id, std::list& _envs, std::list& _lsessionOptions, std::list& _detectors, std::list& _detectors_ids) { assert(_detectors_ids.size() == _detectors.size() && _detectors_ids.size() == _envs.size() && _detectors_ids.size() == _lsessionOptions.size()); std::list::iterator it(_detectors.begin()); std::list::iterator it_id(_detectors_ids.begin()); std::list::iterator it_sessionOptions(_lsessionOptions.begin()); std::list::iterator it_envs(_envs.begin()); while (it != _detectors.end() && it_id != _detectors_ids.end() && it_envs != _envs.end() && it_sessionOptions != _lsessionOptions.end() ) { if (*it_id == id) { if (*it != nullptr) delete* it; if (*it_sessionOptions != nullptr) delete* it_sessionOptions; if (*it_envs != nullptr) delete* it_envs; it_envs = _envs.erase(it_envs); it_sessionOptions = _lsessionOptions.erase(it_sessionOptions); it = _detectors.erase(it); it_id = _detectors_ids.erase(it_id); return true; } else { it_sessionOptions++; it_envs++; it_id++; it++; } } return false; } bool ANSALPR_RT::CloseDetector(unsigned int id, std::list& _envs, std::list& _lsessionOptions, std::list& _detectors, std::list& _detectors_ids) { assert(_detectors_ids.size() == _detectors.size() && _detectors_ids.size() == _envs.size() && _detectors_ids.size() == _lsessionOptions.size()); std::list::iterator it(_detectors.begin()); std::list::iterator it_id(_detectors_ids.begin()); std::list::iterator it_sessionOptions(_lsessionOptions.begin()); std::list::iterator it_envs(_envs.begin()); while (it != _detectors.end() && it_id != _detectors_ids.end() && it_envs != _envs.end() && it_sessionOptions != _lsessionOptions.end() ) { if (*it_id == id) { if (*it != nullptr) delete* it; if (*it_sessionOptions != nullptr) delete* it_sessionOptions; if (*it_envs != nullptr) delete* it_envs; it_envs = _envs.erase(it_envs); it_sessionOptions = _lsessionOptions.erase(it_sessionOptions); it = _detectors.erase(it); it_id = _detectors_ids.erase(it_id); return true; } else { it_sessionOptions++; it_envs++; it_id++; it++; } } return false; } // Private interface unsigned int ANSALPR_RT::InitYoloDetector(unsigned int len, const char* model_file) { assert(detectors_ids.size() == detectors.size()); const std::string model_filename(model_file, len); if (!model_filename.size() || !std::filesystem::exists(model_filename) || !std::filesystem::is_regular_file(model_filename) ) { this->_logger->LogError("ANSALPR::InitYoloDetector. Model file is not regular file.", model_filename, __FILE__, __LINE__); return 0; } //step 2 declare an onnx runtime environment std::string instanceName{ "image-classification-inference" }; // https://github.com/microsoft/onnxruntime/blob/rel-1.6.0/include/onnxruntime/core/session/onnxruntime_c_api.h#L123 Ort::Env* penv = new Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_WARNING, instanceName.c_str()); if (penv != nullptr) { //step 3 declare options for the runtime environment Ort::SessionOptions* psessionOptions = new Ort::SessionOptions(); if (psessionOptions != nullptr) { psessionOptions->SetIntraOpNumThreads(1); // Sets graph optimization level // Available levels are // ORT_DISABLE_ALL -> To disable all optimizations // ORT_ENABLE_BASIC -> To enable basic optimizations (Such as redundant node // removals) ORT_ENABLE_EXTENDED -> To enable extended optimizations // (Includes level 1 + more complex optimizations like node fusions) // ORT_ENABLE_ALL -> To Enable All possible optimizations psessionOptions->SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); #ifdef ANSLPR_USE_CUDA // Optionally add more execution providers via session_options // E.g. for CUDA include cuda_provider_factory.h and uncomment the following line: // nullptr for Status* indicates success OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(*psessionOptions, 0); //or status =nullptr; //if you don t have CUDA if (status == nullptr) { #endif //ANSLPR_USE_CUDA Yolov5_alpr_onxx_detector* onnx_net = nullptr; #ifdef _WIN32 //step 4 declare an onnx session (ie model), by giving references to the runtime environment, session options and file path to the model std::wstring widestr = std::wstring(model_filename.begin(), model_filename.end()); onnx_net = new Yolov5_alpr_onxx_detector(*penv, widestr.c_str(), *psessionOptions); #else onnx_net = new Yolov5_alpr_onxx_detector(*penv, model_filename.c_str(), *psessionOptions); #endif if (onnx_net != nullptr && penv != nullptr && psessionOptions != nullptr) { std::unique_lock lck(mtxMutex, std::defer_lock); lck.lock(); detectors_envs.push_back(penv); l_detectors_sessionOptions.push_back(psessionOptions); detectors.push_back(onnx_net); unsigned int id = GetNewId(detectors_ids); detectors_ids.push_back(id); lck.unlock(); return id; } else { this->_logger->LogError("ANSALPR::InitYoloDetector. Error while creating onnxruntime session with file", model_filename.c_str(), __FILE__, __LINE__); return 0; } #ifdef ANSLPR_USE_CUDA } else { CheckStatus(status); this->_logger->LogError("ANSALPR::InitYoloDetector.", "Cuda error", __FILE__, __LINE__); return 0; } #endif //ANSLPR_USE_CUDA } else { this->_logger->LogError("ANSALPR::InitYoloDetector.", "Error while creating SessionOptions", __FILE__, __LINE__); return 0; } } else { this->_logger->LogError("ANSALPR::InitYoloDetector.", "Error while creating while creating session environment (Ort::Env)", __FILE__, __LINE__); return 0; } } unsigned int ANSALPR_RT::InitPlatesClassifer(unsigned int len_models_filename, const char* model_file, unsigned int len_labels_filename, const char* labels_file) { assert(plates_types_classifier_ids.size() == plates_types_classifiers.size()); const std::string model_filename(model_file, len_models_filename); const std::string labels_filename(labels_file, len_labels_filename); if (!model_filename.size() || !std::filesystem::exists(model_filename) || !std::filesystem::is_regular_file(model_filename) || !labels_filename.size() || !std::filesystem::exists(labels_filename) || !std::filesystem::is_regular_file(labels_filename) ) { this->_logger->LogDebug("ANSALPR::InitPlatesClassifer. Model file is not regular file.", model_filename, __FILE__, __LINE__); return 0; } //step 2 declare an onnx runtime environment std::string instanceName{ "image-classification-inference" }; // https://github.com/microsoft/onnxruntime/blob/rel-1.6.0/include/onnxruntime/core/session/onnxruntime_c_api.h#L123 Ort::Env* penv = new Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_WARNING, instanceName.c_str()); if (penv != nullptr) { //step 3 declare options for the runtime environment Ort::SessionOptions* psessionOptions = new Ort::SessionOptions(); if (psessionOptions != nullptr) { psessionOptions->SetIntraOpNumThreads(1); // Sets graph optimization level // Available levels are // ORT_DISABLE_ALL -> To disable all optimizations // ORT_ENABLE_BASIC -> To enable basic optimizations (Such as redundant node // removals) ORT_ENABLE_EXTENDED -> To enable extended optimizations // (Includes level 1 + more complex optimizations like node fusions) // ORT_ENABLE_ALL -> To Enable All possible optimizations psessionOptions->SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); #ifdef ANSLPR_USE_CUDA // Optionally add more execution providers via session_options // E.g. for CUDA include cuda_provider_factory.h and uncomment the following line: // nullptr for Status* indicates success OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(*psessionOptions, 0); //or status =nullptr; //if you don t have CUDA if (status == nullptr) { #endif //ANSLPR_USE_CUDA Plates_types_classifier* onnx_net = nullptr; #ifdef _WIN32 //step 4 declare an onnx session (ie model), by giving references to the runtime environment, session options and file path to the model std::wstring widestr = std::wstring(model_filename.begin(), model_filename.end()); onnx_net = new Plates_types_classifier(*penv, widestr.c_str(), *psessionOptions, labels_filename); #else onnx_net = new Plates_types_classifier(*penv, model_filename.c_str(), *psessionOptions, labels_filename); #endif if (onnx_net != nullptr && penv != nullptr && psessionOptions != nullptr) { std::unique_lock lck(mtxMutex, std::defer_lock); lck.lock(); plates_types_envs.push_back(penv); l_plates_types_classifier_sessionOptions.push_back(psessionOptions); plates_types_classifiers.push_back(onnx_net); unsigned int id = GetNewId(plates_types_classifier_ids); plates_types_classifier_ids.push_back(id); lck.unlock(); return id; } else { this->_logger->LogError("ANSALPR::InitPlatesClassifer. Error while creating onnxruntime session with file.", model_filename, __FILE__, __LINE__); return 0; } #ifdef ANSLPR_USE_CUDA } else { CheckStatus(status); this->_logger->LogError("ANSALPR::InitPlatesClassifer.", "Cuda error", __FILE__, __LINE__); return 0; } #endif //ANSLPR_USE_CUDA } else { this->_logger->LogError("ANSALPR::InitPlatesClassifer.", "Error while creating SessionOptions", __FILE__, __LINE__); return 0; } } else { this->_logger->LogError("ANSALPR::InitPlatesClassifer.", "Error while creating session environment (Ort::Env)", __FILE__, __LINE__); return 0; } } bool ANSALPR_RT::TwoStageALPR(const int width,//width of image const int height,//height of image i.e. the specified dimensions of the image const int pixOpt,// pixel type : 1 (8 bpp greyscale image) 3 (RGB 24 bpp image) or 4 (RGBA 32 bpp image) void* pbData, unsigned int step,// source image bytes buffer unsigned int id_global_view, unsigned int id_focused_on_lp, unsigned int lpn_len, char* lpn, cv::Rect& bbox) { if ((pixOpt != 1) && (pixOpt != 3) && (pixOpt != 4) || height <= 0 || width <= 0 || pbData == nullptr) { this->_logger->LogError("ANSALPR::TwoStageLPR.", "Condition on image (pixOpt != 1) && (pixOpt != 3) && (pixOpt != 4) || height <= 0 || width <= 0 || pbData == nullptr not met", __FILE__, __LINE__); return false; } else { cv::Mat destMat; if (pixOpt == 1) { destMat = cv::Mat(height, width, CV_8UC1, pbData, step); } if (pixOpt == 3) { destMat = cv::Mat(height, width, CV_8UC3, pbData, step); } if (pixOpt == 4) { destMat = cv::Mat(height, width, CV_8UC4, pbData, step); } std::list::const_iterator it_global_view = GetDetector(id_global_view, detectors, detectors_ids); if (it_global_view != detectors.end()) { std::list::const_iterator it_focused_on_lp = GetDetector(id_focused_on_lp, detectors, detectors_ids); std::string lpn_str; std::list ROIs; std::unique_lock lck(mtxMutex, std::defer_lock); if (it_focused_on_lp != detectors.end()) { lck.lock(); //for normal plates ROIs = (*it_global_view)->TwoStage_LPR(*(*it_focused_on_lp), destMat, lpn_str); //for small plates lck.unlock(); } else { this->_logger->LogError("ANSALPR::TwoStageLPR.", "id_focused_on_lp does not point to a valid detector", __FILE__, __LINE__); lck.lock(); //for normal plates ROIs = (*it_global_view)->TwoStage_LPR(*(*it_global_view), destMat, lpn_str); //for small plates lck.unlock(); } std::string::const_iterator it_lpn(lpn_str.begin()); int i = 0; while (it_lpn != lpn_str.end() && i < lpn_len - 1) { lpn[i] = *it_lpn; i++; it_lpn++; } while (i < lpn_len) { lpn[i] = '\0'; i++; } bbox = GetGlobalROI(ROIs); return (lpn_str.length() > 0); } else { this->_logger->LogError("ANSALPR::TwoStageLPR.", "id_global_view does not point to a valid detector", __FILE__, __LINE__); return false; } } } cv::Rect ANSALPR_RT::GetGlobalROI(std::list ROIs) { cv::Rect result; if (ROIs.size() > 0) result = ROIs.front(); return result; /*std::list::iterator it; cv::Rect v = ROIs.front(); int x_min, y_min, w_min, h_min; int x_max, y_max, w_max, h_max; x_min = v.x; x_max = v.x; y_min = v.y; y_max = v.y; w_min = v.width; w_max = v.width; h_min = v.height; h_max = v.height; for (it = ROIs.begin(); it != ROIs.end(); ++it) { if (x_min > it->x) { x_min = it->x; } if (x_max < it->x) { x_max = it->x; } if (y_min > it->y) { y_min = it->y; } if (y_max < it->y) { y_max = it->y; } if (w_min > it->width) { w_min = it->width; } if (w_max < it->width) { w_max = it->width; } if (h_min > it->height) { w_min = it->height; } if (h_max < it->height) { w_max = it->height; } } v.x = x_min - 2; v.y = y_min - 2; v.width = x_max + w_max - x_min + 2; v.height = h_max + 2; return v;*/ } bool ANSALPR_RT::TwoStageLPRPlatesTypeDetection(const int width,//width of image const int height,//height of image i.e. the specified dimensions of the image const int pixOpt,// pixel type : 1 (8 bpp greyscale image) 3 (RGB 24 bpp image) or 4 (RGBA 32 bpp image) void* pbData, unsigned int step,// source image bytes buffer unsigned int id_global_view, unsigned int id_focused_on_lp, unsigned int id_plates_types_classifier, unsigned int lpn_len, char* lpn, cv::Rect& bbox) { if ((pixOpt != 1) && (pixOpt != 3) && (pixOpt != 4) || height <= 0 || width <= 0 || pbData == nullptr) { this->_logger->LogError("ANSALPR::TwoStageLPRPlatesTypeDetection.", "Condition on image (pixOpt != 1) && (pixOpt != 3) && (pixOpt != 4) || height <= 0 || width <= 0 || pbData == nullptr not met", __FILE__, __LINE__); return false; } else { cv::Mat destMat; if (pixOpt == 1) { destMat = cv::Mat(height, width, CV_8UC1, pbData, step); } if (pixOpt == 3) { destMat = cv::Mat(height, width, CV_8UC3, pbData, step); } if (pixOpt == 4) { destMat = cv::Mat(height, width, CV_8UC4, pbData, step); } std::list::const_iterator it_plates_types_classifier = GetPlatesTypesClassifier(id_plates_types_classifier, plates_types_classifiers, plates_types_classifier_ids); if (it_plates_types_classifier != plates_types_classifiers.end()) { std::list::const_iterator it_global_view = GetDetector(id_global_view, detectors, detectors_ids); if (it_global_view != detectors.end()) { std::list::const_iterator it_focused_on_lp = GetDetector(id_focused_on_lp, detectors, detectors_ids); std::string lpn_str; std::list ROIs; std::unique_lock lck(mtxMutex, std::defer_lock); if (it_focused_on_lp != detectors.end()) { lck.lock(); //for normal plates ROIs = (*it_global_view)->TwoStageLPR(*(*it_focused_on_lp), *(*it_plates_types_classifier), destMat, lpn_str); //for small plates lck.unlock(); } else { this->_logger->LogError("ANSALPR::TwoStageLPRPlatesTypeDetection.", "id_focused_on_lp does not point to a valid detector", __FILE__, __LINE__); lck.lock(); //for normal plates ROIs = (*it_global_view)->TwoStageLPR(*(*it_global_view), *(*it_plates_types_classifier), destMat, lpn_str); //for small plates lck.unlock(); } std::string::const_iterator it_lpn(lpn_str.begin()); int i = 0; while (it_lpn != lpn_str.end() && i < lpn_len - 1) { lpn[i] = *it_lpn; i++; it_lpn++; } while (i < lpn_len) { lpn[i] = '\0'; i++; } bbox = GetGlobalROI(ROIs); return (lpn_str.length() > 0); } else { this->_logger->LogError("ANSALPR::TwoStageLPRPlatesTypeDetection.", "id_global_view does not point to a valid detector", __FILE__, __LINE__); return false; } } else { this->_logger->LogError("ANSALPR::TwoStageLPRPlatesTypeDetection.", "id_plates_types_classifier does not point to a valid detector", __FILE__, __LINE__); return TwoStageALPR(width,//width of image height,//height of image i.e. the specified dimensions of the image pixOpt,// pixel type : 1 (8 bpp greyscale image) 3 (RGB 24 bpp image) or 4 (RGBA 32 bpp image) pbData, step,// source image bytes buffer id_global_view, id_focused_on_lp, lpn_len, lpn, bbox); } } } bool ANSALPR_RT::CloseDetector(unsigned int id) { assert(detectors_ids.size() == detectors.size()); std::unique_lock lck(mtxMutex, std::defer_lock); lck.lock(); bool session_closed = CloseDetector(id, detectors_envs, l_detectors_sessionOptions, detectors, detectors_ids); lck.unlock(); return session_closed; } bool ANSALPR_RT::ClosePlatesTypesClassifier(unsigned int id) { assert(plates_types_classifier_ids.size() == plates_types_classifiers.size()); std::unique_lock lck(mtxMutex, std::defer_lock); lck.lock(); bool session_closed = CloseDetector(id, plates_types_envs, l_plates_types_classifier_sessionOptions, plates_types_classifiers, plates_types_classifier_ids); lck.unlock(); return session_closed; } }