Files
ANSCORE/modules/ANSLPR/ANSLPR_OD.h

266 lines
28 KiB
C
Raw Normal View History

2026-03-28 16:54:11 +11:00
#ifndef ANSLPROD_H
#define ANSLPROD_H
#pragma once
#include "ANSLPR.h"
#include "NV12PreprocessHelper.h"
#include <list>
#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>
2026-03-28 16:54:11 +11:00
#include <utility>
#include <vector>
namespace ANSCENTER
{
class ANSLPR_API ANSALPR_OD :public ANSALPR {
private:
ANSCENTER::EngineType engineType;
// --------------------------------------------------------------
// Vendor predicates — use these to gate hardware-specific paths
// (NV12 GPU crop, CUDA helpers, DirectML quirks, OpenVINO tricks).
//
// Certain helpers like _nv12Helper.tryNV12CropToBGR() call into
// CUDA runtime (cv::cuda::Stream/GpuMat/cudaStream_t) unconditionally,
// which is unsafe on AMD/Intel hardware — cv::cuda::Stream's ctor
// touches the CUDA driver even when the helper would early-return.
// Always wrap those calls in isNvidiaEngine() before invoking.
// --------------------------------------------------------------
[[nodiscard]] bool isNvidiaEngine() const noexcept {
return engineType == ANSCENTER::EngineType::NVIDIA_GPU;
}
[[nodiscard]] bool isAmdEngine() const noexcept {
return engineType == ANSCENTER::EngineType::AMD_GPU;
}
[[nodiscard]] bool isIntelEngine() const noexcept {
return engineType == ANSCENTER::EngineType::OPENVINO_GPU;
}
[[nodiscard]] bool isCpuEngine() const noexcept {
return engineType == ANSCENTER::EngineType::CPU;
}
2026-03-28 16:54:11 +11:00
std::unique_ptr<ANSCENTER::ANSODBase>_lpDetector = nullptr; // License plate detector
std::unique_ptr<ANSCENTER::ANSODBase>_ocrDetector = nullptr; // OCR detector
std::unique_ptr<ANSCENTER::ANSODBase>_lpColourDetector = nullptr; // License plate colour classifier
ANSCENTER::ModelConfig _lpdmodelConfig;
ANSCENTER::ModelConfig _ocrModelConfig;
ANSCENTER::ModelConfig _lpColourModelConfig;
// _clahe moved to thread-local in enhanceForOCR() for thread safety
2026-03-28 16:54:11 +11:00
ANSCENTER::NV12PreprocessHelper _nv12Helper; // NV12 crop for high-res plate OCR
std::string _lpdLabels;
std::string _ocrLabels;
std::string _lpColourLabels;
cv::Mat _frameBuffer; // Reusable buffer for color conversion
cv::Mat enhanceAndDebug(const cv::Mat& roi);
std::vector <std::string> _lprModelClass; //model that recognise license plate
#ifdef FNS_DEBUG
void showDebugComparison(const cv::Mat& roi, const cv::Mat& processed,
const std::vector<std::vector<cv::Point>>& contours, int bestIdx,
const cv::RotatedRect& bestRect);
#endif
[[nodiscard]] bool MatchesPlateFormat(const std::string& plate) const;
std::vector<std::string> ValidVNMotobikeList = { "29BA", "29BB", "29BC", "29BD", "29BE",
"29BF", "29BG", "29BH", "29BK", "29BL",
"29BM", "29BN", "29BP", "29AA", "29AD",
"29AE", "29AF", "29AG", "29AH", "29AK",
"29AL", "29AM", "29AN", "29AP", "29AS",
"29AT", "29AU", "29AV", "29AX", "29AY","29AZ","29AB", "29AC"//HN
"59AA", "59TA", "59FA", "59CA", "59HA",
"59KA", "59CB", "59LA", "59UA", "59MA",
"59GA", "59DB", "59PA", "59NA", "59EA",
"59SA", "59VA", "59YA", "59YB", "59ZA",
"59ZB", "59NB", "59XB", "59BA", "59XA",
"59XB", "59FA", //HCM
"43AA", "43AC", "43AD", "43AE", "43AF", "43AG", "43AB",// Da Nang
"67AA", "67AD", "67AE", "67AH", "67AB",
"67AF", "67AK", "67AL", "67AM", "67AN",// An Giang
"94AB", "94AE", "94AF", "94AH", "94AK","94FD","94FE",// Bac Lieu
"98AA", "98AH", "98AB", "98AC", "98AD",
"98AE", "98AF", "98AG", "98AK", "98AL",// Bac Giang
"71AA", "71AF", "71AG", "71AH", "71AK",
"71AB", "71AC", "71AD", "71AE", // Ben Tre
"77AA", "77AE", "77AB", "77AH",
"77AK", "77AC", "77AD", "77AF",
"77AG", "77AN", "77AM", // Binh Dinh
"69AA", "69AB", "69AC", "69AD", "69AE",
"69AF", "69KA", "69AK", "69AL", "69AM", // Ca Mau
"65MA", "65AA", "65CA", "65DB", "65EA",
"65FA", "65GA", "65HA", "65KA", // Can Tho
"76AA", "76AU", "76AV", "76AH", "76AB",
"76AC", "76AD", "76AE", "76AF", "76AK",
"76AL", "76AM", "76AN", "76AP", "76AS","76AT",// Quang Ngai
"84HA", "66PA", "84AE", "88AB", "68MA",
"63AB", "84AF", "66HA", "60AD", "47AG", "74AE",
"84AH", "76AA", "21BA", "68HA", "68AA", "28FN",
"49AL", "12HA", "66MA", "15AA", "15AC", "83VK",
"95EA", "64AA", "12FA", "21AA", "83YM", "38AG",
"68TA", "63AE", "79NA", "12ZA", "20AC", "64EA",
"66VA", "83CA", "21FA", "68KB", "74AB", "63AK",
"23AB", "47AK", "60AM", "23AE", "74AK", "84CA",
"47AV", "26AA", "28FC", "21LA", "76AS", "68FA",
"21GA", "47AH", "47AU", "23AC", "63AN", "21KA",
"49AD", "74AH", "20AK", "26AC", "74AF", "76AC",
"68NA", "60AE", "22LA", "12XA", "15AH", "26AD",
"23AA", "83EA", "47AA", "38AA", "26AB", "60AB",
"60AF", "38AE", "28FD", "66BA", "68CA", "20AD",
"21EA", "38AS", "60AA", "88AC", "64BA", "22AB",
"49AG", "38AK", "47AS", "64AC", "47AD", "68SA",
"12BA", "15AE", "28FM", "26AM", "79ZA", "66FA",
"63AH", "64DA", "47AM", "68UA", "26AG", "84AC",
"66SA", "76AD", "49AN", "26AF", "79XA", "28FS",
"49AA", "63AS", "84BA", "12SA", "83DB", "60AL",
"21HA", "38AF", "22AA", "63AF", "49AE", "47AT",
"23AD", "84AD", "23AH", "79CA", "60AH", "66GA",
"26AK", "21CA", "38AB", "28FE", "26AP", "47AP",
"47AE", "76AV", "49AC", "38AN", "12PA", "76AE",
"64FA", "12VA", "22FA", "79DA", "95NA", "76AP",
"66NA", "47AB", "74AG", "60AC", "68GA", "63AC",
"47AN", "22YA", "68PA", "47AC", "83GE", "26AL",
"64DB", "47AL", "83ZY", "60AN", "64GA", "84AL",
"49AK", "28FB", "20AE", "20AG", "76AU", "66KA",
"64CA", "76AK", "23AV", "38AX", "79HA", "47AX",
"49AM", "83PT", "15AF", "95AA", "38AM", "76AT",
"47AF", "74AC", "20AB", "64HA", "12UA", "22SA",
"68BA", "49AH", "23AK", "20AF", "63AD", "60AK",
"28FZ", "28FL", "76AB", "49AF", "26AH", "63AL",
"74AA", "79DB", "22NA", "23AU", "23AY", "83TG",
"63AM", "64KA", "23AM", "74AD", "79VA", "95XA",
"28FF", "68KA", "49AP", "83XL", "83MF", "64HB",
"15AN", "15AK", "76AF", "22TA", "12LA", "38AL",
"95HA", "68EA", "84AA", "66CA", "26AE", "66LA",
"76AN", "23AX", "95RA", "68B", "68LA", "20AH",
"20AA", "76AH", "38AC", "12TA", "76AM",
"59C3", "29S7", "29V7", "29L2", "72K1", "72D1", "98AF",
"59D2", "59S1", "59K2", "67K1", "59C4", "98AG", "59E2",
"67H2", "94L1", "29S1", "59E1", "59X4", "94B2", "67L1",
"29E1", "72C1", "29V3", "67M1", "29X7", "29X1", "98AD",
"59N3", "59C1", "59D3", "59P1", "67F1", "59M2", "59K1",
"98AB", "59T2", "72E1", "59V1", "29N2", "29E2", "67D2",
"72E2", "29T2", "29V5", "59L3", "29S2", "59L2", "72G1",
"59G2", "30Z1", "67N1", "98B1", "59U1", "59D1", "72C2",
"98B2", "98M1", "29P1", "67M2", "98H1", "29V1", "29K2",
"59V2", "59F2", "59N1", "29Z1", "98D1", "59C2", "94K1",
"67G1", "98AL", "29Y5", "59B1", "41B1", "94G1", "59G1",
"94M1", "59X2", "67C1", "67D1", "59X3", "67B1", "98AC",
"67C2", "98B3", "59Z1", "59Z2", "98AH", "59S3", "94F1",
"98L1", "59H2", "98D2", "29D1", "59M1", "29B2", "29D2",
"29U1", "59U2", "29H2", "29K1", "94B1", "98C1", "59F1",
"67H1", "29F1", "29Y1", "59P2", "67L2", "59X1", "98G1",
"29C1", "67B2", "59T1", "29G2", "29L5", "29S6", "29Y7",
"59Y2", "67E1", "98AK", "94C1", "29X2", "98K1", "98AE",
"98AA", "29H1", "29T1", "67K2", "94D2", "94E1", "29M1",
"29N1", "59Y1", "72H1", "29X3", "98F1", "29C2", "94K2",
"72F1", "29M2", "29Y3", "59P3", "29E3", "29G1", "59V3",
"59Y3", "29P2", "59N2", "29L1", "98E1", "59G3", "29X5",
"59S2", "94D1", "59H1", "29B1", "59L1", "50X1", "72L1",
"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"
ALPRChecker alprChecker;
// --- Full-frame vs pipeline auto-detection ---
// Tri-state: -1 = auto-detect (default), 0 = explicitly disabled, 1 = explicitly enabled
// _enableALPRChecker is inherited from ANSALPR base class
// Master switch for tracker + voting post-processing inside
// RunInference / RunInferenceSingleFrame. When false, these methods
// return raw per-frame OCR output (no alprChecker.checkPlateByTrackId
// voting, no spatial ensureUniquePlateText dedup). Default: disabled.
bool _enableTrackerVoting{ false };
struct ImageSizeTracker {
cv::Size lastSize{0, 0};
int consistentCount = 0;
bool detectedFullFrame = false;
static constexpr int CONFIRM_THRESHOLD = 5;
// Full-frame images must be exactly the same size every frame.
// Pipeline crops vary by a few pixels, so exact match filters them out.
// Additionally, full-frame is typically >1000px wide; crops are smaller.
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);
2026-04-01 17:01:05 +11:00
// Plate identity persistence: accumulated confidence per spatial plate location.
// Prevents the same plate string from appearing on multiple vehicles.
// Uses bounding box center position (not trackId) as the identity key,
// since trackIds may overlap when ALPR runs on cropped vehicle images.
struct SpatialPlateIdentity {
cv::Point2f center; // plate center in frame coordinates
std::string plateText;
float accumulatedScore = 0.0f;
2026-04-01 17:01:05 +11:00
int framesSinceLastSeen = 0;
};
2026-04-01 17:01:05 +11:00
// cameraId → list of tracked plate identities
std::mutex _plateIdentitiesMutex; // Fine-grained lock for plate identity tracking
2026-04-01 17:01:05 +11:00
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);
2026-03-28 16:54:11 +11:00
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",
[[nodiscard]] std::string AnalyseLicensePlateText(const std::string& ocrText);
[[nodiscard]] char convertDigitToLetter(char c);
[[nodiscard]] char convertLetterToDigit(char c);
[[nodiscard]] char fixLPDigit(char c);
[[nodiscard]] int findSubstringIndex(const std::string& str);
[[nodiscard]] std::string convertStringToDigits(const std::string& input);
[[nodiscard]] std::string convertStringToLetters(const std::string& input);
[[nodiscard]] int searchDiplomacyLP(const std::string& input);
[[nodiscard]] bool ValidateVNMotobikeLP(const std::string& input);
[[nodiscard]] bool ValidateVNCarLP(const std::string& input);
bool valid;
cv::Mat alignPlateForOCR(const cv::Mat& fullImage, const cv::Rect& bbox);
cv::Mat enhanceForOCR(const cv::Mat& plateROI);
[[nodiscard]] std::string DetectLicensePlateString(const cv::Mat& lprROI, const std::string& cameraId);
[[nodiscard]] std::string DetectLPColourDetector(const cv::Mat& lprROI, const std::string& cameraId);
[[nodiscard]] std::string DetectLPColourCached(const cv::Mat& lprROI, const std::string& cameraId, const std::string& plateText);
// LPC colour cache: keyed by plate text (e.g. "29BA-12345"),
// stores { colour, hitCount }. Plate colour doesn't change, so
// we only run the classifier once per unique plate and reuse the
// result for subsequent frames.
struct ColourCacheEntry {
std::string colour;
int hitCount = 0;
};
std::mutex _colourCacheMutex; // Fine-grained lock for colour cache only
2026-03-28 16:54:11 +11:00
std::unordered_map<std::string, ColourCacheEntry> _colourCache;
static constexpr size_t COLOUR_CACHE_MAX_SIZE = 200;
public:
ANSALPR_OD();
~ANSALPR_OD();
[[nodiscard]] bool Initialize(const std::string& licenseKey, const std::string& modelZipFilePath, const std::string& modelZipPassword, double detectorThreshold, double ocrThreshold, double colourThreshold) override;
[[nodiscard]] bool LoadEngine() override;
[[nodiscard]] bool Inference(const cv::Mat& input, std::string& lprResult) override;
[[nodiscard]] bool Inference(const cv::Mat& input, std::string& lprResult, const std::string &cameraId) override;
[[nodiscard]] bool Inference(const cv::Mat& input, const std::vector<cv::Rect> & Bbox, std::string& lprResult) override;
[[nodiscard]] bool Inference(const cv::Mat& input, const std::vector<cv::Rect> & Bbox, std::string& lprResult, const std::string & cameraId) override;
[[nodiscard]] std::vector<Object> RunInferenceSingleFrame(const cv::Mat& input, const std::string& cameraId);
[[nodiscard]] std::vector<Object> RunInference(const cv::Mat& input, const std::string& cameraId) override;
2026-04-15 09:23:05 +10:00
[[nodiscard]] std::vector<Object> RunInferencesBatch(
const cv::Mat& input,
const std::vector<cv::Rect>& vehicleBoxes,
const std::string& cameraId) override;
2026-03-28 16:54:11 +11:00
[[nodiscard]] std::vector<std::string> DetectLicensePlateStringBatch(const std::vector<cv::Mat>& lprROIs, const std::string& cameraId);
[[nodiscard]] std::vector<std::string> DetectLPColourDetectorBatch(const std::vector<cv::Mat>& lprROIs, const std::string& cameraId);
[[nodiscard]] std::string ProcessSingleOCRResult(const std::vector<Object>& ocrOutput);
[[nodiscard]] bool Destroy() override;
/// Propagate debug flag to all sub-detectors (LPD, OCR, colour)
void ActivateDebugger(bool debugFlag) override {
_debugFlag = debugFlag;
if (_lpDetector) _lpDetector->ActivateDebugger(debugFlag);
if (_ocrDetector) _ocrDetector->ActivateDebugger(debugFlag);
if (_lpColourDetector) _lpColourDetector->ActivateDebugger(debugFlag);
}
// SetALPRCheckerEnabled() and IsALPRCheckerEnabled() inherited from ANSALPR base class
void SetTrackerVotingEnabled(bool enable) { _enableTrackerVoting = enable; }
[[nodiscard]] bool IsTrackerVotingEnabled() const { return _enableTrackerVoting; }
2026-03-28 16:54:11 +11:00
};
}
#endif