Files
ANSCORE/modules/ANSODEngine/ANSEngineCommon.h

1160 lines
56 KiB
C
Raw Normal View History

2026-03-28 16:54:11 +11:00
#ifndef ANSENGINECOMMON_H
#define ANSENGINECOMMON_H
#define ANSENGINE_API __declspec(dllexport)
#pragma once
#include <opencv2/opencv.hpp>
#include <opencv2/core/cuda.hpp>
#include <openvino/openvino.hpp>
#include "ANSLicense.h"
#include "Utility.h"
#include <algorithm>
#include <fstream>
#include <exception>
#include <random>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <string>
#include <map>
#include "ANSMOT.h"
#include "onnxruntime_cxx_api.h"
#define USEONNXOV
#define RETAINDETECTEDFRAMES 80
#define DEBUG_PRINT(x) std::cout << x << std::endl;
//#define DEBUGENGINE
//#define USE_TV_MODEL // Use model to detect if person is on TV screen or not
const int MAX_HISTORY_FACE = 5;
const int MAX_MISSING_FACE = 30;
const int MAX_TRACKS = 200;
const float PAD_TRACK_RATIO = 0.5f;
const float PAD_DETECT_RATIO = 1.0f;
const int MAX_MISSING_SCREEN = 1000;
namespace ANSCENTER
{
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
inline clamp(const T& value, const T& low, const T& high)
{
T validLow = low < high ? low : high;
T validHigh = low < high ? high : low;
if (value < validLow) return validLow;
if (value > validHigh) return validHigh;
return value;
}
struct Point {
int x, y;
};
struct ROIConfig {
bool Rectangle;
bool Polygon;
bool Line;
int MinItems;
int MaxItems;
std::string Name;
std::string ROIMatch;
};
struct Parameter {
std::string Name;
std::string DataType;
int NoOfDecimals;
int MaxValue;
int MinValue;
std::string StartValue;
std::vector<std::string> ListItems;
std::string DefaultValue;
std::string Value;
};
struct ROIValue {
std::string ROIMatch;
std::vector<Point> ROIPoints;
std::string Option;
std::string Name;
int OriginalImageSize;
};
struct Params {
std::vector<ROIConfig> ROI_Config;
std::vector<std::string> ROI_Options;
std::vector<Parameter> Parameters;
std::vector<ROIValue> ROI_Values;
};
/* Example
{
"ROI_Config":[
{
"Rectangle":true,
"Polygon":true,
"Line":false,
"MinItems":0,
"MaxItems":3,
"Name":"Traffic Light",
"ROI-Match":"All Corners"
},
{
"Rectangle":true,
"Polygon":false,
"Line":false,
"MinItems":1,
"MaxItems":1,
"Name":"Car Zone",
"ROI-Match":"All Corners"
},
{
"Rectangle":false,
"Polygon":false,
"Line":true,
"MinItems":1,
"MaxItems":2,
"Name":"Cross Line",
"ROI-Match":"All Corners"
}
],
"ROI_Options":[
"Inside ROI",
"Inside ROI",
"Both Directions"
],
"Parameters":[
{
"Name":"Para1",
"DataType":"Boolean",
"NoOfdecimals":0,
"MaxValue":0,
"MinValue":0,
"StartValue":"",
"ListItems":[],
"DefaultValue":"",
"Value":"true"
},
{
"Name":"Para2",
"DataType":"Integer",
"NoOfdecimals":0,
"MaxValue":5,
"MinValue":1,
"StartValue":"2",
"ListItems":[],
"DefaultValue":"",
"Value":"3"
},
{
"Name":"Para3",
"DataType":"List-Single",
"NoOfdecimals":0,
"MaxValue":0,
"MinValue":0,
"StartValue":"",
"ListItems":["A","B","C"],
"DefaultValue":"",
"Value":"A"
},
{
"Name":"Para4",
"DataType":"Range",
"NoOfdecimals":0,
"MaxValue":100,
"MinValue":50,
"StartValue":">,60",
"ListItems":[">","<"],
"DefaultValue":"",
"Value":">,52.000000"
}
],
"ROI_Values":[
{
"ROI-Match":"Centre Point",
"ROIPoints":[
{"x":269,"y":134},
{"x":777,"y":134},
{"x":777,"y":457},
{"x":269,"y":457}
],
"Option":"Inside ROI",
"Name":"Car Zone 1",
"OriginalImageSize":1920
},
{
"ROI-Match":"Centre Point",
"ROIPoints":[{"x":280,"y":613},{"x":1108,"y":280}],
"Option":"Above",
"Name":"Cross Line 1",
"OriginalImageSize":1920
},
{
"ROI-Match":"Centre Point",
"ROIPoints":[{"x":1511,"y":383},{"x":1283,"y":754}],
"Option":"Left side",
"Name":"Cross Line 2",
"OriginalImageSize":1920
},
{
"ROI-Match":"Centre Point",
"ROIPoints":[
{"x":229,"y":161},
{"x":964,"y":161},
{"x":964,"y":628},
{"x":229,"y":628}
],
"Option":"Left side",
"Name":"Traffic Light 1",
"OriginalImageSize":1920
},
{
"ROI-Match":"Centre Point",
"ROIPoints":[
{"x":1115,"y":304},
{"x":1730,"y":304},
{"x":1730,"y":695},
{"x":1115,"y":695}
],
"Option":"Left side",
"Name":"Traffic Light 2",
"OriginalImageSize":1920
},
{
"ROI-Match":"Centre Point",
"ROIPoints":[
{"x":678,"y":683},
{"x":1217,"y":683},
{"x":1217,"y":1026},
{"x":678,"y":1026}
],
"Option":"Left side",
"Name":"Traffic Light 3",
"OriginalImageSize":1920
}
]
}
*/
struct MetaData
{
float imageThreshold;
float pixelThreshold;
float min;
float max;
int inferSize[2]; // h w
int imageSize[2]; // h w
std::vector<float> _mean;
std::vector<float> _std;
};
struct Resize
{
cv::Mat resizedImage;
int dw;
int dh;
};
struct Object
{
int classId{ 0 };
int trackId{ 0 };
std::string className{};
float confidence{ 0.0 };
cv::Rect box{};
std::vector<cv::Point2f> polygon; // polygon that contain x1,y1,x2,y2,x3,y3,x4,y4 (for both segmentation and pose estimation)
cv::Mat mask{}; // image in box (cropped)
cv::cuda::GpuMat gpuMask{}; // GPU-resident face crop (set by NV12 affine warp, avoids re-upload)
std::vector<float> kps{}; // Pose exsimate keypoints, containing x1,y1,x2,y2,... or oriented box x,y,width,height,angle
std::string extraInfo; // More information such as facial recognition
std::string cameraId; // Use to check if this object belongs to any camera
// std::string attributes;
};
struct FaceResultObject {
int trackId{ 0 };
std::string userId;
std::string userName;
float similarity;
bool isUnknown;
bool isMasked; // If the face is masked
cv::Rect box{}; // Face bounding box
cv::Mat mask;
std::vector<cv::Point2f> polygon; // polygon that contain x1 ,y1,x2,y2,x3,y3,x4,y4
std::vector<float> kps{}; // Containing landmarks
float confidence{ 0.0 };
std::string extraInformation;
std::string cameraId;
// std::string attributes; // Face attributes (in Json format)
};
struct BoundingBox {
int x;
int y;
int width;
int height;
BoundingBox() : x(0), y(0), width(0), height(0) {}
BoundingBox(int x_, int y_, int width_, int height_)
: x(x_), y(y_), width(width_), height(height_) {}
};
struct KeyPoint {
float x; ///< X-coordinate of the keypoint
float y; ///< Y-coordinate of the keypoint
float confidence; ///< Confidence score of the keypoint
KeyPoint(float x_ = 0, float y_ = 0, float conf_ = 0)
: x(x_), y(y_), confidence(conf_) {
}
};
// A group holds a set of objects and the union (bounding box) of all their boxes.
struct Group {
std::vector<Object> objects;
cv::Rect unionBox;
};
typedef std::pair<cv::Scalar, cv::Scalar> Range;
class ANSENGINE_API ANNHUBClassifier
{
private:
std::vector<double> nInput; //ANN inputs
std::vector<double> nOutput; //ANN outputs
std::vector<std::vector<double>> IW;
std::vector<std::vector<double>> LW;
std::vector<double> Ib;
std::vector<double> Lb;
// Structural parameters
int nInputNodes, nHiddenNodes, nOutputNodes;
int hiddenActivation; // default =2
int outputActivation; // default =2
int dataNormalisationModeInput; // default =1;
int dataNormalisationModeOutput; // default =1;
// Preprocessing and postprocessing settings
std::vector<double> xmaxInput, xminInput; // Maximum and minimum of inputs
double ymaxInput, yminInput; // Maximum and minimum of inputs
std::vector<double> xmaxOutput, xminOutput; // Maximum and minimum of outputs
double ymaxOutput, yminOutput; // Maximum and minimum of outputs
// Control creation
unsigned char isCreated;
std::string _licenseKey;
bool _licenseValid{ false };
bool _isInitialized{ false };
std::string _modelFilePath;
private:
void PreProcessing(std::vector<double>& Input); // mode =0--> linear, mode =1 mapminmax, mode =2 standarddev
void PostProcessing(std::vector<double>& Output); // mode =0--> linear, mode =1 mapminmax, mode =2 standarddev
void Create(int inputNodes, int HiddenNodes, int outputNodes);
void FreeNeuralNetwork();
void CheckLicense();
int ImportANNFromFile(std::string filename);
public:
ANNHUBClassifier();
~ANNHUBClassifier();
bool Init(std::string licenseKey, std::string modelFilePath);
std::vector<double> Inference(std::vector<double> ip);
void Destroy();
int GetOutputNode() { return nOutputNodes; };
private:
void ReLu(std::vector<double>& iVal, std::vector<double>& oVal);
void LogSig(std::vector<double>& iVal, std::vector<double>& oVal);
void TanSig(std::vector<double>& iVal, std::vector<double>& oVal);
void PureLin(std::vector<double>& iVal, std::vector<double>& oVal);
void SoftMax(std::vector<double>& iVal, std::vector<double>& oVal);
void ActivationFunction(std::vector<double>& iVal, std::vector<double>& oVal, int mode);
};
class ANSENGINE_API MoveDetectsHandler
{
public:
// Constructor and Destructor
MoveDetectsHandler();
~MoveDetectsHandler();
// Main detection methods
std::vector<Object> MovementDetect(const std::string& camera_id, cv::Mat& next_image);
std::vector<Object> MovementDetect(const std::string& camera_id, const size_t frame_index, cv::Mat& image);
// Camera management
bool hasCameraData(const std::string& camera_id) const;
void removeCamera(const std::string& camera_id);
std::vector<std::string> getCameraIds() const;
// Configuration methods
void setThreshold(const std::string& camera_id, double threshold);
void setKeyFrameFrequency(const std::string& camera_id, size_t frequency);
void setNumberOfControlFrames(const std::string& camera_id, size_t count);
void setThumbnailRatio(const std::string& camera_id, double ratio);
void setMaskEnabled(const std::string& camera_id, bool enabled);
void setContoursEnabled(const std::string& camera_id, bool enabled);
void setBboxEnabled(const std::string& camera_id, bool enabled);
void setContourThickness(const std::string& camera_id, int thickness);
void setBboxThickness(const std::string& camera_id, int thickness);
void setMinObjectArea(const std::string& camera_id, double area);
void setMinObjectSize(const std::string& camera_id, int size);
void setMorphologyIterations(const std::string& camera_id, int iterations);
// Temporal consistency settings
void setTemporalConsistency(const std::string& camera_id, bool enabled);
void setMaskOverlapThreshold(const std::string& camera_id, double threshold);
void setTemporalHistorySize(const std::string& camera_id, size_t size);
void setMinConsistentFrames(const std::string& camera_id, size_t frames);
void setLocationStabilityEnabled(const std::string& camera_id, bool enabled);
void setMaxLocationJitter(const std::string& camera_id, double pixels);
// Getters for configuration
double getThreshold(const std::string& camera_id) const;
size_t getKeyFrameFrequency(const std::string& camera_id) const;
size_t getNumberOfControlFrames(const std::string& camera_id) const;
double getThumbnailRatio(const std::string& camera_id) const;
bool isMaskEnabled(const std::string& camera_id) const;
bool isContoursEnabled(const std::string& camera_id) const;
bool isBboxEnabled(const std::string& camera_id) const;
bool isTemporalConsistencyEnabled(const std::string& camera_id) const;
// State query methods
bool isMovementDetected(const std::string& camera_id) const;
bool wasTransitionDetected(const std::string& camera_id) const;
double getPSNRScore(const std::string& camera_id) const;
size_t getFrameIndexWithMovement(const std::string& camera_id) const;
std::chrono::milliseconds getTimeSinceLastMovement(const std::string& camera_id) const;
size_t getControlFrameCount(const std::string& camera_id) const;
size_t getNextFrameIndex(const std::string& camera_id) const;
double getTemporalConsistencyScore(const std::string& camera_id) const;
// Public utility methods
bool empty(const std::string& camera_id) const;
void clear(const std::string& camera_id);
void clearAll();
cv::Mat getOutput(const std::string& camera_id) const;
cv::Mat getMask(const std::string& camera_id) const;
std::vector<std::vector<cv::Point>> getContours(const std::string& camera_id) const;
// Statistics
struct CameraStats {
size_t total_frames_processed = 0;
size_t frames_with_movement = 0;
size_t frames_rejected_by_temporal_check = 0;
size_t control_frames_count = 0;
double average_psnr = 0.0;
double min_psnr = std::numeric_limits<double>::max();
double max_psnr = 0.0;
double average_temporal_consistency = 0.0;
std::chrono::milliseconds total_processing_time{ 0 };
std::chrono::high_resolution_clock::time_point last_movement_time;
// Reset stats
void reset()
{
total_frames_processed = 0;
frames_with_movement = 0;
frames_rejected_by_temporal_check = 0;
control_frames_count = 0;
average_psnr = 0.0;
min_psnr = std::numeric_limits<double>::max();
max_psnr = 0.0;
average_temporal_consistency = 0.0;
total_processing_time = std::chrono::milliseconds{ 0 };
}
};
CameraStats getStats(const std::string& camera_id) const;
void resetStats(const std::string& camera_id);
private:
struct CameraData
{
// Detection state
bool movement_detected = false;
bool transition_detected = false;
size_t next_frame_index = 0;
size_t next_key_frame = 0;
double most_recent_psnr_score = 0.0;
size_t frame_index_with_movement = 0;
double max_change_percentage = 20.0; // Max % of frame that can change
double min_change_percentage = 1.0; // Min % of frame that must change
std::chrono::high_resolution_clock::time_point movement_last_detected;
// Control frames storage
std::map<size_t, cv::Mat> control_frames;
// Output data
cv::Mat output;
cv::Mat mask;
std::vector<std::vector<cv::Point>> contours;
// Configuration parameters
size_t key_frame_frequency = 20;
size_t number_of_control_frames = 10;
double psnr_threshold = 45.0;
double thumbnail_ratio = 0.05;
cv::Size thumbnail_size = cv::Size(0, 0);
// Visual options
bool mask_enabled = true;
bool contours_enabled = true;
bool bbox_enabled = true;
cv::LineTypes line_type = cv::LINE_4;
int contours_size = 1;
int bbox_size = 1;
// Filtering parameters
double min_object_area = 1000.0;
int min_object_dimension = 5;
int min_object_total_size = 25;
// Morphology parameters
int morphology_iterations = 10;
// Temporal consistency parameters
bool temporal_consistency_enabled = true;
double mask_overlap_threshold = 0.05; // 5% overlap with previous required
size_t temporal_history_size = 5; // Keep last N masks
size_t min_consistent_frames = 3; // Need N consecutive consistent frames
bool location_stability_enabled = true;
double max_location_jitter = 50.0; // Max pixel movement between frames
// Temporal consistency state
std::deque<cv::Mat> mask_history;
std::deque<cv::Point> centroid_history;
size_t consistent_frame_count = 0;
double last_temporal_consistency_score = 0.0;
// Statistics
CameraStats stats;
// Clear function to release memory
void clear()
{
for (auto& [index, frame] : control_frames)
{
frame.release();
}
control_frames.clear();
output.release();
mask.release();
contours.clear();
// Clear temporal history
for (auto& m : mask_history)
{
m.release();
}
mask_history.clear();
centroid_history.clear();
// Reset state
movement_detected = false;
transition_detected = false;
most_recent_psnr_score = 0.0;
frame_index_with_movement = 0;
thumbnail_size = cv::Size(0, 0);
consistent_frame_count = 0;
last_temporal_consistency_score = 0.0;
}
};
// Private member functions
double psnr(const cv::Mat& src, const cv::Mat& dst);
cv::Mat simple_colour_balance(const cv::Mat& src);
cv::Rect BoundingBoxFromContour(const std::vector<cv::Point>& contour);
// Multi-camera data storage
std::unordered_map<std::string, CameraData> cameras;
mutable std::recursive_mutex cameras_mutex;
// Helper functions
CameraData& getCameraData(const std::string& camera_id);
const CameraData* getCameraDataConst(const std::string& camera_id) const;
bool cameraExists(const std::string& camera_id) const;
// Processing helpers
cv::Mat computeMovementMask(const cv::Mat& control_frame, const cv::Mat& current_frame,
const cv::Size& output_size, int morphology_iterations);
std::vector<Object> extractObjectsFromMask(const cv::Mat& mask, const cv::Mat& image,
CameraData& camera, const std::string& camera_id);
void updateControlFrames(CameraData& camera, size_t frame_index, const cv::Mat& thumbnail);
void updateStatistics(CameraData& camera, double psnr, bool movement_detected,
std::chrono::milliseconds processing_time);
// Temporal consistency helpers
bool checkTemporalConsistency(CameraData& camera, const cv::Mat& current_mask);
double calculateMaskOverlap(const cv::Mat& mask1, const cv::Mat& mask2);
cv::Point calculateMaskCentroid(const cv::Mat& mask);
double calculateLocationStability(const std::deque<cv::Point>& centroids);
void updateTemporalHistory(CameraData& camera, const cv::Mat& mask);
std::vector<Object> MovementDetectInternal(const std::string& camera_id,
const size_t frame_index,
cv::Mat& image,
CameraData& camera);
};
class ANSENGINE_API ANSUtilityHelper {
public:
static std::vector<std::string> Split(const std::string& s, char delimiter);
static std::vector<cv::Point> StringToPolygon(const std::string& input);
static cv::Mat CropPolygon(const cv::Mat& image, const std::vector<cv::Point>& polygon);
static cv::Mat CropFromStringPolygon(const cv::Mat& image, const std::string& strPolygon);
static std::vector<cv::Rect> GetBoundingBoxesFromString(std::string strBBoxes);
static std::vector<ANSCENTER::Object> GetDetectionsFromString(const std::string& strDets);
static std::vector<float> StringToKeypoints(const std::string& str);
static std::vector<cv::Point2f> PolygonFromString(const std::string& str);
static ANSCENTER::Params ParseCustomParameters(const std::string& paramsJson);
static std::string SerializeCustomParamters(const ANSCENTER::Params& params);
static bool ParseActiveROIMode(const std::string activeROIMode,int & mode,double & detectionScore, std::vector<int> & trackingObjectIds);
static cv::Rect GetBoundingBoxFromPolygon(const std::vector<cv::Point>& polygon);
static std::string VectorDetectionToJsonString(const std::vector<Object>& dets);
static cv::Mat ReadImagePath(const std::string& imagePath);
static cv::Mat ReadImageStreamBase64(const std::string& imageStreamBase64);
static cv::Mat FormatToSquare(const cv::Mat& source);
static unsigned char* CVMatToBytes(cv::Mat image, unsigned int& bufferLengh);
static std::vector<std::string> GetConfigFileContent(std::string modelConfigFile, ModelType& modelType, std::vector<int>& inputShape);
static MetaData GetJson(const std::string& jsonPath);
static std::vector<unsigned char> DecodeBase64(const std::string& base64);
static cv::Mat Resize(const cv::Mat& src, int dst_height, int dst_width, const std::string& interpolation);
static cv::Mat Crop(const cv::Mat& src, int top, int left, int bottom, int right);
static cv::Mat Divide(const cv::Mat& src, float divide = 255.0);
static cv::Mat Normalize(cv::Mat& src, const std::vector<float>& mean, const std::vector<float>& std, bool to_rgb = false, bool inplace = true);
static cv::Mat Transpose(const cv::Mat& src);
static cv::Mat Pad(const cv::Mat& src, int top, int left, int bottom, int right, int border_type, float val);
static cv::Mat JpegStringToMat(const std::string& jpegString);
static cv::Mat MeanAxis0(const cv::Mat& src);
static cv::Mat ElementwiseMinus(const cv::Mat& A, const cv::Mat& B);
static cv::Mat VarAxis0(const cv::Mat& src);
static int MatrixRank(cv::Mat M);
static cv::Mat SimilarTransform(cv::Mat& dst, cv::Mat& src);
static std::vector<cv::Mat> AlignFaceWithFivePoints(const cv::Mat& image,
const std::vector<std::array<int, 4>> boxes,
std::vector<std::array<float, 2>> landmarks);
static std::vector<cv::Mat>GetCroppedFaces(const cv::Mat& image, const std::vector<std::array<int, 4>> boxes);
static cv::Mat GetCroppedFace(const cv::Mat& image, const int x1, const int y1, const int x2, const int y2);
static cv::Mat GetCroppedFaceScale(const cv::Mat& image, const int x1, const int y1, const int x2, const int y2, int cropedImageSize);
// For openVINO face alignment
static cv::Mat GetTransform(cv::Mat* src, cv::Mat* dst);
static void AlignFaces(std::vector<cv::Mat>* face_images, std::vector<cv::Mat>* landmarks_vec);
static void AlignFacesExt(std::vector<cv::Mat>* face_images, std::vector<cv::Mat>* landmarks_vec);
static std::pair<cv::Mat, cv::Mat> AlignFacesSCRFD(const cv::Mat& input_mat, const std::vector<cv::Point2f>& face_landmark_5);
// Model optimsation (for TensorRT)
static bool ModelOptimizer(std::string modelZipFilePath, std::string modelFileZipPassword, int fp16, std::string& optimisedModelFolder, int inputImageHeight=640, int inputImageWidth=640);
// For tiled inference
static std::vector<Object> ApplyNMS(const std::vector<Object>& detections, float nmsThreshold = 0.4);
static void AdjustBoudingBox(Object& obj, int offsetX, int offsetY);
static std::vector<cv::Rect> GetPatches(cv::Mat& image, int tileWidth, int tileHeight, double overlap);
static std::vector<cv::Mat> ExtractPatches(cv::Mat& image, std::vector<cv::Rect>& patchRegions);
static cv::Mat ResizePatch(cv::Mat& patch, int modelWidth, int modelHeight);
static std::map<int, std::vector<int>> Greedy_NMM(const std::vector<Object>& object_predictions, const std::string& match_metric = "IOU", float match_threshold = 0.5);
static float calculate_intersection_area(const cv::Rect& box1, const cv::Rect& box2);
static float calculate_bbox_iou(const Object& pred1, const Object& pred2);
static float calculate_bbox_ios(const Object& pred1, const Object& pred2);
static bool has_match(const Object& pred1, const Object& pred2, const std::string& match_type = "IOU", float match_threshold = 0.5);
static float get_merged_score(const Object& pred1, const Object& pred2);
static cv::Rect calculate_box_union(const cv::Rect& box1, const cv::Rect& box2);
static cv::Rect get_merged_bbox(const Object& pred1, const Object& pred2);
static int get_merged_class_id(const Object& pred1, const Object& pred2) {
return (pred1.confidence > pred2.confidence) ? pred1.classId : pred2.classId;
}
static std::string get_merged_category(const Object& pred1, const Object& pred2) {
return (pred1.confidence > pred2.confidence) ? pred1.className : pred2.className;
}
static Object merge_object_pair(const Object& obj1, const Object& obj2);
static std::vector<Object> select_object_predictions(const std::vector<Object>& object_prediction_list,const std::map<int, std::vector<int>>& keep_to_merge_list,const std::string& match_metric,float match_threshold);
static cv::Rect BoundingBoxFromContour(std::vector<cv::Point> contour);
static std::string PolygonToString(const std::vector<cv::Point2f>& polygon);
static std::string KeypointsToString(const std::vector<float>& kps);
static std::vector<cv::Point2f> RectToNormalizedPolygon(const cv::Rect& rect, float imageWidth, float imageHeight);
2026-03-31 14:10:21 +11:00
// Convert a UTF-8 encoded string to UTF-16LE byte string.
// Useful for LabVIEW which can display UTF-16LE Unicode text on Windows.
// Returns a std::string containing the raw UTF-16LE bytes (2 bytes per character).
static std::string ConvertUTF8ToUTF16LE(const std::string& utf8Str);
// Decode JSON Unicode escape sequences (\uXXXX) to UTF-16LE byte string.
// Input: ASCII string with \uXXXX escapes (e.g., "\\u6c5f\\u6771 599")
// Output: UTF-16LE byte string for LabVIEW display.
// ASCII characters pass through as 2-byte UTF-16LE (e.g., 'A' -> 0x41 0x00).
static std::string DecodeJsonUnicodeToUTF16LE(const std::string& escapedStr);
2026-03-28 16:54:11 +11:00
static std::vector<cv::Point2f> MaskToNormalizedPolygon(const cv::Mat& binaryMask, const cv::Rect& boundingBox, float imageWidth, float imageHeight, float simplificationEpsilon = 2.0f, int minContourArea = 10, int maxPoints = 50);
};
class ANSENGINE_API ANSFRBase {
protected:
bool _licenseValid{ false };
bool _isInitialized{ false };
std::string _licenseKey;
std::string _modelFolder;
std::string _modelConfigFile;
SPDLogger& _logger = SPDLogger::GetInstance("ANSFR", false);
void CheckLicense();
public:
virtual bool Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap);
virtual bool LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword);
virtual bool OptimizeModel(bool fp16, std::string& optimizedModelFolder);
virtual std::vector<FaceResultObject> Match(const cv::Mat& input, const std::vector<ANSCENTER::Object>& bBox, const std::map<std::string, std::string>& userDict) = 0; //
virtual std::vector<float> Feature(const cv::Mat& image, const ANSCENTER::Object& bBox) = 0; // Run inference and get embedding information from a cropped image (the first bbox)
virtual cv::Mat GetCropFace(const cv::Mat& input, const ANSCENTER::Object& bBox) = 0;
std::string GetModelFolder() { return _modelFolder; };
virtual bool UpdateParamater(double knownPersonThreshold)=0;
// For face
virtual void Init()=0;
virtual void AddEmbedding(const std::string& className, float embedding[])=0;
virtual void AddEmbedding(const std::string& className, const std::vector<float>& embedding) =0;
virtual bool Destroy()=0;
virtual void SetMaxSlotsPerGpu(int n) {} // override in TRT-based subclasses
~ANSFRBase();
// Utility functions
std::vector<float> L2Normalize(const std::vector<float>& values);
float CosineSimilarity(const std::vector<float>& a, const std::vector<float>& b, bool normalized);
};
class ANSENGINE_API ANSODBase {
protected:
bool _licenseValid{ false };
bool _isInitialized{ false };
Params _params;
std::string _licenseKey;
std::string _modelFolder;
std::string _modelConfigFile;
ModelConfig _modelConfig;
SPDLogger& _logger = SPDLogger::GetInstance("ANSOD", false);
// Debug benchmarking flag — when enabled, logs per-stage timing
// for the full inference pipeline (preprocess, inference, postprocess, tracking, etc.)
bool _debugFlag{ false };
std::string _classFilePath;
std::vector <std::string> _classes;
bool _loadEngineOnCreation{ true };
bool _skipEngineCache{ false };
bool _forceNoPool{ false };
void CheckLicense();
void LoadClassesFromString();
void LoadClassesFromFile();
std::recursive_mutex _mutex;
MoveDetectsHandler _handler;
size_t QUEUE_SIZE = 20;
// Multi-object tracker (MOT) — per-camera instances lazy-created in ApplyTracking
bool _trackerEnabled = false;
TrackerType _trackerType = TrackerType::BYTETRACK;
int _trackerMotType = 1; // ANSMOT motType int
std::string _trackerParams; // JSON params applied to each per-camera tracker
// Detection stabilization config
bool _stabilizationEnabled = false;
size_t _stabilizationQueueSize = 20; // history depth (frames)
int _stabilizationMaxConsecutiveMisses = 5; // stop interpolating after N misses
float _stabilizationConfidenceDecay = 0.85f; // per-miss confidence multiplier
float _stabilizationMinConfidence = 0.15f; // floor below which ghosts are dropped
// #1 Confidence hysteresis: two-threshold system
float _hysteresisEnterThreshold = 0.0f; // 0 = auto (use detectionScoreThreshold)
float _hysteresisKeepThreshold = 0.0f; // 0 = auto (enterThreshold * 0.65)
// #2 Temporal confidence smoothing (EMA)
float _emaAlpha = 0.3f; // EMA weight for new observation (0..1)
// #5 Track-aware confidence boost for established tracks
int _trackBoostMinFrames = 10; // frames before boost kicks in
float _trackBoostAmount = 0.05f; // confidence bonus for established tracks
// #7 Class consistency — prevent sudden class switches on established tracks
int _classConsistencyMinFrames = 5; // consecutive frames of new class required to accept switch
// Adaptive screens
struct ImageSection {
cv::Rect region;
int priority;
ImageSection(const cv::Rect& r) : region(r), priority(0) {}
};
cv::Size previousImageSize = cv::Size(0, 0);
// For active windows
std::vector<ImageSection> cachedSections;
int _currentPriority{ 0 }; // None
cv::Rect _detectedArea;// This is active windows.
int _retainDetectedArea{ 0 };
bool _isObjectDetected{ false };
struct CameraData
{
std::deque<std::vector<Object>> _detectionQueue; // That stores the detection results
// Per-camera tracker instance (lazy-created in ApplyTracking)
ANSCENTER::ANSMOT* _tracker = nullptr;
// ── Stabilization state ──────────────────────────────
struct TrackedObjectHistory {
int classId = 0;
std::string className;
std::string extraInfo; // preserve last-known extraInfo for ghost objects
cv::Rect lastBox;
float lastConfidence = 0.f;
float smoothedConfidence = 0.f; // EMA-smoothed confidence
int consecutiveMisses = 0; // frames since last raw detection
int totalDetections = 0; // lifetime detection count
int frameFirstSeen = 0; // frame counter when first detected
bool isEstablished = false; // true once totalDetections >= trackBoostMinFrames
// #7 Class consistency — resist sudden class switches
int pendingClassId = -1; // candidate new class (-1 = none)
std::string pendingClassName;
int pendingClassStreak = 0; // consecutive frames with pendingClass
};
std::unordered_map<int, TrackedObjectHistory> _trackHistories; // trackId -> history
int _stabilizationFrameCounter = 0;
void clear()
{
if (_tracker) {
ReleaseANSMOTHandle(&_tracker);
_tracker = nullptr;
}
for (auto& detectionVector : _detectionQueue)
{
detectionVector.clear(); // Clear each vector of Objects
}
_detectionQueue.clear(); // Clear the deque itself
_trackHistories.clear();
_stabilizationFrameCounter = 0;
}
};
// Multi-camera data storage
std::unordered_map<std::string, CameraData> _cameras;
CameraData _defaultCamera; // Default camera data if camera_id is not provided
// Tracker: convert detections → TrackerObject, run tracker, assign trackIds via IoU match
std::vector<Object> ApplyTracking(std::vector<Object>& detections, const std::string& camera_id);
// Stabilize detections: fill gaps with tracker-predicted objects, apply confidence decay
std::vector<Object> StabilizeDetections(std::vector<Object>& detections, const std::string& camera_id);
// extraInfo stabilization tag helpers
static void TagStabilized(std::string& extraInfo);
static void UntagStabilized(std::string& extraInfo);
static bool IsTaggedStabilized(const std::string& extraInfo);
// Other functions can be used;
bool isSimilarObject(const Object& obj1, const Object& obj2);
bool isOverlayObject(const Object& obj1, const Object& obj2);
// Helper: returns the Euclidean distance between two points.
float distance(const cv::Point2f& a, const cv::Point2f& b) {
float dx = a.x - b.x;
float dy = a.y - b.y;
return std::sqrt(dx * dx + dy * dy);
}
// Compute the union (bounding box) of two rectangles.
cv::Rect unionRect(const cv::Rect& a, const cv::Rect& b) {
int x = std::min(a.x, b.x);
int y = std::min(a.y, b.y);
int x2 = std::max(a.x + a.width, b.x + b.width);
int y2 = std::max(a.y + a.height, b.y + b.height);
return cv::Rect(x, y, x2 - x, y2 - y);
}
cv::Rect computeCandidateROI(const cv::Rect& unionBox, int fixedWidth, int fixedHeight, int imageWidth, int imageHeight);
// Check if two rectangles overlap (i.e. intersection area > 0).
bool isOverlap(const cv::Rect& a, const cv::Rect& b) {
return ((a & b).area() > 0);
}
std::string GetOpenVINODevice(ov::Core &core);
// Function to seperate screen size
double calculateDistanceToCenter(const cv::Point& center, const cv::Rect& rect);
std::vector<ImageSection> divideImage(const cv::Mat& image);
std::vector<ImageSection> createSlideScreens(const cv::Mat& image);
int getHighestPriorityRegion();
int getLowestPriorityRegion();
cv::Rect getRegionByPriority(int priority);
std::vector<Object> AdjustDetectedBoundingBoxes(const std::vector<Object>& detectionsInROI,
const cv::Rect& roi, const cv::Size& fullImageSize,
float aspectRatio = 0.9f, // width at least 2x height
int padding = 10 // base padding
);
void UpdateNoDetectionCondition();
void UpdateActiveROI(const cv::Mat& frame, ANSCENTER::Object detectedObj);
bool IsValidObject(const Object& obj, std::vector<int> objectIds);
public:
[[nodiscard]] virtual bool Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap);
[[nodiscard]] virtual bool LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword);
[[nodiscard]] virtual bool LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName, std::string className, const std::string& modelFolder, std::string& labelMap);
[[nodiscard]] virtual bool OptimizeModel(bool fp16, std::string& optimizedModelFolder);
[[nodiscard]] virtual std::vector<Object> RunInference(const cv::Mat& input) = 0;
[[nodiscard]] virtual std::vector<Object> RunInference(const cv::Mat& input, const std::string& camera_id) = 0;
[[nodiscard]] virtual std::vector<std::vector<Object>> RunInferencesBatch(const std::vector<cv::Mat>& inputs, const std::string& camera_id);
[[nodiscard]] std::vector<Object> RunInference(const cv::Mat& input, std::vector<cv::Rect> Bbox, const std::string& camera_id);
[[nodiscard]] std::vector<Object> RunInference(const cv::Mat& input, std::vector<cv::Point> Polygon, const std::string& camera_id);
[[nodiscard]] std::vector<Object> RunInferences(const cv::Mat& input, int tiledWidth, int tiledHeight, double overLap, const std::string& camera_id); // split image to slides and run inference
[[nodiscard]] std::vector<Object> RunInferenceFromJpegString(const char* jpegData, unsigned long jpegSize, const std::string& camera_id) ;
[[nodiscard]] std::vector<Object> RunTiledInferenceFromJpegString(const char* jpegData, unsigned long jpegSize, int tiledWith, int tiledHeight, double overLap, const std::string& camera_id);
[[nodiscard]] std::vector<Object> DetectMovement(const cv::Mat& input, const std::string& camera_id);
[[nodiscard]] std::vector<cv::Rect> GenerateFixedROIs(const std::vector<Object>& movementObjects, int fixedWidth, int fixedHeight, int imageWidth, int imageHeight);
[[nodiscard]] cv::Rect GenerateMinimumSquareBoundingBox(const std::vector<ANSCENTER::Object>& detectedObjects, int minSize = 640);
void UpdateAndFilterDetectionObjects(std::vector<Object>& detectionObjects, int threshold);
[[nodiscard]] bool ContainsIntersectingObject(const std::vector<Object>& movementObjects, const Object& result);
[[nodiscard]] cv::Rect GetActiveWindow(const cv::Mat& input);
[[nodiscard]] Params GetParameters() { return _params; } //
[[nodiscard]] virtual bool ConfigureParameters(Params& param); //
[[nodiscard]] virtual bool SetParameters(const Params& param); //ANSVIS will set the parameters
[[nodiscard]] bool UpdateDetectionThreshold(float detectionScore);
[[nodiscard]] std::vector<Object> RunInferenceWithOption(const cv::Mat& input, const std::string& camera_id, const std::string activeROIMode);// Get detected objects
// New API to suppor dynamic inference
[[nodiscard]] std::vector<Object> RunDynamicInference(const cv::Mat& input, cv::Rect Bbox, const std::string& camera_id);
[[nodiscard]] std::vector<Object> RunStaticInference(const cv::Mat& input, cv::Rect Bbox, const std::string& camera_id);
void SetLoadEngineOnCreation(bool loadEngineOnCreation) { _loadEngineOnCreation = loadEngineOnCreation; }
virtual void SetMaxSlotsPerGpu(int n) {} // override in TRT-based subclasses
void SetSkipEngineCache(bool skip) { _skipEngineCache = skip; } // propagated to Engine<T> before buildLoadNetwork
void SetForceNoPool(bool force) { _forceNoPool = force; } // propagated to Engine<T> before buildLoadNetwork
/// Enable/disable internal debug benchmarking.
/// When enabled, per-stage timing (preprocess, inference, postprocess, tracking, etc.)
/// is logged via _logger at info level for every inference call.
void ActivateDebugger(bool debugFlag) { _debugFlag = debugFlag; }
// Multi-object tracker (MOT) control
bool SetTracker(TrackerType trackerType, bool enabled);
// Detection stabilization control
// Auto-enables tracker if not already enabled. Tracker auto-enables stabilization too.
bool SetStabilization(bool enabled, int historySize = 20, int maxMisses = 5);
// Fine-tune all stabilization parameters at once (JSON input).
// Keys (all optional — omit to keep current value):
// "hysteresis_enter" : float — confidence to start tracking (0=auto from model threshold)
// "hysteresis_keep" : float — confidence to keep tracking (0=auto, 65% of enter)
// "ema_alpha" : float — EMA weight for new observation (0..1, default 0.3)
// "track_boost_min_frames" : int — frames before boost kicks in (default 10)
// "track_boost_amount" : float — confidence bonus for established tracks (default 0.05)
// "class_consistency_frames": int — consecutive frames of new class to accept switch (default 5)
// "confidence_decay" : float — per-miss decay multiplier for ghosts (default 0.85)
// "min_confidence" : float — floor below which ghosts are dropped (default 0.15)
bool SetStabilizationParameters(const std::string& jsonParams);
bool SetTrackerParameters(const std::string& jsonParams);
/// Set the text prompt for segmentation (pre-tokenized).
/// Override in subclasses that support text-prompted segmentation (e.g. ANSSAM3, ANSONNXSAM3).
virtual bool SetPrompt(const std::vector<int64_t>& inputIds,
const std::vector<int64_t>& attentionMask) {
return true;
}
/// Set the text prompt by tokenizing the given text.
/// Requires merges.txt (CLIP BPE vocabulary) in the model folder.
/// Override in subclasses that support text-prompted segmentation.
virtual bool SetPrompt(const std::string& text) { return true; }
std::vector<Object> _detectedObjects;
[[nodiscard]] ModelConfig GetModelConfig();
// Function to add or retrieve camera data by ID
CameraData& GetCameraData(const std::string& cameraId) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try
{
if (_cameras.empty())
{
std::cerr << "Warning: _cameras is initially empty." << std::endl;
}
// Use try_emplace to insert a default CameraData if cameraId does not exist
auto [iterator, inserted] = _cameras.try_emplace(cameraId, CameraData{});
if (inserted)
{
std::cout << "Added new CameraData for cameraId: " << cameraId << std::endl;
}
return iterator->second; // Return the reference to CameraData
}
catch (const std::exception& ex)
{
std::cerr << "Exception in GetCameraData: " << ex.what() << std::endl;
return _defaultCamera;
}
}
void EnqueueDetection(const std::vector<Object>& detectedObjects, const std::string& cameraId);
[[nodiscard]] bool RunInference(const cv::Mat& input, const std::string& camera_id, std::string& detectionResult);
[[nodiscard]] std::deque<std::vector<Object>> DequeueDetection(const std::string& cameraId);
[[nodiscard]] virtual bool Destroy()=0;
~ANSODBase();
protected:
std::vector<Object> RunInferenceInScanningMode(const cv::Mat& input, const std::string& camera_id);// Get detected objects
std::vector<Object> RunInferenceInTrackingMode(const cv::Mat& input, const std::string& camera_id, std::vector<int> trackingObjectIds);// Get detected objects
};
class ANSENGINE_API ANSFDBase {
protected:
bool _licenseValid{ false };
bool _isInitialized{ false };
std::string _licenseKey;
std::string _modelFolder;
std::string _faceAttrModelFolder;
ModelConfig _modelConfig;
std::string _modelConfigFile;
std::string _imageProcessingModelFile;
MoveDetectsHandler _handler;
const size_t QUEUE_SIZE = 10;
std::recursive_mutex _mutex;
ANSCENTER::EngineType engineType;
bool _facelivenessEngineValid{ false };
Ort::Env* _ortLivenessEnv = nullptr;
Ort::SessionOptions* _ortLivenessSessionOptions = nullptr;
Ort::Session* _livenessSession = nullptr;
std::string _livenessInputName;
std::string _livenessOutputName;
ANSCENTER::ANSMOT* _faceTracker = nullptr;
#ifdef USE_TV_MODEL
ANSCENTER::ANSMOT* _tvTracker = nullptr;
std::unique_ptr<ANSODBase>_tvDetector = nullptr;
std::vector<Object> TrackTVScreens(const std::vector<Object>& tvObjects);
bool InsideScreen(const cv::Rect& tvBox, const cv::Rect& faceBox);
#endif
bool _useTvDetector{ false };
std::unordered_map<int, int> _mMissingTrackFrames; // Track ID and number of missing face
std::unordered_map<int, int> _mMissingTrackScreen; // Track ID and number of missing screen
std::unordered_map<int, std::deque<int>> _mTrackHistory; //History of liveness attribute
std::unordered_map<int, std::vector<Object>> _mTrackScreen; //History of Screen's position
// Adaptive screens
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
//AsyncPipeline* _pipeline = nullptr;
SPDLogger& _logger = SPDLogger::GetInstance("ANSFD", false);
EngineType _engineType;
void CheckLicense();
void Cleanup();
// Other functions can be used;
bool isSimilarObject(const Object& obj1, const Object& obj2);
bool isOverlayObject(const Object& obj1, const Object& obj2);
struct CameraData
{
std::deque<std::vector<Object>> _detectionQueue; // That stores the detection results
void clear()
{
for (auto& detectionVector : _detectionQueue)
{
detectionVector.clear(); // Clear each vector of Objects
}
_detectionQueue.clear(); // Clear the deque itself
}
};
CameraData _defaultCamera;
// Helper: returns the Euclidean distance between two points.
float distance(const cv::Point2f& a, const cv::Point2f& b) {
float dx = a.x - b.x;
float dy = a.y - b.y;
return std::sqrt(dx * dx + dy * dy);
}
// Compute the union (bounding box) of two rectangles.
cv::Rect unionRect(const cv::Rect& a, const cv::Rect& b) {
int x = std::min(a.x, b.x);
int y = std::min(a.y, b.y);
int x2 = std::max(a.x + a.width, b.x + b.width);
int y2 = std::max(a.y + a.height, b.y + b.height);
return cv::Rect(x, y, x2 - x, y2 - y);
}
cv::Rect computeCandidateROI(const cv::Rect& unionBox, int fixedWidth, int fixedHeight, int imageWidth, int imageHeight);
// Check if two rectangles overlap (i.e. intersection area > 0).
bool isOverlap(const cv::Rect& a, const cv::Rect& b) {
return ((a & b).area() > 0);
}
bool isValidFace(const std::vector<cv::Point2f>& landmarks, const cv::Rect& faceRect, float maxEyeAngle = 25, int offsetX = 0, int offsetY = 0, const cv::Mat& frame = cv::Mat(), float minBlurScore = 15.0f);
// Multi-camera data storage
std::unordered_map<std::string, CameraData> _cameras;
//cv::Mat EnhanceImage(const cv::Mat inputImage, int cropedImageSize);
cv::Mat GetCroppedFaceScale(const cv::Mat& image, const int x1, const int y1, const int x2, const int y2, int cropedImageSize);
std::string GetOpenVINODevice(ov::Core& core);
cv::Mat Preprocess(cv::Mat& input_mat, std::vector<cv::Point2f>& face_landmark_5, cv::Mat& preprocessed_mat);
// Function to seperate screen size
double calculateDistanceToCenter(const cv::Point& center, const cv::Rect& rect);
std::vector<ImageSection> divideImage(const cv::Mat& image);
std::vector<ANSFDBase::ImageSection> createSlideScreens(const cv::Mat& image);
int getHighestPriorityRegion();
int getLowestPriorityRegion();
cv::Rect getRegionByPriority(int priority);
std::vector<Object> AdjustDetectedBoundingBoxes(const std::vector<Object>& detectionsInROI,
const cv::Rect& roi, const cv::Size& fullImageSize,
float aspectRatio = 0.9f, // width at least 2x height
int padding = 10 // base padding
);
// Track faces
std::vector<Object> TrackFaces(const cv::Mat& inputImage, const std::vector<Object>& faceObjects);
template<typename MapTrackData, typename MapMissingFrames>
void CleanUpTracks(std::vector<Object>& currentObjects,
MapTrackData& trackDataMap,
MapMissingFrames& missingFramesMap,
int maxMissing,
int maxTracks);
public:
[[nodiscard]] virtual bool Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap);
[[nodiscard]] virtual bool LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword);
[[nodiscard]] virtual bool LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName, std::string className, const std::string& modelFolder, std::string& labelMap);
[[nodiscard]] virtual bool OptimizeModel(bool fp16, std::string& optimizedModelFolder);
[[nodiscard]] virtual std::vector<ANSCENTER::Object> RunInference(const cv::Mat& input, bool useDynamicImage = true, bool validateFace = false, bool facelivenessCheck = true) = 0;
[[nodiscard]] virtual std::vector<Object> RunInference(const cv::Mat& input, const std::string& camera_id, bool useDynamicImage = true, bool validateFace = false, bool facelivenessCheck = true) = 0;
[[nodiscard]] virtual bool Destroy() = 0;
[[nodiscard]] std::vector<Object> DetectMovement(const cv::Mat& input, const std::string& camera_id);
[[nodiscard]] cv::Rect GenerateMinimumSquareBoundingBox(const std::vector<ANSCENTER::Object>& detectedObjects, int minSize = 640);
[[nodiscard]] std::vector<cv::Rect> GenerateFixedROIs(const std::vector<Object>& movementObjects, int fixedWidth, int fixedHeight, int imageWidth, int imageHeight);
[[nodiscard]] bool ContainsIntersectingObject(const std::vector<Object>& movementObjects, const Object& result);
void UpdateAndFilterDetectionObjects(std::vector<Object>& detectionObjects, int threshold);
[[nodiscard]] bool UpdateDetectionThreshold(float detectionScore);
[[nodiscard]] float GetDetectionThreshold();
[[nodiscard]] ModelConfig GetModelConfig();
// Function to add or retrieve camera data by ID
CameraData& GetCameraData(const std::string& cameraId)
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
try
{
if (_cameras.empty())
{
std::cerr << "Warning: _cameras is initially empty." << std::endl;
}
// Use try_emplace to insert a default CameraData if cameraId does not exist
auto [iterator, inserted] = _cameras.try_emplace(cameraId, CameraData{});
if (inserted)
{
std::cout << "Added new CameraData for cameraId: " << cameraId << std::endl;
}
return iterator->second; // Return the reference to CameraData
}
catch (const std::exception& ex)
{
std::cerr << "Exception in GetCameraData: " << ex.what() << std::endl;
return _defaultCamera;
}
}
void EnqueueDetection(const std::vector<Object>& detectedObjects, const std::string& cameraId);
std::deque<std::vector<Object>> DequeueDetection(const std::string& cameraId);
// Face liveness functions
bool LoadLivenessModel(std::string antiSpoofModelPath, bool isGPU = true);
bool InitializeLivenessModel(std::string licenseKey, const std::string& modelZipFilePath, const std::string& modelZipPassword);
std::pair<int, float> PredictLiveness(const cv::Mat& faceImage);
std::pair<int, float> LivenessPostProcessing(const float* pOutput);
std::vector<Object> ValidateLivenessFaces(const cv::Mat& inputImage, const std::vector<Object>& faceObjects, const std::string& camera_id);
float ComputeIoU(const cv::Rect& a, const cv::Rect& b);
virtual void SetMaxSlotsPerGpu(int n) {} // override in TRT-based subclasses
~ANSFDBase();
};
}
2026-03-31 14:10:21 +11:00
// Unicode conversion utilities for LabVIEW wrapper classes
extern "C" ANSENGINE_API int ANSEngine_ConvertUTF8ToUTF16LE(const char* utf8Str, LStrHandle result);
extern "C" ANSENGINE_API int ANSEngine_ConvertUTF16LEToUTF8(const unsigned char* utf16leBytes, int byteLen, LStrHandle result);
2026-03-28 16:54:11 +11:00
#endif