#ifndef ANSMOTIONDETECTOR_H #define ANSMOTIONDETECTOR_H #pragma once #include "ANSEngineCommon.h" #include #include #include #include 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::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::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 control_frames; // Output data cv::Mat output; cv::Mat mask; std::vector> 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 mask_history; std::deque 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& contour); void setDynamicPSNRThreshold(CameraData& camera, const cv::Mat& working_image); // Multi-camera data storage std::unordered_map 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 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& centroids); void updateTemporalHistory(CameraData& camera, const cv::Mat& mask); std::vector MovementDetectInternal(const std::string& camera_id,const size_t frame_index,const cv::Mat& image,CameraData& camera); // Main detection methods std::vector MovementDetect(const std::string& camera_id, const cv::Mat& next_image); std::vector 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 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> 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 RunInference(const cv::Mat& input); std::vector RunInference(const cv::Mat& input, const std::string& camera_id); bool Destroy(); ~ANSMOTIONDETECTOR(); }; } #endif