Fix ALPR Batch and memory leak

This commit is contained in:
2026-04-15 23:00:19 +10:00
parent b05c49ad93
commit 808df4656d
8 changed files with 1846 additions and 54 deletions

View File

@@ -125,6 +125,79 @@ namespace ANSCENTER
// --- OCR helper ---
[[nodiscard]] std::string RunOCROnPlate(const cv::Mat& plateROI, const std::string& cameraId);
// ----------------------------------------------------------------
// Plate preprocessing: classical perspective rectification
//
// Takes an LP YOLO bounding box and tries to find the plate's
// actual 4 corners via Canny + findContours + approxPolyDP. When
// that succeeds, the plate is warped to a rectangle whose height
// is fixed (kRectifiedHeight) and whose width preserves the
// detected plate's aspect ratio. This produces a tight,
// perspective-corrected crop that the recognizer handles more
// reliably than the tilted / skewed axis-aligned bbox.
//
// Falls back to minAreaRect on the largest contour if no 4-point
// polygon is found, and returns false outright if nothing
// plausible can be isolated. Callers must handle the false case
// by using the (padded) axis-aligned crop instead.
// ----------------------------------------------------------------
static constexpr int kRectifiedHeight = 220;
static constexpr float kMinPlateAspect = 1.3f;
static constexpr float kMaxPlateAspect = 6.0f;
static constexpr float kRectifyAreaFraction = 0.30f;
[[nodiscard]] bool RectifyPlateROI(
const cv::Mat& source,
const cv::Rect& bbox,
cv::Mat& outRectified) const;
// Order an arbitrary quadrilateral as
// [top-left, top-right, bottom-right, bottom-left] (in that order)
// using the x+y / y-x extreme trick so perspective transforms land
// right-side-up regardless of input winding.
[[nodiscard]] static std::vector<cv::Point2f>
OrderQuadCorners(const std::vector<cv::Point>& pts);
// ----------------------------------------------------------------
// Japan-only: targeted kana recovery
//
// The PaddleOCR v5 recognizer's CTC decoder silently drops a
// character when it sits next to a large blank region in the
// input image — which is exactly the layout of the bottom row
// of a Japanese plate (single small hiragana on the left, big
// gap, then 4 digits on the right). We detect this failure
// mode by counting UTF-8 codepoint classes in the fast-path
// output, and if hiragana/katakana is missing we re-run the
// recognizer on a tight crop of the kana region only. The
// recognizer handles that tight crop correctly because the
// input matches what it was trained on (a dense text-line
// image with no large blank stretches).
// ----------------------------------------------------------------
struct CodepointClassCounts {
int digit = 0;
int kanji = 0;
int hiragana = 0;
int katakana = 0;
};
[[nodiscard]] static CodepointClassCounts CountCodepointClasses(const std::string& text);
[[nodiscard]] static bool IsJapaneseIncomplete(const std::string& text);
// Strip non-text artifacts (screws, rivets, dirt, stickers) that
// the OCR recognizer occasionally picks up from plate surface
// features. These glyphs (degree sign, ring above, circles,
// ideographic punctuation, etc.) are never legitimate plate
// characters in any supported country, so we can drop them
// unconditionally. Runs of spaces resulting from stripped
// characters are collapsed and leading/trailing spaces trimmed.
[[nodiscard]] static std::string StripPlateArtifacts(const std::string& text);
// Run recognizer-only on a tight crop of the left portion of the
// bottom half, trying three vertical offsets to absorb row-split
// inaccuracies. Returns the first non-empty result that contains
// a hiragana or katakana codepoint, or empty string on failure.
[[nodiscard]] std::string RecoverKanaFromBottomHalf(
const cv::Mat& plateROI, int halfH) const;
public:
ANSALPR_OCR();
~ANSALPR_OCR();