Fix NV12 crash issue when recreate camera object

This commit is contained in:
2026-04-02 22:07:27 +11:00
parent 4bedf3a3a2
commit 958cab6ae3
25 changed files with 1459 additions and 393 deletions

View File

@@ -378,7 +378,7 @@ namespace ANSCENTER {
}
}
std::vector<Object> ANSALPR_CPU::RunInference(const cv::Mat& input, const std::string &cameraId) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — sub-components have their own fine-grained locks.
std::vector<Object> output;
output.clear();
// Initial validation
@@ -419,17 +419,18 @@ namespace ANSCENTER {
#ifdef FNS_DEBUG // Corrected preprocessor directive
cv::Mat draw = input.clone();
#endif
_detectedArea = cv::Rect(0, 0, frame.cols, frame.rows);
if ((_detectedArea.width > 50) && (_detectedArea.height > 50)) {
// Use local variable instead of shared _detectedArea for thread safety
cv::Rect detectedArea(0, 0, frame.cols, frame.rows);
if ((detectedArea.width > 50) && (detectedArea.height > 50)) {
#ifdef FNS_DEBUG // Corrected preprocessor directive
cv::rectangle(draw, _detectedArea, cv::Scalar(0, 0, 255), 2); // RED for detectedArea
#endif
cv::rectangle(draw, detectedArea, cv::Scalar(0, 0, 255), 2); // RED for detectedArea
#endif
// Ensure _lprDetector is valid
if (!_lprDetector) {
this->_logger.LogFatal("ANSALPR_CPU::Inference", "_lprDetector is null", __FILE__, __LINE__);
return output;
}
cv::Mat activeFrame = frame(_detectedArea).clone();
cv::Mat activeFrame = frame(detectedArea).clone();
//std::vector<Object> lprOutputRaw = _lpDetector->RunInference(activeFrame, cameraId);
//std::vector<Object> lprOutput = AdjustLicensePlateBoundingBoxes(lprOutputRaw, _detectedArea, frame.size(), 3.0);
@@ -471,8 +472,12 @@ namespace ANSCENTER {
lprObject.cameraId = cameraId;
lprObject.polygon = RectToNormalizedPolygon(lprObject.box, input.cols, input.rows);
// OCR inference
std::vector<PaddleOCR::OCRPredictResult> res_ocr = ppocr->ocr(alignedLPR);
// OCR inference (ppocr is not thread-safe, use fine-grained lock)
std::vector<PaddleOCR::OCRPredictResult> res_ocr;
{
std::lock_guard<std::mutex> ocrLock(_ocrMutex);
res_ocr = ppocr->ocr(alignedLPR);
}
std::string ocrText;
if (!res_ocr.empty() && res_ocr.size() < 3) {
@@ -515,13 +520,13 @@ namespace ANSCENTER {
return output;
}
bool ANSALPR_CPU::Inference(const cv::Mat& input, std::string& lprResult) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — delegates to Inference(input, lprResult, cameraId)
if (input.empty()) return false;
if ((input.cols < 5) || (input.rows < 5)) return false;
return Inference(input, lprResult, "CustomCam");
}
bool ANSALPR_CPU::Inference(const cv::Mat& input, std::string& lprResult, const std::string & cameraId) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — sub-components have fine-grained locks.
std::vector<Object> output;
output.clear();
if (!_licenseValid) {
@@ -587,10 +592,15 @@ namespace ANSCENTER {
cv::Mat lprImage = frame(lprPos).clone();
lprObject.cameraId = cameraId;
lprObject.polygon = RectToNormalizedPolygon(lprObject.box, input.cols, input.rows);
std::vector<PaddleOCR::OCRPredictResult> res_ocr = ppocr->ocr(lprImage);
// ppocr is not thread-safe, use fine-grained lock
std::vector<PaddleOCR::OCRPredictResult> res_ocr;
{
std::lock_guard<std::mutex> ocrLock(_ocrMutex);
res_ocr = ppocr->ocr(lprImage);
}
int detectionSize = res_ocr.size();
if ((detectionSize > 0) && (detectionSize < 3)) {
for (int n = 0; n < res_ocr.size(); n++) { // number of detections
for (int n = 0; n < res_ocr.size(); n++) { // number of detections
ocrText.append(res_ocr[n].text);
}
std::string rawText = AnalyseLicensePlateText(ocrText);
@@ -613,7 +623,7 @@ namespace ANSCENTER {
}
}
bool ANSALPR_CPU::Inference(const cv::Mat& input, const std::vector<cv::Rect> & Bbox, std::string& lprResult) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — delegates to Inference(input, Bbox, lprResult, cameraId)
if (input.empty()) return false;
if ((input.cols < 5) || (input.rows < 5)) return false;
return Inference(input, Bbox, lprResult, "CustomCam");
@@ -622,7 +632,7 @@ namespace ANSCENTER {
bool ANSALPR_CPU::Inference(const cv::Mat& input, const std::vector<cv::Rect>& Bbox,
std::string& lprResult, const std::string& cameraId)
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — sub-components have fine-grained locks.
// Early validation
if (!_licenseValid) {
@@ -668,16 +678,12 @@ namespace ANSCENTER {
}
try {
// Convert grayscale to BGR if necessary
const cv::Mat* framePtr;
// Convert grayscale to BGR if necessary (use local buffer for thread safety)
cv::Mat localFrame;
if (input.channels() == 1) {
cv::cvtColor(input, this->_frameBuffer, cv::COLOR_GRAY2BGR);
framePtr = &this->_frameBuffer;
cv::cvtColor(input, localFrame, cv::COLOR_GRAY2BGR);
}
else {
framePtr = &input;
}
const cv::Mat& frame = *framePtr;
const cv::Mat& frame = (input.channels() == 1) ? localFrame : input;
const int frameWidth = frame.cols;
const int frameHeight = frame.rows;
@@ -794,7 +800,12 @@ namespace ANSCENTER {
cv::Mat lprImage = frame(plateRect);
cv::Mat alignedLPR = enhanceForOCR(lprImage);
std::vector<PaddleOCR::OCRPredictResult> res_ocr = ppocr->ocr(alignedLPR);
// ppocr is not thread-safe, use fine-grained lock
std::vector<PaddleOCR::OCRPredictResult> res_ocr;
{
std::lock_guard<std::mutex> ocrLock(_ocrMutex);
res_ocr = ppocr->ocr(alignedLPR);
}
const size_t detectionSize = res_ocr.size();
if (detectionSize == 0 || detectionSize >= 3) {

View File

@@ -5,6 +5,7 @@
#include <list>
#include <map>
#include <string>
#include <mutex>
#include <utility>
#include <vector>
#include <include/paddleocr.h>
@@ -157,6 +158,7 @@ namespace ANSCENTER
"43B1", "68L1", "70G1", "36M1", "81N1", "90K1", "17B1", "64E1", "99D1", "60B2", "74L1", "60C1", "68M1", "63B7", "34B1", "69M1", "24B1", "15M1", "83Y1", "48C1", "95H1", "79X1", "17B6", "36E1", "38K1", "25N1", "25U1", "61B1", "36C1", "36B3", "38F1", "99G1", "69N1", "97D1", "92T1", "92B1", "88B1", "97G1", "14U1", "63A1", "26N1", "19D1", "93C1", "73B1", "84B1", "81K1", "18L1", "64D1", "35M1", "61N1", "83P1", "15S1", "82B1", "92U1", "43D1", "22L1", "63B5", "64G1", "27N1", "14X1", "62C1", "81D1", "38G1", "19F1", "34K1", "49P1", "89H1", "14T1", "19M1", "78D1", "76A1", "66K1", "66C1", "71C1", "37K1", "19G1", "15F1", "85C1", "49B1", "21B1", "89F1", "23M1", "66L1", "90B5", "93M1", "14P1", "77N1", "36B8", "86B1", "12U1", "63B3", "21L1", "36G5", "65G1", "82E1", "61H1", "65H1", "84A1", "23F1", "95C1", "99K1", "49G1", "92D1", "36K3", "92N1", "82X1", "83M1", "11N1", "14K1", "19H1", "93H1", "60A1", "79A1", "20D1", "90D1", "81C1", "66P1", "36K1", "92V1", "18B1", "37P1", "22Y1", "23H1", "26D1", "66G1", "78F1", "49C1", "26H1", "38P1", "47T1", "74H1", "63P1", "47D1", "15D1", "23D1", "68E1", "20B1", "49F1", "43K1", "65K1", "27Z1", "92S1", "79H1", "21E1", "35Y1", "14S1", "75E1", "24Y1", "12T1", "27P1", "77B1", "88H1", "60B3", "23P1", "61F1", "99H1", "23K1", "59A3", "26C1", "81B1", "74E1", "66B1", "22S1", "92P1", "93B1", "69B1", "81P1", "12H1", "62K1", "35A1", "77C1", "27V1", "68N1", "12D1", "64K1", "41A1", "12Z1", "76C1", "38B1", "78G1", "74K1", "69H1", "94A1", "61K1", "86B7", "82G1", "14N1", "82M1", "76E1", "18E1", "61C1", "15N1", "90A1", "77F1", "34D1", "47B1", "62S1", "43E1", "81M1", "92X1", "75B1", "34F1", "70H1", "62B1", "26B1", "60B4", "61A1", "12B1", "90T1", "92E1", "34C1", "47G1", "97B1", "25S1", "70E1", "93Y1", "47S1", "37F1", "28N1", "11K1", "38E1", "78M1", "74C1", "12S1", "75S1", "37A1", "28D1", "65L1", "22B1", "99B1", "74G1", "79K1", "76K1", "76H1", "23B1", "15R1", "36B1", "74D1", "62L1", "37E1", "78E1", "89K1", "26M1", "25F1", "48H1", "79D1", "43H1", "76F1", "36L1", "43L1", "21K1", "88L1", "27S1", "92K1", "77D1", "19N1", "66H1", "36H5", "62N1", "18G1", "75D1", "37L1", "68K1", "28C1", "26E1", "35N1", "85H1", "62D1", "27U1", "19E1", "99E1", "14Y1", "49L1", "66M1", "73F1", "70K1", "36F5", "97H1", "93E1", "68P1", "43F1", "48G1", "75K1", "62U1", "86B9", "65F1", "27L1", "70L1", "63B8", "78L1", "11Z1", "68C1", "18D1", "15L1", "99C1", "49E1", "84E1", "69E1", "38A1", "48D1", "68S1", "81E1", "84K1", "63B6", "24T1", "95A1", "86B4", "34M1", "84L1", "24V1", "14M1", "36H1", "15B1", "69F1", "47E1", "38H1", "88D1", "28E1", "60C2", "63B9", "75Y1", "21D1", "35H1", "68F1", "86B5", "15H1", "36B5", "83X1", "17B7", "12V1", "86B8", "95E1", "63B2", "74F1", "86C1", "48K1", "89M1", "85D1", "71C4", "34E1", "97C1", "88E1", "81F1", "60B5", "84M1", "92H1", "28L1", "34H1", "38X1", "82L1", "61E1", "82F1", "62P1", "93F1", "65B1", "93L1", "95B1", "15P1", "77G1", "28M1", "35B1", "68G1", "36C2", "68D1", "69K1", "14L1", "36M3", "24X1", "24Z1", "86A1", "88C1", "15E1", "77E1", "83E1", "47L1", "25T1", "89C1", "71C3", "49D1", "36L6", "48F1", "36B6", "34P1", "84D1", "15C1", "38M1", "85F1", "77K1", "86B3", "74B1", "78H1", "89G1", "64A2", "15K1", "85B1", "49K1", "21H1", "73C1", "47U1", "65E1", "18C1", "69D1", "63B1", "95G1", "19L1", "20G1", "76D1", "29A1", "68T1", "75L1", "12L1", "89L1", "37C1", "27B1", "19C1", "11H1", "81X1", "70B1", "11V1", "43G1", "22A1", "83C1", "75C1", "79C1", "22F1", "92F1", "81G1", "81T1", "28H1", "66N1", "71B1", "18H1", "76P1", "26F1", "81U1", "34N1", "64F1", "76N1", "24S1", "26P1", "63B4", "35T1", "36N1", "47F1", "81L1", "61G1", "77M1", "34G1", "26G1", "97F1", "62H1", "28F1", "62T1", "93G1", "73D1", "65A1", "47P1", "74P1", "82N1", "20E1", "36D1", "60B1", "49M1", "37H1", "37M1", "38D1", "84F1", "88F1", "36B2", "65C1", "92M1", "86B6", "75H1", "38L1", "20C1", "97E1", "85E1", "38N1", "26K1", "89B1", "99F1", "28B1", "34L1", "86B2", "66F1", "77L1", "27Y1", "68H1", "37D1", "92L1", "82K1", "99A1", "69L1", "76M1", "90B4", "48B1", "95D1", "20H1", "64H1", "79Z1", "92G1", "23G1", "21G1", "37G1", "35K1", "81H1", "83Z1", "76T1", "36F1", "36B4", "14B9", "47K1", "20K1", "62M1", "84H1", "62F1", "74A1", "18A1", "73H1", "37N1", "79N1", "61D1", "11P1", "15G1", "47N1", "19K1", "71C2", "81S1", "11M1", "60B7", "60B8", "62G1", "71A1", "24P1", "69A1", "38C1", "49N1", "21C1", "84G1", "37B1", "72A1", "88K1", "88G1", "83V1", "78C1", "73K1", "78K1", "73E189D1", "67A1", "27X1", "62A1", "18K1", "70F1", "36K5", "19B1", "49H1", "66S1", "12P1"};
ALPRChecker alprChecker;
std::vector<std::string> ValidVNCarList = { "94H", "49F", "93A", "20F", "81H", "95R", "38R", "29F", "81F", "28G", "19A", "85B", "2", "43H", "51L", "28C", "21A", "51D", "50F", "24H", "93R", "92H", "71G", "75H", "86G", "30L", "79A", "82B", "79H", "78C", "61E", "70A", "90C", "72G", "34B", "17E", "18E", "78A", "37F", "51E", "71A", "28F", "47E", "83D", "81B", "84C", "71H", "76G", "92E", "36A", "69R", "30M", "27R", "71D", "19B", "34E", "38K", "88G", "68G", "30E", "68E", "25F", "74D", "98K", "89H", "36R", "84D", "61F", "49G", "25H", "17F", "14R", "36H", "47G", "90A", "68A", "83C", "26B", "15B", "61C", "15K", "47H", "78E", "75D", "15C", "63E", "34C", "36F", "38G", "15E", "93F", "22G", "60B", "94D", "62R", "24D", "11R", "12A", "76A", "94C", "97R", "24E", "26A", "15F", "72A", "49H", "62D", "98C", "71B", "61A", "12C", "27A", "78R", "51M", "69E", "76D", "78F", "49R", "81A", "64F", "29D", "18A", "19F", "21E", "92A", "65G", "86E", "62G", "61K", "47A", "23R", "14F", "95D", "36B", "74R", "11H", "24C", "11G", "66D", "63A", "43R", "70F", "86B", "61G", "47M", "67C", "37D", "43G", "14H", "90F", "51G", "86A", "11E", "29K", "85C", "83F", "24B", "98R", "19E", "61B", "90D", "82G", "14K", "74G", "72D", "85A", "19C", "37G", "98E", "74F", "28H", "90E", "89D", "35R", "97H", "83H", "95A", "20C", "65E", "15R", "73C", "37A", "38E", "77G", "94B", "17A", "75R", "98F", "65R", "76R", "20B", "24G", "25B", "73G", "62F", "29G", "77C", "22H", "14D", "23F", "93C", "19R", "15D", "47R", "79D", "60G", "77A", "82C", "63G", "21H", "81E", "25D", "12D", "37R", "36K", "84F", "98G", "28B", "51N", "18F", "50R", "74C", "35C", "30G", "64A", "95F", "18C", "99G", "99B", "37C", "76H", "60K", "67R", "75A", "83R", "28E", "65F", "17D", "92G", "23C", "60R", "90R", "38A", "43D", "50H", "43C", "77H", "47B", "89F", "82F", "65H", "89E", "62C", "24R", "26G", "84E", "17C", "65B", "34A", "12B", "64R", "29H", "71C", "88D", "79F", "76C", "98A", "69H", "22B", "29A", "72R", "67H", "48C", "22D", "60C", "35H", "38H", "63P", "70D", "49D", "18H", "89A", "72E", "92D", "26H", "73R", "85G", "20E", "98H", "69C", "18B", "73B", "22E", "34G", "30K", "20D", "50A", "34D", "15H", "34H", "71E", "62E", "64C", "51R", "82D", "99E", "70R", "18D", "92F", "94R", "24A", "85H", "11C", "73E", "95E", "86C", "94F", "86R", "37K", "23B", "20H", "73D", "95H", "35A", "89B", "82H", "67F", "70H", "97F", "29E", "97A", "51K", "68D", "37B", "82E", "18R", "86H", "35B", "43E", "35F", "95B", "70E", "21D", "27F", "36E", "63D", "68C", "50E", "36G", "75F", "21G", "29B", "93B", "22A", "18G", "43F", "93G", "62A", "83B", "28D", "75C", "22C", "21R", "25E", "23G", "97C", "75E", "79E", "19H", "47K", "65C", "35E", "20R", "68B", "89R", "67A", "75G", "81R", "78B", "77D", "78G", "20K", "36D", "66C", "38F", "27G", "19D", "67B", "84G", "22F", "61D", "20G", "48A", "76F", "48H", "92B", "85R", "26C", "65A", "70B", "38D", "14C", "66A", "73A", "49C", "74E", "68R", "66B", "74A", "49E", "17B", "69D", "51C", "85F", "21F", "99C", "17G", "72H", "94E", "51F", "92R", "60H", "21B", "93D", "19G", "86F", "51A", "66R", "72B", "26D", "64E", "93H", "12H", "97E", "60E", "82A", "60A", "83E", "27D", "64B", "11B", "11D", "76B", "95G", "14A", "61R", "21C", "30F", "23H", "89C", "97G", "62B", "63R", "88B", "98B", "90B", "67G", "69F", "73H", "20A", "72C", "65D", "68H", "51H", "79G", "70C", "90G", "66G", "83A", "77F", "63B", "64G", "25A", "88E", "68F", "99D", "26E", "94A", "48F", "34R", "61H", "90H", "74B", "14G", "12F", "15A", "27E", "69A", "35D", "12E", "85E", "25C", "29M", "89G", "17R", "78D", "84R", "95C", "15G", "28R", "99A", "69G", "48D", "97D", "27C", "78H", "14E", "79R", "73F", "88A", "48E", "48B", "64H", "99R", "14B", "77R", "75B", "88F", "84B", "11A", "67E", "12R", "50M", "11F", "79C", "49A", "43A", "88R", "77E", "48G", "51B", "81D", "74H", "93E", "37H", "88C", "71F", "94G", "38C", "29C", "43B", "30H", "81G", "28A", "26R", "66H", "66E", "17H", "79B", "49B", "63C", "98D", "81C", "69B", "63H", "85D", "26F", "22R", "83G", "37E", "12G", "77B", "35G", "62H", "60D", "60F", "99H", "70G", "76E", "84A", "72F", "25R", "27B", "30A", "47F", "34F", "97B", "23E", "36C", "66F", "48R", "92C", "71R", "23A", "50G", "47C", "82R", "63F", "84H", "38B", "47D", "67D", "25G", "86D", "88H", "64D", "24F", "23D", "99F" };
std::mutex _ocrMutex; // Fine-grained lock for PaddleOCR (not thread-safe)
std::unique_ptr<PaddleOCR::PPOCR> ppocr = std::make_unique<PaddleOCR::PPOCR>();
[[nodiscard]] std::string AnalyseLicensePlateText(const std::string& ocrText);
[[nodiscard]] char convertDigitToLetter(char c);

View File

@@ -863,7 +863,8 @@ namespace ANSCENTER {
}
}
std::vector<Object> ANSALPR_OD::RunInferenceSingleFrame(const cv::Mat& input, const std::string& cameraId) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex here — sub-components (detectors, alprChecker) have their own locks.
// LabVIEW semaphore controls concurrency at the caller level.
// Early validation
if (!_licenseValid) {
@@ -916,18 +917,19 @@ namespace ANSCENTER {
cv::Mat draw = input.clone();
#endif
_detectedArea = cv::Rect(0, 0, frameWidth, frameHeight);
// Use local variable instead of shared _detectedArea for thread safety
cv::Rect detectedArea(0, 0, frameWidth, frameHeight);
if (_detectedArea.width <= 50 || _detectedArea.height <= 50) {
if (detectedArea.width <= 50 || detectedArea.height <= 50) {
return {};
}
#ifdef FNS_DEBUG
cv::rectangle(draw, _detectedArea, cv::Scalar(0, 0, 255), 2);
cv::rectangle(draw, detectedArea, cv::Scalar(0, 0, 255), 2);
#endif
// Run license plate detection
cv::Mat activeFrame = frame(_detectedArea);
cv::Mat activeFrame = frame(detectedArea);
std::vector<Object> lprOutput = _lpDetector->RunInference(activeFrame, cameraId);
if (lprOutput.empty()) {
@@ -1010,7 +1012,7 @@ namespace ANSCENTER {
return {};
}
std::string ANSALPR_OD::DetectLicensePlateString(const cv::Mat& lprROI, const std::string& cameraId) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — _ocrDetector has its own m_inferenceMutex
try {
// convert lprROI to greyscale if it is not already
if (lprROI.empty()) {
@@ -1277,8 +1279,7 @@ namespace ANSCENTER {
return {};
}
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — _lpColourDetector has its own m_inferenceMutex
try {
std::vector<Object> colourOutputs = _lpColourDetector->RunInference(lprROI, cameraId);
@@ -1310,8 +1311,9 @@ namespace ANSCENTER {
return DetectLPColourDetector(lprROI, cameraId);
}
// Check cache first (no GPU work needed)
// Check cache first (fine-grained lock, no GPU work)
{
std::lock_guard<std::mutex> cacheLock(_colourCacheMutex);
auto it = _colourCache.find(plateText);
if (it != _colourCache.end()) {
it->second.hitCount++;
@@ -1319,11 +1321,12 @@ namespace ANSCENTER {
}
}
// Cache miss — run the actual classifier
// Cache miss — run the actual classifier (no lock held during GPU inference)
std::string colour = DetectLPColourDetector(lprROI, cameraId);
// Store in cache
// Store in cache (fine-grained lock)
if (!colour.empty()) {
std::lock_guard<std::mutex> cacheLock(_colourCacheMutex);
if (_colourCache.size() >= COLOUR_CACHE_MAX_SIZE) {
_colourCache.clear();
}
@@ -1334,13 +1337,14 @@ namespace ANSCENTER {
}
bool ANSALPR_OD::Inference(const cv::Mat& input, std::string& lprResult) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — delegates to Inference(input, lprResult, cameraId) which is also lock-free
if (input.empty()) return false;
if ((input.cols < 5) || (input.rows < 5)) return false;
return Inference(input, lprResult, "CustomCam");
}
bool ANSALPR_OD::Inference(const cv::Mat& input, std::string& lprResult, const std::string& cameraId) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — sub-components have their own fine-grained locks.
// LabVIEW semaphore controls concurrency at the caller level.
// Early validation
if (!_licenseValid) {
@@ -1518,14 +1522,14 @@ namespace ANSCENTER {
}
}
bool ANSALPR_OD::Inference(const cv::Mat& input, const std::vector<cv::Rect> & Bbox, std::string& lprResult) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — delegates to Inference(input, Bbox, lprResult, cameraId)
if (input.empty()) return false;
if ((input.cols < 5) || (input.rows < 5)) return false;
return Inference(input, Bbox, lprResult, "CustomCam");
}
bool ANSALPR_OD::Inference(const cv::Mat& input, const std::vector<cv::Rect>& Bbox,std::string& lprResult, const std::string& cameraId)
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
// No coarse _mutex — sub-components have their own fine-grained locks.
// Early validation
if (!_licenseValid) {
@@ -2177,12 +2181,10 @@ namespace ANSCENTER {
cv::Mat unsharp;
cv::addWeighted(denoised, 1.8, blurred, -0.8, 0, unsharp);
// Step 5: CLAHE contrast enhancement
if (!_clahe) {
_clahe = cv::createCLAHE(4.0, cv::Size(8, 8));
}
// Step 5: CLAHE contrast enhancement (thread-local for thread safety)
thread_local cv::Ptr<cv::CLAHE> tl_clahe = cv::createCLAHE(4.0, cv::Size(8, 8));
cv::Mat contrastEnhanced;
_clahe->apply(unsharp, contrastEnhanced);
tl_clahe->apply(unsharp, contrastEnhanced);
// Step 6: Laplacian edge sharpening
cv::Mat lap;
@@ -2718,6 +2720,7 @@ namespace ANSCENTER {
void ANSALPR_OD::ensureUniquePlateText(std::vector<Object>& results, const std::string& cameraId)
{
std::lock_guard<std::mutex> plateLock(_plateIdentitiesMutex);
auto& identities = _plateIdentities[cameraId];
// Option B: Auto-detect mode by counting detections.

View File

@@ -24,7 +24,7 @@ namespace ANSCENTER
ANSCENTER::ModelConfig _lpdmodelConfig;
ANSCENTER::ModelConfig _ocrModelConfig;
ANSCENTER::ModelConfig _lpColourModelConfig;
cv::Ptr<cv::CLAHE> _clahe; // Reusable CLAHE instance
// _clahe moved to thread-local in enhanceForOCR() for thread safety
ANSCENTER::NV12PreprocessHelper _nv12Helper; // NV12 crop for high-res plate OCR
std::string _lpdLabels;
@@ -147,6 +147,7 @@ namespace ANSCENTER
int framesSinceLastSeen = 0;
};
// cameraId → list of tracked plate identities
std::mutex _plateIdentitiesMutex; // Fine-grained lock for plate identity tracking
std::unordered_map<std::string, std::vector<SpatialPlateIdentity>> _plateIdentities;
static constexpr float PLATE_SPATIAL_MATCH_THRESHOLD = 0.3f; // IoU threshold for same plate
void ensureUniquePlateText(std::vector<Object>& results, const std::string& cameraId);
@@ -176,6 +177,7 @@ namespace ANSCENTER
std::string colour;
int hitCount = 0;
};
std::mutex _colourCacheMutex; // Fine-grained lock for colour cache only
std::unordered_map<std::string, ColourCacheEntry> _colourCache;
static constexpr size_t COLOUR_CACHE_MAX_SIZE = 200;