2026-03-28 16:54:11 +11:00
|
|
|
#ifndef ANSLPR_H
|
|
|
|
|
#define ANSLPR_H
|
|
|
|
|
#define ANSLPR_API __declspec(dllexport)
|
|
|
|
|
#pragma once
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include <opencv2/opencv.hpp>
|
|
|
|
|
#include "Utility.h"
|
|
|
|
|
#include "ANSLicense.h"
|
|
|
|
|
#include "LabVIEWHeader/extcode.h"
|
|
|
|
|
#include "ANSEngineCommon.h"
|
|
|
|
|
#define MAX_ALPR_FRAME 60
|
|
|
|
|
namespace ANSCENTER
|
|
|
|
|
{
|
2026-03-30 15:21:32 +11:00
|
|
|
// Country enum is now defined in ANSLicense.h (ANSCENTER namespace)
|
|
|
|
|
|
2026-03-28 16:54:11 +11:00
|
|
|
class ALPRChecker {
|
|
|
|
|
private:
|
|
|
|
|
int maxFrames;
|
|
|
|
|
int minVotesToStabilize = 3; // need at least 3 identical reads to lock
|
|
|
|
|
float iouMatchThreshold = 0.3f; // IoU to match same physical plate across frames
|
|
|
|
|
std::recursive_mutex _mutex;
|
|
|
|
|
|
|
|
|
|
// Per-plate spatial tracking: each tracked plate has a location + text history
|
|
|
|
|
struct TrackedPlate {
|
|
|
|
|
cv::Rect lastBox;
|
|
|
|
|
std::deque<std::string> textHistory; // rolling history of OCR reads
|
|
|
|
|
std::string lockedText; // majority-vote winner (empty = not locked yet)
|
|
|
|
|
int lockCount = 0; // how many consecutive frames the lock held
|
|
|
|
|
int framesSinceLastSeen = 0; // how many checkPlate calls since this plate was last matched
|
|
|
|
|
};
|
|
|
|
|
int _pruneCounter = 0; // counts checkPlate calls for periodic pruning
|
|
|
|
|
// cameraId -> list of tracked plates
|
|
|
|
|
std::unordered_map<std::string, std::vector<TrackedPlate>> trackedPlates;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] int levenshteinDistance(const std::string& s1, const std::string& s2);
|
|
|
|
|
[[nodiscard]] float computeIoU(const cv::Rect& a, const cv::Rect& b);
|
|
|
|
|
[[nodiscard]] std::string majorityVote(const std::deque<std::string>& history);
|
|
|
|
|
public:
|
|
|
|
|
void Init(int framesToStore = MAX_ALPR_FRAME);
|
|
|
|
|
ALPRChecker(int framesToStore = MAX_ALPR_FRAME) : maxFrames(framesToStore) {}
|
|
|
|
|
// Original API (backward compatible) — no spatial tracking
|
|
|
|
|
[[nodiscard]] std::string checkPlate(const std::string& cameraId, const std::string& detectedPlate);
|
|
|
|
|
// Enhanced API with bounding box for spatial plate tracking
|
|
|
|
|
[[nodiscard]] std::string checkPlate(const std::string& cameraId, const std::string& detectedPlate, const cv::Rect& plateBox);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ANSLPR_API ANSALPR {
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
SPDLogger& _logger = SPDLogger::GetInstance("ALPR", false);
|
|
|
|
|
bool _debugFlag{ false };
|
|
|
|
|
bool _licenseValid{ false };
|
|
|
|
|
bool _isInitialized{ false};
|
|
|
|
|
double _detectorThreshold{ 0.5 };
|
|
|
|
|
double _ocrThreshold{ 0.5 };
|
|
|
|
|
double _colorThreshold{ 0.0 };// If we use the colour information, this threshold should be greater than 0.0
|
|
|
|
|
std::vector<std::string> _plateFormats;
|
|
|
|
|
std::string _licenseKey{};
|
|
|
|
|
std::string _modelFolder;
|
|
|
|
|
struct ImageSection {
|
|
|
|
|
cv::Rect region;
|
|
|
|
|
int priority;
|
|
|
|
|
ImageSection(const cv::Rect& r) : region(r), priority(0) {}
|
|
|
|
|
};
|
|
|
|
|
cv::Size previousImageSize = cv::Size(0, 0);
|
|
|
|
|
std::vector<ImageSection> cachedSections;
|
|
|
|
|
int _currentPriority{ 0 }; // None
|
|
|
|
|
cv::Rect _detectedArea;// Area where license plate are detected
|
|
|
|
|
Country _country;
|
|
|
|
|
std::recursive_mutex _mutex;
|
|
|
|
|
public:
|
|
|
|
|
[[nodiscard]] virtual bool Initialize(const std::string& licenseKey, const std::string& modelZipFilePath, const std::string& modelZipPassword, double detectorThreshold, double ocrThreshold, double colourTheshold=0);
|
|
|
|
|
[[nodiscard]] virtual bool LoadEngine();
|
|
|
|
|
[[nodiscard]] virtual bool Inference(const cv::Mat& input, std::string& lprResult) = 0;
|
|
|
|
|
[[nodiscard]] virtual bool Inference(const cv::Mat& input, std::string& lprResult,const std::string &cameraId) = 0;
|
|
|
|
|
[[nodiscard]] virtual bool Inference(const cv::Mat& input, const std::vector<cv::Rect> & Bbox, std::string& lprResult) = 0;
|
|
|
|
|
[[nodiscard]] virtual bool Inference(const cv::Mat& input, const std::vector<cv::Rect> & Bbox, std::string& lprResult,const std::string & cameraId) = 0;
|
|
|
|
|
[[nodiscard]] virtual std::vector<Object> RunInference(const cv::Mat& input, const std::string &cameraId) = 0;
|
|
|
|
|
[[nodiscard]] std::string VectorDetectionToJsonString(const std::vector<Object>& dets);
|
|
|
|
|
void SetPlateFormats(const std::vector<std::string>& formats);
|
|
|
|
|
void SetPlateFormat(const std::string& format);
|
|
|
|
|
[[nodiscard]] std::vector<std::string> GetPlateFormats() const;
|
|
|
|
|
virtual ~ANSALPR();
|
|
|
|
|
void CheckLicense();
|
|
|
|
|
|
|
|
|
|
/// Enable/disable deep pipeline benchmarking.
|
|
|
|
|
/// When enabled, logs per-stage timing for the full ALPR pipeline
|
|
|
|
|
/// (LP detection, OCR, color classification, validation, serialization).
|
|
|
|
|
/// Also propagates the flag to sub-detectors (_lpDetector, _ocrDetector, etc.).
|
|
|
|
|
virtual void ActivateDebugger(bool debugFlag) { _debugFlag = debugFlag; }
|
|
|
|
|
[[nodiscard]] virtual bool Destroy() = 0;
|
|
|
|
|
[[nodiscard]] static std::vector<cv::Rect> GetBoundingBoxes(const std::string& strBBoxes);
|
|
|
|
|
[[nodiscard]] static std::string PolygonToString(const std::vector<cv::Point2f>& polygon);
|
|
|
|
|
[[nodiscard]] static std::string KeypointsToString(const std::vector<float>& kps);
|
|
|
|
|
[[nodiscard]] static std::vector<cv::Point2f> RectToNormalizedPolygon(const cv::Rect& rect, float imageWidth, float imageHeight);
|
|
|
|
|
protected:
|
|
|
|
|
// Utilities for scanning license plate
|
|
|
|
|
// Function to seperate screen size
|
|
|
|
|
[[nodiscard]] double calculateDistanceToCenter(const cv::Point& center, const cv::Rect& rect);
|
|
|
|
|
[[nodiscard]] std::vector<ImageSection> divideImage(const cv::Mat& image);
|
|
|
|
|
[[nodiscard]] std::vector<ANSALPR::ImageSection> createSlideScreens(const cv::Mat& image);
|
|
|
|
|
[[nodiscard]] int getHighestPriorityRegion();
|
|
|
|
|
[[nodiscard]] int getLowestPriorityRegion();
|
|
|
|
|
[[nodiscard]] cv::Rect getRegionByPriority(int priority);
|
|
|
|
|
[[nodiscard]] std::vector<Object> AdjustLicensePlateBoundingBoxes(const std::vector<Object>& detectionsInROI,
|
|
|
|
|
const cv::Rect& roi, const cv::Size& fullImageSize,
|
|
|
|
|
float aspectRatio = 2.0f, // width at least 2x height
|
|
|
|
|
int padding = 10 // base padding
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C" ANSLPR_API int CreateANSALPRHandle(ANSCENTER::ANSALPR **Handle, const char* licenseKey, const char* modelZipFilePath, const char* modelZipPassword, int engineType, double detectorThreshold, double ocrThreshold, double colourThreshold);
|
|
|
|
|
extern "C" ANSLPR_API int LoadANSALPREngineHandle(ANSCENTER::ANSALPR** Handle);
|
|
|
|
|
|
|
|
|
|
extern "C" ANSLPR_API std::string ANSALPR_RunInference(ANSCENTER::ANSALPR **Handle, unsigned char* jpeg_string, unsigned int bufferLength);
|
|
|
|
|
extern "C" ANSLPR_API std::string ANSALPR_RunInferenceWithCamID(ANSCENTER::ANSALPR** Handle, unsigned char* jpeg_string, unsigned int bufferLength, const char* cameraId);
|
|
|
|
|
extern "C" ANSLPR_API std::string ANSALPR_RunInferenceBinary(ANSCENTER::ANSALPR * *Handle, unsigned char* jpeg_bytes, unsigned int width, unsigned int height);
|
|
|
|
|
extern "C" ANSLPR_API std::string ANSALPR_RunInferenceBinaryInCroppedImages(ANSCENTER::ANSALPR * *Handle, unsigned char* jpeg_bytes, unsigned int width, unsigned int height, const char* strBboxes);
|
|
|
|
|
extern "C" ANSLPR_API std::string ANSALPR_RunInferenceInCroppedImages(ANSCENTER::ANSALPR** Handle, unsigned char* jpeg_string, unsigned int bufferLength, const char* strBboxes);
|
|
|
|
|
extern "C" ANSLPR_API std::string ANSALPR_RunInferenceInCroppedImagesWithCamID(ANSCENTER::ANSALPR** Handle, unsigned char* jpeg_string, unsigned int bufferLength, const char* strBboxes, const char* cameraId);
|
|
|
|
|
|
|
|
|
|
extern "C" ANSLPR_API int ReleaseANSALPRHandle(ANSCENTER::ANSALPR **Handle);
|
|
|
|
|
//// For LabVIEW API
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_RunInference_LV(ANSCENTER::ANSALPR **Handle, unsigned char* jpeg_string, unsigned int bufferLength, LStrHandle detectionResult);
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_RunInferenceWithCamID_LV(ANSCENTER::ANSALPR** Handle, unsigned char* jpeg_string, unsigned int bufferLength, const char* cameraId, LStrHandle detectionResult);
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_RunInferenceBinary_LV(ANSCENTER::ANSALPR * *Handle, unsigned char* jpeg_bytes, unsigned int width, unsigned int height, LStrHandle detectionResult);
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_RunInferenceInCroppedImages_LV(ANSCENTER::ANSALPR * *Handle, unsigned char* jpeg_string, unsigned int bufferLength, const char* strBboxes, LStrHandle detectionResult);
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_RunInferenceInCroppedImagesWithCamID_LV(ANSCENTER::ANSALPR** Handle, unsigned char* jpeg_string, unsigned int bufferLength, const char* strBboxes, const char* cameraId, LStrHandle detectionResult);
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_RunInferenceComplete_LV(ANSCENTER::ANSALPR** Handle, cv::Mat** cvImage, const char* cameraId, int getJpegString, int jpegImageSize, LStrHandle detectionResult, LStrHandle imageStr);
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_RunInferenceComplete_CPP(ANSCENTER::ANSALPR** Handle, cv::Mat** cvImage, const char* cameraId, int getJpegString, int jpegImageSize,std::string& detectionResult, std::string& imageStr);
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_RunInferencesComplete_LV(ANSCENTER::ANSALPR** Handle, cv::Mat** cvImage, const char* cameraId, int maxImageSize,const char* strBboxes, LStrHandle detectionResult);
|
|
|
|
|
|
|
|
|
|
// Get/Set format
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_SetFormat(ANSCENTER::ANSALPR** Handle, const char* format);
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_SetFormats(ANSCENTER::ANSALPR** Handle, const char* formats);// comma separated formats
|
|
|
|
|
extern "C" ANSLPR_API int ANSALPR_GetFormats(ANSCENTER::ANSALPR** Handle, LStrHandle formats);// comma separated formats
|
|
|
|
|
|
2026-03-31 14:10:21 +11:00
|
|
|
// Unicode conversion utilities for LabVIEW wrapper classes
|
2026-03-31 21:52:47 +11:00
|
|
|
extern "C" ANSLPR_API int ANSLPR_ConvertUTF8ToUTF16LE(const char* utf8Str, LStrHandle result, int includeBOM = 1);
|
2026-03-31 14:10:21 +11:00
|
|
|
extern "C" ANSLPR_API int ANSLPR_ConvertUTF16LEToUTF8(const unsigned char* utf16leBytes, int byteLen, LStrHandle result);
|
|
|
|
|
|
2026-03-28 16:54:11 +11:00
|
|
|
#endif
|