248 lines
12 KiB
C
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
|