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

@@ -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.