Fix ALPR Batch and memory leak

This commit is contained in:
2026-04-15 09:23:05 +10:00
parent 7778f8c214
commit b05c49ad93
9 changed files with 686 additions and 83 deletions

View File

@@ -304,11 +304,18 @@ namespace ANSCENTER {
p.framesSinceLastSeen++;
}
// Periodic pruning: remove stale entries
static thread_local int pruneCounterById = 0;
pruneCounterById++;
if (pruneCounterById >= 30 && plates.size() > 20) {
pruneCounterById = 0;
// Periodic pruning: remove stale entries.
// NOTE: previously used `static thread_local int pruneCounterById`.
// LabVIEW dispatches calls across a worker-thread pool, so the
// thread-local counter fragmented across threads and pruning
// effectively stopped firing — `trackedPlatesById[cameraId]` then
// grew unbounded (one entry per frame when trackIds never repeat),
// which manifested as a slow LabVIEW-side memory leak. The counter
// is now a plain instance member guarded by `_mutex` (taken above),
// so every 30th call across the whole engine triggers a prune pass.
_pruneCounterById++;
if (_pruneCounterById >= 30 && plates.size() > 20) {
_pruneCounterById = 0;
int staleThreshold = maxFrames * 3;
for (auto it = plates.begin(); it != plates.end(); ) {
if (it->second.framesSinceLastSeen > staleThreshold) {
@@ -521,6 +528,36 @@ namespace ANSCENTER {
ANSALPR::~ANSALPR(){};
bool ANSALPR::Destroy() { return true; };
// Default batch implementation — fallback that loops RunInference over
// vehicle crops one at a time. Subclasses should override this with a
// true batched path (see ANSALPR_OD::RunInferencesBatch and
// ANSALPR_OCR::RunInferencesBatch) to issue a single LP-detect and a
// single OCR call per frame instead of N. The fallback preserves the
// "transform bboxes back to frame coordinates" contract so a subclass
// that never overrides still produces valid output.
std::vector<Object> ANSALPR::RunInferencesBatch(
const cv::Mat& input,
const std::vector<cv::Rect>& vehicleBoxes,
const std::string& cameraId)
{
std::vector<Object> out;
if (input.empty() || vehicleBoxes.empty()) return out;
const cv::Rect frameRect(0, 0, input.cols, input.rows);
out.reserve(vehicleBoxes.size());
for (const auto& r : vehicleBoxes) {
cv::Rect c = r & frameRect;
if (c.width <= 0 || c.height <= 0) continue;
const cv::Mat crop = input(c);
std::vector<Object> perVehicle = RunInference(crop, cameraId);
for (auto& obj : perVehicle) {
obj.box.x += c.x;
obj.box.y += c.y;
out.push_back(std::move(obj));
}
}
return out;
}
std::vector<cv::Rect> ANSCENTER::ANSALPR::GetBoundingBoxes(const std::string& strBBoxes) {
std::vector<cv::Rect> bBoxes;
bBoxes.clear();