Support tracker to improve ALPR_OCR

This commit is contained in:
2026-04-14 21:18:10 +10:00
parent f9a0af8949
commit 5706615ed5
4 changed files with 435 additions and 62 deletions

View File

@@ -6,6 +6,7 @@
#include <map>
#include <string>
#include <mutex>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -45,6 +46,66 @@ namespace ANSCENTER
ALPRChecker alprChecker;
// ----------------------------------------------------------------
// Full-frame vs pipeline auto-detection (ported from ANSALPR_OD)
//
// When the caller feeds ANSLPR_OCR pre-cropped vehicle ROIs (each
// frame is a different small image), the tracker can't work — the
// LP detector sees a totally new image every call so trackIds mean
// nothing. In that "pipeline" mode we must skip the ALPRChecker
// voting layer entirely and return raw OCR results.
//
// When the caller feeds full-frame video (same resolution every
// frame, plates moving through the scene), the tracker works
// normally and we run plate text through ALPRChecker majority
// voting + spatial dedup to stabilise readings.
//
// Mode is auto-detected by watching whether consecutive frames
// share the exact same (width, height) for at least
// CONFIRM_THRESHOLD frames. Pipeline crops vary by a few pixels;
// full-frame video is pixel-identical.
// ----------------------------------------------------------------
struct ImageSizeTracker {
cv::Size lastSize{ 0, 0 };
int consistentCount = 0;
bool detectedFullFrame = false;
static constexpr int CONFIRM_THRESHOLD = 5;
static constexpr int MIN_FULLFRAME_WIDTH = 1000;
};
std::unordered_map<std::string, ImageSizeTracker> _imageSizeTrackers;
[[nodiscard]] bool shouldUseALPRChecker(const cv::Size& imageSize,
const std::string& cameraId);
// ----------------------------------------------------------------
// Spatial plate identity persistence (ported from ANSALPR_OD)
//
// Prevents the same plate string from appearing on two different
// vehicles in the same frame. The LP tracker may briefly assign
// the same trackId to two different plates when vehicles pass
// each other, or two different trackIds to the same plate when
// occlusion breaks a track. In either case, OCR can produce the
// same text for two spatial locations for a frame or two — which
// looks like "plate flicker" in the UI.
//
// ensureUniquePlateText() resolves the ambiguity by accumulating
// confidence per spatial location. When two detections share a
// plate text, the one whose spatial history has the higher score
// wins and the other has its className cleared.
// ----------------------------------------------------------------
struct SpatialPlateIdentity {
cv::Point2f center; // plate center in frame coords
std::string plateText;
float accumulatedScore = 0.0f;
int framesSinceLastSeen = 0;
};
std::mutex _plateIdentitiesMutex;
std::unordered_map<std::string, std::vector<SpatialPlateIdentity>> _plateIdentities;
static constexpr float PLATE_SPATIAL_MATCH_THRESHOLD = 0.3f; // IoU threshold
void ensureUniquePlateText(std::vector<Object>& results,
const std::string& cameraId);
// --- Original model zip path (reused for ANSONNXOCR initialization) ---
std::string _modelZipFilePath;