Files
ANSCORE/modules/ANSODEngine/ANSMotionDetector.h

248 lines
12 KiB
C++

#ifndef ANSMOTIONDETECTOR_H
#define ANSMOTIONDETECTOR_H
#pragma once
#include "ANSEngineCommon.h"
#include <string>
#include <opencv2/opencv.hpp>
#include <openvino/openvino.hpp>
#include <array>
namespace ANSCENTER
{
class ANSENGINE_API ANSMOTIONDETECTOR : public ANSODBase
{
protected:
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 };
}
};
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 = 15.0;
double min_change_percentage = 0.5;
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 = 5; // CHANGED: Reduce from 10 to 5
double psnr_threshold = 35;
double thumbnail_ratio = 0.1;
cv::Size thumbnail_size = cv::Size(0, 0);
// NEW: Maximum age of control frames to compare (in frames)
size_t max_control_frame_age = 20; // Only compare frames within last 100 frames (~5 seconds at 20fps)
// NEW: Sensitivity multiplier (1.0 = normal, 1.2 = more sensitive, 0.8 = less sensitive)
double sensitivity_multiplier = 1.1;
// Mask computation parameters
int mask_diff_threshold = 10; // Fixed threshold for difference detection
double mask_min_percentage = 0.01; // Min % of frame to be valid movement
double mask_max_percentage = 40.0; // Max % of frame (reject as scene change)
double min_mask_pixels_percentage = 0.05; // 0.02% of working image
// Filtering parameters
double min_object_area = 1000;
int min_object_dimension = 5;
int min_object_total_size = 25;
// Morphology parameters
int morphology_iterations = 2;
// Temporal consistency parameters
bool temporal_consistency_enabled = true;
double mask_overlap_threshold = 0.1;
size_t temporal_history_size = 5;
size_t min_consistent_frames = 3;
bool location_stability_enabled = true;
double max_location_jitter = 30.0;
// 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);
void setDynamicPSNRThreshold(CameraData& camera, const cv::Mat& working_image);
// 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, const CameraData& camera);
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,const cv::Mat& image,CameraData& camera);
// Main detection methods
std::vector<Object> MovementDetect(const std::string& camera_id, const cv::Mat& next_image);
std::vector<Object> MovementDetect(const std::string& camera_id, const size_t frame_index, const 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;*/
const cv::Mat& getOutput(const std::string& camera_id) const;
const cv::Mat getMask(const std::string& camera_id) const;
std::vector<std::vector<cv::Point>> getContours(const std::string& camera_id) const;
CameraStats getStats(const std::string& camera_id) const;
void resetStats(const std::string& camera_id);
protected:
std::string _modelFilePath;
public:
virtual bool Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap) override;
virtual bool LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) override;
virtual bool LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName, std::string className, const std::string& modelFolder, std::string& labelMap)override;
virtual bool OptimizeModel(bool fp16, std::string& optimizedModelFolder);
std::vector<Object> RunInference(const cv::Mat& input);
std::vector<Object> RunInference(const cv::Mat& input, const std::string& camera_id);
bool Destroy();
~ANSMOTIONDETECTOR();
};
}
#endif