matrice-analytics 0.1.43__tar.gz → 0.1.45__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of matrice-analytics might be problematic. Click here for more details.
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/PKG-INFO +1 -1
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/matrice_analytics.egg-info/PKG-INFO +1 -1
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/matrice_analytics.egg-info/SOURCES.txt +1 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/config.py +1 -1
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/face_reg/face_recognition.py +145 -99
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/face_reg/face_recognition_client.py +24 -19
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/face_reg/people_activity_logging.py +6 -4
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/easyocr_extractor.py +3 -1
- matrice_analytics-0.1.45/src/matrice_analytics/post_processing/test_cases/test_usecases.py +165 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color/clip.py +4 -3
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color/color_mapper.py +1 -1
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color_detection.py +89 -54
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/fire_detection.py +89 -55
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/license_plate_monitoring.py +81 -46
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/people_counting.py +29 -28
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/vehicle_monitoring.py +89 -54
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/LICENSE.txt +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/README.md +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/matrice_analytics.egg-info/dependency_links.txt +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/matrice_analytics.egg-info/not-zip-safe +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/matrice_analytics.egg-info/top_level.txt +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/pyproject.toml +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/setup.cfg +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/setup.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/boundary_drawing_internal/README.md +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/boundary_drawing_internal/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/boundary_drawing_internal/boundary_drawing_internal.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/boundary_drawing_internal/boundary_drawing_tool.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/boundary_drawing_internal/boundary_tool_template.html +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/boundary_drawing_internal/example_usage.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/boundary_drawing_internal/usage/README.md +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/boundary_drawing_internal/usage/boundary_drawer_launcher.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/boundary_drawing_internal/usage/simple_boundary_launcher.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/README.md +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/advanced_tracker/README.md +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/advanced_tracker/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/advanced_tracker/base.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/advanced_tracker/config.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/advanced_tracker/kalman_filter.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/advanced_tracker/matching.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/advanced_tracker/strack.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/advanced_tracker/tracker.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/core/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/core/base.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/core/config.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/core/config_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/face_reg/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/face_reg/compare_similarity.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/face_reg/embedding_manager.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/cli.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/dataset_stats.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/export.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/train.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/valid.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/validate_dataset.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/visualize_augmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/visualize_predictions.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/core/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/core/process.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/core/types.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/core/utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/inference/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/inference/config.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/inference/hub.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/inference/plate_recognizer.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/py.typed +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/data/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/data/augmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/data/dataset.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/config.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/layers.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/loss.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/metric.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/model_builders.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/model_schema.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/utilities/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/utilities/backend_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/utilities/utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/postprocessing.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/ocr/preprocessing.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/post_processor.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/run_tests.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_advanced_customer_service.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_basic_counting_tracking.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_comprehensive.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_config.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_customer_service.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_data_generators.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_people_counting.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_processor.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_utilities.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/test_cases/test_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/Histopathological_Cancer_Detection_img.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/abandoned_object_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/advanced_customer_service.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/age_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/age_gender_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/anti_spoofing_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/assembly_line_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/banana_defect_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/basic_counting_tracking.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/blood_cancer_detection_img.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/car_damage_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/car_part_segmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/car_service.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/cardiomegaly_classification.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/cell_microscopy_segmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/chicken_pose_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/child_monitoring.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color/clip_processor/merges.txt +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color/clip_processor/preprocessor_config.json +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color/clip_processor/special_tokens_map.json +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color/clip_processor/tokenizer.json +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color/clip_processor/tokenizer_config.json +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color/clip_processor/vocab.json +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color/color_map_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/color_map_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/concrete_crack_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/crop_weed_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/customer_service.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/defect_detection_products.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/distracted_driver_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/drone_traffic_monitoring.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/drowsy_driver_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/dwell_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/emergency_vehicle_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/face_emotion.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/face_recognition.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/fashion_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/field_mapping.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/flare_analysis.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/flower_segmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/gas_leak_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/gender_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/human_activity_recognition.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/intrusion_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/leaf.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/leaf_disease.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/leak_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/license_plate_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/litter_monitoring.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/mask_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/natural_disaster.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/parking.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/parking_space_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/pcb_defect_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/pedestrian_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/people_counting_bckp.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/people_tracking.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/pipeline_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/plaque_segmentation_img.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/pothole_segmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/ppe_compliance.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/price_tag_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/proximity_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/road_lane_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/road_traffic_density.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/road_view_segmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/shelf_inventory_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/shoplifting_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/shopping_cart_analysis.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/skin_cancer_classification_img.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/smoker_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/solar_panel.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/suspicious_activity_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/template_usecase.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/theft_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/traffic_sign_monitoring.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/underground_pipeline_defect_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/underwater_pollution_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/warehouse_object_segmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/waterbody_segmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/weapon_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/weld_defect_detection.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/wildlife_monitoring.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/windmill_maintenance.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/usecases/wound_segmentation.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/__init__.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/advanced_counting_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/advanced_helper_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/advanced_tracking_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/alerting_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/category_mapping_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/color_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/counting_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/filter_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/format_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/geometry_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/smoothing_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/post_processing/utils/tracking_utils.py +0 -0
- {matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/src/matrice_analytics/py.typed +0 -0
{matrice_analytics-0.1.43 → matrice_analytics-0.1.45}/matrice_analytics.egg-info/SOURCES.txt
RENAMED
|
@@ -88,6 +88,7 @@ src/matrice_analytics/post_processing/test_cases/test_customer_service.py
|
|
|
88
88
|
src/matrice_analytics/post_processing/test_cases/test_data_generators.py
|
|
89
89
|
src/matrice_analytics/post_processing/test_cases/test_people_counting.py
|
|
90
90
|
src/matrice_analytics/post_processing/test_cases/test_processor.py
|
|
91
|
+
src/matrice_analytics/post_processing/test_cases/test_usecases.py
|
|
91
92
|
src/matrice_analytics/post_processing/test_cases/test_utilities.py
|
|
92
93
|
src/matrice_analytics/post_processing/test_cases/test_utils.py
|
|
93
94
|
src/matrice_analytics/post_processing/usecases/Histopathological_Cancer_Detection_img.py
|
|
@@ -143,4 +143,4 @@ def get_usecase_from_app_name(app_name: str) -> str:
|
|
|
143
143
|
|
|
144
144
|
def get_category_from_app_name(app_name: str) -> str:
|
|
145
145
|
normalized_app_name = app_name.lower().replace(" ", "_").replace("-", "_")
|
|
146
|
-
return APP_NAME_TO_CATEGORY.get(app_name, APP_NAME_TO_CATEGORY.get(normalized_app_name))
|
|
146
|
+
return APP_NAME_TO_CATEGORY.get(app_name, APP_NAME_TO_CATEGORY.get(normalized_app_name))
|
|
@@ -24,7 +24,7 @@ subprocess.run(
|
|
|
24
24
|
cmd,
|
|
25
25
|
stdout=log_file,
|
|
26
26
|
stderr=subprocess.STDOUT,
|
|
27
|
-
preexec_fn=os.setpgrp
|
|
27
|
+
# preexec_fn=os.setpgrp
|
|
28
28
|
)
|
|
29
29
|
log_file.close()
|
|
30
30
|
|
|
@@ -81,13 +81,13 @@ class TemporalIdentityManager:
|
|
|
81
81
|
"""
|
|
82
82
|
Maintains stable identity labels per tracker ID using temporal smoothing and embedding history.
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
via search_similar_faces(embedding, threshold=0.01, limit=1) to obtain top-1 match and score.
|
|
84
|
+
Uses local embedding similarity search via EmbeddingManager instead of API calls.
|
|
86
85
|
"""
|
|
87
86
|
|
|
88
87
|
def __init__(
|
|
89
88
|
self,
|
|
90
89
|
face_client: FacialRecognitionClient,
|
|
90
|
+
embedding_manager: Optional[Any] = None, # EmbeddingManager instance
|
|
91
91
|
recognition_threshold: float = 0.35,
|
|
92
92
|
history_size: int = 20,
|
|
93
93
|
unknown_patience: int = 7,
|
|
@@ -96,6 +96,7 @@ class TemporalIdentityManager:
|
|
|
96
96
|
) -> None:
|
|
97
97
|
self.logger = logging.getLogger(__name__)
|
|
98
98
|
self.face_client = face_client
|
|
99
|
+
self.embedding_manager = embedding_manager
|
|
99
100
|
self.threshold = float(recognition_threshold)
|
|
100
101
|
self.history_size = int(history_size)
|
|
101
102
|
self.unknown_patience = int(unknown_patience)
|
|
@@ -119,69 +120,65 @@ class TemporalIdentityManager:
|
|
|
119
120
|
|
|
120
121
|
async def _compute_best_identity(self, emb: List[float], location: str = "", timestamp: str = "") -> Tuple[Optional[str], str, float, Optional[str], Dict[str, Any], str]:
|
|
121
122
|
"""
|
|
122
|
-
Query
|
|
123
|
+
Query embedding manager for top-1 match using local similarity search.
|
|
123
124
|
Returns (staff_id, person_name, score, employee_id, staff_details, detection_type).
|
|
124
|
-
|
|
125
|
+
|
|
126
|
+
NOTE: API call to search_similar_faces is commented out - using local embeddings only.
|
|
125
127
|
"""
|
|
126
128
|
if not emb or not isinstance(emb, list):
|
|
127
129
|
return None, "Unknown", 0.0, None, {}, "unknown"
|
|
130
|
+
|
|
131
|
+
# COMMENTED OUT: API-based search - now using local embedding similarity search
|
|
132
|
+
# try:
|
|
133
|
+
# resp = await self.face_client.search_similar_faces(
|
|
134
|
+
# face_embedding=emb,
|
|
135
|
+
# threshold=0.01, # low threshold to always get top-1
|
|
136
|
+
# limit=1,
|
|
137
|
+
# collection="staff_enrollment",
|
|
138
|
+
# location=location,
|
|
139
|
+
# timestamp=timestamp,
|
|
140
|
+
# )
|
|
141
|
+
# except Exception as e:
|
|
142
|
+
# self.logger.error(f"API ERROR: Failed to search similar faces in _compute_best_identity: {e}", exc_info=True)
|
|
143
|
+
# return None, "Unknown", 0.0, None, {}, "unknown"
|
|
144
|
+
#
|
|
145
|
+
# [API response parsing code removed - see git history]
|
|
146
|
+
|
|
147
|
+
# NEW: Use local embedding manager for similarity search
|
|
128
148
|
try:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
149
|
+
if not self.embedding_manager:
|
|
150
|
+
self.logger.warning("Embedding manager not available for local similarity search")
|
|
151
|
+
return None, "Unknown", 0.0, None, {}, "unknown"
|
|
152
|
+
|
|
153
|
+
# Perform local similarity search using embedding manager
|
|
154
|
+
search_result = await self.embedding_manager.search_face_embedding(
|
|
155
|
+
embedding=emb,
|
|
156
|
+
track_id=None, # No track_id needed for this search
|
|
134
157
|
location=location,
|
|
135
158
|
timestamp=timestamp,
|
|
136
159
|
)
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
try:
|
|
142
|
-
results: List[Any] = []
|
|
143
|
-
self.logger.debug('API Response received for identity search')
|
|
144
|
-
if isinstance(resp, dict):
|
|
145
|
-
if isinstance(resp.get("data"), list):
|
|
146
|
-
results = resp.get("data", [])
|
|
147
|
-
elif isinstance(resp.get("results"), list):
|
|
148
|
-
results = resp.get("results", [])
|
|
149
|
-
elif isinstance(resp.get("items"), list):
|
|
150
|
-
results = resp.get("items", [])
|
|
151
|
-
elif isinstance(resp, list):
|
|
152
|
-
results = resp
|
|
153
|
-
|
|
154
|
-
if not results:
|
|
155
|
-
self.logger.debug("No identity match found from API")
|
|
160
|
+
|
|
161
|
+
if not search_result:
|
|
162
|
+
self.logger.debug("No identity match found from local embeddings")
|
|
156
163
|
return None, "Unknown", 0.0, None, {}, "unknown"
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
employee_id =
|
|
163
|
-
|
|
164
|
-
detection_type =
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if isinstance(staff_details, dict) and staff_details:
|
|
169
|
-
first_name = staff_details.get("firstName")
|
|
170
|
-
last_name = staff_details.get("lastName")
|
|
171
|
-
name = staff_details.get("name")
|
|
172
|
-
if name:
|
|
173
|
-
person_name = str(name)
|
|
174
|
-
else:
|
|
175
|
-
if first_name or last_name:
|
|
176
|
-
person_name = f"{first_name or ''} {last_name or ''}".strip() or "UnknowNN" #TODO:ebugging change to normal once done
|
|
177
|
-
# If API says unknown or missing staff_id, treat as unknown
|
|
178
|
-
if not staff_id: #or detection_type == "unknown"
|
|
179
|
-
self.logger.debug(f"API returned unknown or missing staff_id - score={score}, employee_id={employee_id}")
|
|
164
|
+
|
|
165
|
+
# Extract data from SearchResult
|
|
166
|
+
staff_id = search_result.staff_id
|
|
167
|
+
person_name = search_result.person_name
|
|
168
|
+
score = search_result.similarity_score
|
|
169
|
+
employee_id = search_result.employee_id
|
|
170
|
+
staff_details = search_result.staff_details
|
|
171
|
+
detection_type = search_result.detection_type
|
|
172
|
+
|
|
173
|
+
if not staff_id or detection_type == "unknown":
|
|
174
|
+
self.logger.debug(f"Local search returned unknown or missing staff_id - score={score}, employee_id={employee_id}")
|
|
180
175
|
return None, "Unknown", float(score), employee_id, staff_details if isinstance(staff_details, dict) else {}, "unknown"
|
|
181
|
-
|
|
176
|
+
|
|
177
|
+
self.logger.info(f"Local embedding identified face - staff_id={staff_id}, person_name={person_name}, score={score:.3f}")
|
|
182
178
|
return str(staff_id), person_name, float(score), employee_id, staff_details if isinstance(staff_details, dict) else {}, "known"
|
|
179
|
+
|
|
183
180
|
except Exception as e:
|
|
184
|
-
self.logger.error(f"Error
|
|
181
|
+
self.logger.error(f"Error in local embedding similarity search: {e}", exc_info=True)
|
|
185
182
|
return None, "Unknown", 0.0, None, {}, "unknown"
|
|
186
183
|
|
|
187
184
|
async def _compute_best_identity_from_history(self, track_state: Dict[str, object], location: str = "", timestamp: str = "") -> Tuple[Optional[str], str, float, Optional[str], Dict[str, Any], str]:
|
|
@@ -488,16 +485,17 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
488
485
|
self.embedding_manager = EmbeddingManager(init_config.embedding_config, self.face_client)
|
|
489
486
|
self.logger.info("Embedding manager initialized")
|
|
490
487
|
|
|
491
|
-
# Initialize TemporalIdentityManager
|
|
488
|
+
# Initialize TemporalIdentityManager with embedding_manager for local search
|
|
492
489
|
self.temporal_identity_manager = TemporalIdentityManager(
|
|
493
490
|
face_client=self.face_client,
|
|
491
|
+
embedding_manager=self.embedding_manager, # Pass embedding manager for local similarity search
|
|
494
492
|
recognition_threshold=float(init_config.similarity_threshold),
|
|
495
493
|
history_size=20,
|
|
496
494
|
unknown_patience=7,
|
|
497
495
|
switch_patience=5,
|
|
498
496
|
fallback_margin=0.05,
|
|
499
497
|
)
|
|
500
|
-
self.logger.info("Temporal identity manager initialized")
|
|
498
|
+
self.logger.info("Temporal identity manager initialized with local embedding search")
|
|
501
499
|
|
|
502
500
|
self._initialized = True
|
|
503
501
|
self.logger.info("Face recognition use case fully initialized")
|
|
@@ -909,16 +907,28 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
909
907
|
# Generate current timestamp
|
|
910
908
|
current_timestamp = datetime.now(timezone.utc).isoformat()
|
|
911
909
|
|
|
912
|
-
|
|
913
|
-
#
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
# Process each detection sequentially with await to preserve order
|
|
917
|
-
processed_detection = await self._process_face(
|
|
910
|
+
# Process all detections in parallel for better performance
|
|
911
|
+
# Create tasks for parallel processing
|
|
912
|
+
tasks = [
|
|
913
|
+
self._process_face(
|
|
918
914
|
detection, current_frame, location, current_timestamp, config,
|
|
919
915
|
current_recognized_count, current_unknown_count,
|
|
920
916
|
recognized_persons, current_frame_staff_details
|
|
921
917
|
)
|
|
918
|
+
for detection in detections
|
|
919
|
+
]
|
|
920
|
+
|
|
921
|
+
# Process all faces in parallel
|
|
922
|
+
processed_detections = await asyncio.gather(*tasks, return_exceptions=True)
|
|
923
|
+
|
|
924
|
+
# Build final results and update counters (maintains order)
|
|
925
|
+
final_detections = []
|
|
926
|
+
for processed_detection in processed_detections:
|
|
927
|
+
# Handle exceptions from parallel processing
|
|
928
|
+
if isinstance(processed_detection, Exception):
|
|
929
|
+
self.logger.error(f"Error processing face detection: {processed_detection}", exc_info=True)
|
|
930
|
+
continue
|
|
931
|
+
|
|
922
932
|
# Include both known and unknown faces in final detections (maintains original order)
|
|
923
933
|
if processed_detection:
|
|
924
934
|
final_detections.append(processed_detection)
|
|
@@ -1085,7 +1095,7 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
1085
1095
|
# If it later becomes recognized, we'll remove it from unknown set above
|
|
1086
1096
|
self._unknown_track_ids.add(internal_tid)
|
|
1087
1097
|
|
|
1088
|
-
# Enqueue detection for background logging with all required parameters
|
|
1098
|
+
# Enqueue detection for background logging with all required parameters (non-blocking)
|
|
1089
1099
|
try:
|
|
1090
1100
|
# Log known faces for activity tracking (skip any employee_id starting with "unknown_")
|
|
1091
1101
|
if (
|
|
@@ -1096,7 +1106,8 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
1096
1106
|
and employee_id
|
|
1097
1107
|
and not str(employee_id).startswith("unknown_")
|
|
1098
1108
|
):
|
|
1099
|
-
await
|
|
1109
|
+
# Non-blocking enqueue - no await needed
|
|
1110
|
+
self.people_activity_logging.enqueue_detection(
|
|
1100
1111
|
detection=detection,
|
|
1101
1112
|
current_frame=current_frame,
|
|
1102
1113
|
location=location,
|
|
@@ -1743,56 +1754,57 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
1743
1754
|
return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
|
|
1744
1755
|
|
|
1745
1756
|
def _format_timestamp(self, timestamp: Any) -> str:
|
|
1746
|
-
"""Format a timestamp
|
|
1757
|
+
"""Format a timestamp to match the current timestamp format: YYYY:MM:DD HH:MM:SS.
|
|
1747
1758
|
|
|
1748
1759
|
The input can be either:
|
|
1749
|
-
1. A numeric Unix timestamp (``float`` / ``int``) – it will
|
|
1750
|
-
|
|
1751
|
-
2. A string already following the same layout.
|
|
1760
|
+
1. A numeric Unix timestamp (``float`` / ``int``) – it will be converted to datetime.
|
|
1761
|
+
2. A string in the format ``YYYY-MM-DD-HH:MM:SS.ffffff UTC``.
|
|
1752
1762
|
|
|
1753
|
-
The returned value
|
|
1754
|
-
the fractional seconds portion to **exactly two digits**.
|
|
1763
|
+
The returned value will be in the format: YYYY:MM:DD HH:MM:SS (no milliseconds, no UTC suffix).
|
|
1755
1764
|
|
|
1756
1765
|
Example
|
|
1757
1766
|
-------
|
|
1758
|
-
>>> self._format_timestamp("2025-
|
|
1759
|
-
'2025
|
|
1767
|
+
>>> self._format_timestamp("2025-10-27-19:31:20.187574 UTC")
|
|
1768
|
+
'2025:10:27 19:31:20'
|
|
1760
1769
|
"""
|
|
1761
1770
|
|
|
1762
|
-
# Convert numeric timestamps to
|
|
1771
|
+
# Convert numeric timestamps to datetime first
|
|
1763
1772
|
if isinstance(timestamp, (int, float)):
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
)
|
|
1773
|
+
dt = datetime.fromtimestamp(timestamp, timezone.utc)
|
|
1774
|
+
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
|
1767
1775
|
|
|
1768
1776
|
# Ensure we are working with a string from here on
|
|
1769
1777
|
if not isinstance(timestamp, str):
|
|
1770
1778
|
return str(timestamp)
|
|
1771
1779
|
|
|
1772
|
-
#
|
|
1773
|
-
|
|
1774
|
-
return timestamp
|
|
1780
|
+
# Remove ' UTC' suffix if present
|
|
1781
|
+
timestamp_clean = timestamp.replace(' UTC', '').strip()
|
|
1775
1782
|
|
|
1776
|
-
#
|
|
1777
|
-
|
|
1783
|
+
# Remove milliseconds if present (everything after the last dot)
|
|
1784
|
+
if '.' in timestamp_clean:
|
|
1785
|
+
timestamp_clean = timestamp_clean.split('.')[0]
|
|
1778
1786
|
|
|
1779
|
-
#
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1787
|
+
# Parse the timestamp string and convert to desired format
|
|
1788
|
+
try:
|
|
1789
|
+
# Handle format: YYYY-MM-DD-HH:MM:SS
|
|
1790
|
+
if timestamp_clean.count('-') >= 2:
|
|
1791
|
+
# Replace first two dashes with colons for date part, third with space
|
|
1792
|
+
parts = timestamp_clean.split('-')
|
|
1793
|
+
if len(parts) >= 4:
|
|
1794
|
+
# parts = ['2025', '10', '27', '19:31:20']
|
|
1795
|
+
formatted = f"{parts[0]}:{parts[1]}:{parts[2]} {'-'.join(parts[3:])}"
|
|
1796
|
+
return formatted
|
|
1797
|
+
except Exception:
|
|
1798
|
+
pass
|
|
1788
1799
|
|
|
1789
|
-
return
|
|
1800
|
+
# If parsing fails, return the cleaned string as-is
|
|
1801
|
+
return timestamp_clean
|
|
1790
1802
|
|
|
1791
1803
|
def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
|
|
1792
1804
|
"""Get formatted current timestamp based on stream type."""
|
|
1805
|
+
|
|
1793
1806
|
if not stream_info:
|
|
1794
1807
|
return "00:00:00.00"
|
|
1795
|
-
|
|
1796
1808
|
if precision:
|
|
1797
1809
|
if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
|
|
1798
1810
|
if frame_id:
|
|
@@ -1801,7 +1813,6 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
1801
1813
|
start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
|
|
1802
1814
|
stream_time_str = self._format_timestamp_for_video(start_time)
|
|
1803
1815
|
|
|
1804
|
-
|
|
1805
1816
|
return self._format_timestamp(stream_info.get("input_settings", {}).get("stream_time", "NA"))
|
|
1806
1817
|
else:
|
|
1807
1818
|
return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
@@ -1813,7 +1824,8 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
1813
1824
|
start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
|
|
1814
1825
|
|
|
1815
1826
|
stream_time_str = self._format_timestamp_for_video(start_time)
|
|
1816
|
-
|
|
1827
|
+
|
|
1828
|
+
|
|
1817
1829
|
return self._format_timestamp(stream_info.get("input_settings", {}).get("stream_time", "NA"))
|
|
1818
1830
|
else:
|
|
1819
1831
|
stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
|
|
@@ -1835,23 +1847,57 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
1835
1847
|
|
|
1836
1848
|
if precision:
|
|
1837
1849
|
if self.start_timer is None:
|
|
1838
|
-
|
|
1850
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
1851
|
+
if not candidate or candidate == "NA":
|
|
1852
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1853
|
+
self.start_timer = candidate
|
|
1839
1854
|
return self._format_timestamp(self.start_timer)
|
|
1840
1855
|
elif stream_info.get("input_settings", {}).get("start_frame", "na") == 1:
|
|
1841
|
-
|
|
1856
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
1857
|
+
if not candidate or candidate == "NA":
|
|
1858
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1859
|
+
self.start_timer = candidate
|
|
1842
1860
|
return self._format_timestamp(self.start_timer)
|
|
1843
1861
|
else:
|
|
1844
1862
|
return self._format_timestamp(self.start_timer)
|
|
1845
1863
|
|
|
1846
1864
|
if self.start_timer is None:
|
|
1847
|
-
|
|
1865
|
+
# Prefer direct input_settings.stream_time if available and not NA
|
|
1866
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
1867
|
+
if not candidate or candidate == "NA":
|
|
1868
|
+
# Fallback to nested stream_info.stream_time used by current timestamp path
|
|
1869
|
+
stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
|
|
1870
|
+
if stream_time_str:
|
|
1871
|
+
try:
|
|
1872
|
+
timestamp_str = stream_time_str.replace(" UTC", "")
|
|
1873
|
+
dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
|
|
1874
|
+
self._tracking_start_time = dt.replace(tzinfo=timezone.utc).timestamp()
|
|
1875
|
+
candidate = datetime.fromtimestamp(self._tracking_start_time, timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1876
|
+
except:
|
|
1877
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1878
|
+
else:
|
|
1879
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1880
|
+
self.start_timer = candidate
|
|
1848
1881
|
return self._format_timestamp(self.start_timer)
|
|
1849
1882
|
elif stream_info.get("input_settings", {}).get("start_frame", "na") == 1:
|
|
1850
|
-
|
|
1883
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
1884
|
+
if not candidate or candidate == "NA":
|
|
1885
|
+
stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
|
|
1886
|
+
if stream_time_str:
|
|
1887
|
+
try:
|
|
1888
|
+
timestamp_str = stream_time_str.replace(" UTC", "")
|
|
1889
|
+
dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
|
|
1890
|
+
ts = dt.replace(tzinfo=timezone.utc).timestamp()
|
|
1891
|
+
candidate = datetime.fromtimestamp(ts, timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1892
|
+
except:
|
|
1893
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1894
|
+
else:
|
|
1895
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1896
|
+
self.start_timer = candidate
|
|
1851
1897
|
return self._format_timestamp(self.start_timer)
|
|
1852
1898
|
|
|
1853
1899
|
else:
|
|
1854
|
-
if self.start_timer is not None:
|
|
1900
|
+
if self.start_timer is not None and self.start_timer != "NA":
|
|
1855
1901
|
return self._format_timestamp(self.start_timer)
|
|
1856
1902
|
|
|
1857
1903
|
if self._tracking_start_time is None:
|
|
@@ -182,9 +182,9 @@ class FacialRecognitionClient:
|
|
|
182
182
|
payload=enrollment_request,
|
|
183
183
|
base_url=self.server_base_url
|
|
184
184
|
)
|
|
185
|
-
self.logger.info(f"API RESPONSE: Staff enrollment completed - Success: {response.get('success', False)}")
|
|
186
|
-
if not response.get('success', False):
|
|
187
|
-
self.logger.warning(f"Staff enrollment failed: {response.get('error', 'Unknown error')}")
|
|
185
|
+
self.logger.info(f"API RESPONSE: Staff enrollment completed - Success: {response.get('success', False) if response else False}")
|
|
186
|
+
if not response or not response.get('success', False):
|
|
187
|
+
self.logger.warning(f"Staff enrollment failed: {response.get('error', 'Unknown error') if response else 'No response'}")
|
|
188
188
|
return self._handle_response(response)
|
|
189
189
|
except Exception as e:
|
|
190
190
|
self.logger.error(f"API ERROR: Staff enrollment request failed - {e}", exc_info=True)
|
|
@@ -236,14 +236,14 @@ class FacialRecognitionClient:
|
|
|
236
236
|
)
|
|
237
237
|
|
|
238
238
|
results_count = 0
|
|
239
|
-
if response.get('success', False):
|
|
239
|
+
if response and response.get('success', False):
|
|
240
240
|
data = response.get('data', [])
|
|
241
241
|
results_count = len(data) if isinstance(data, list) else 0
|
|
242
242
|
self.logger.info(f"API RESPONSE: Face search completed - Found {results_count} matches")
|
|
243
243
|
if results_count > 0:
|
|
244
244
|
self.logger.debug(f"Top match: staff_id={data[0].get('staffId', 'N/A')}, score={data[0].get('score', 0):.3f}")
|
|
245
245
|
else:
|
|
246
|
-
self.logger.warning(f"Face search failed: {response.get('error', 'Unknown error')}")
|
|
246
|
+
self.logger.warning(f"Face search failed: {response.get('error', 'Unknown error') if response else 'No response'}")
|
|
247
247
|
|
|
248
248
|
return self._handle_response(response)
|
|
249
249
|
except Exception as e:
|
|
@@ -267,10 +267,10 @@ class FacialRecognitionClient:
|
|
|
267
267
|
base_url=self.server_base_url
|
|
268
268
|
)
|
|
269
269
|
|
|
270
|
-
if response.get('success', False):
|
|
270
|
+
if response and response.get('success', False):
|
|
271
271
|
self.logger.info(f"API RESPONSE: Staff details retrieved successfully - staff_id={staff_id}")
|
|
272
272
|
else:
|
|
273
|
-
self.logger.warning(f"Failed to get staff details for staff_id={staff_id}: {response.get('error', 'Unknown error')}")
|
|
273
|
+
self.logger.warning(f"Failed to get staff details for staff_id={staff_id}: {response.get('error', 'Unknown error') if response else 'No response'}")
|
|
274
274
|
|
|
275
275
|
return self._handle_response(response)
|
|
276
276
|
except Exception as e:
|
|
@@ -366,10 +366,10 @@ class FacialRecognitionClient:
|
|
|
366
366
|
base_url=self.server_base_url
|
|
367
367
|
)
|
|
368
368
|
|
|
369
|
-
if response.get('success', False):
|
|
369
|
+
if response and response.get('success', False):
|
|
370
370
|
self.logger.info(f"API RESPONSE: Staff images updated successfully - employee_id={employee_id}")
|
|
371
371
|
else:
|
|
372
|
-
self.logger.warning(f"Failed to update staff images for employee_id={employee_id}: {response.get('error', 'Unknown error')}")
|
|
372
|
+
self.logger.warning(f"Failed to update staff images for employee_id={employee_id}: {response.get('error', 'Unknown error') if response else 'No response'}")
|
|
373
373
|
|
|
374
374
|
return self._handle_response(response)
|
|
375
375
|
except Exception as e:
|
|
@@ -417,10 +417,10 @@ class FacialRecognitionClient:
|
|
|
417
417
|
base_url=self.server_base_url
|
|
418
418
|
)
|
|
419
419
|
|
|
420
|
-
if response.get('success', False):
|
|
420
|
+
if response and response.get('success', False):
|
|
421
421
|
self.logger.info(f"API RESPONSE: Service shutdown successful")
|
|
422
422
|
else:
|
|
423
|
-
self.logger.warning(f"Service shutdown failed: {response.get('error', 'Unknown error')}")
|
|
423
|
+
self.logger.warning(f"Service shutdown failed: {response.get('error', 'Unknown error') if response else 'No response'}")
|
|
424
424
|
|
|
425
425
|
return self._handle_response(response)
|
|
426
426
|
except Exception as e:
|
|
@@ -447,12 +447,12 @@ class FacialRecognitionClient:
|
|
|
447
447
|
)
|
|
448
448
|
|
|
449
449
|
embeddings_count = 0
|
|
450
|
-
if response.get('success', False):
|
|
450
|
+
if response and response.get('success', False):
|
|
451
451
|
data = response.get('data', [])
|
|
452
452
|
embeddings_count = len(data) if isinstance(data, list) else 0
|
|
453
453
|
self.logger.info(f"API RESPONSE: Retrieved {embeddings_count} staff embeddings")
|
|
454
454
|
else:
|
|
455
|
-
self.logger.warning(f"Failed to get staff embeddings: {response.get('error', 'Unknown error')}")
|
|
455
|
+
self.logger.warning(f"Failed to get staff embeddings: {response.get('error', 'Unknown error') if response else 'No response'}")
|
|
456
456
|
|
|
457
457
|
return self._handle_response(response)
|
|
458
458
|
except Exception as e:
|
|
@@ -485,10 +485,10 @@ class FacialRecognitionClient:
|
|
|
485
485
|
base_url=self.server_base_url
|
|
486
486
|
)
|
|
487
487
|
|
|
488
|
-
if response.get('success', False):
|
|
488
|
+
if response and response.get('success', False):
|
|
489
489
|
self.logger.info(f"API RESPONSE: Deployment updated successfully - deployment_id={deployment_id}")
|
|
490
490
|
else:
|
|
491
|
-
self.logger.warning(f"Failed to update deployment for deployment_id={deployment_id}: {response.get('error', 'Unknown error')}")
|
|
491
|
+
self.logger.warning(f"Failed to update deployment for deployment_id={deployment_id}: {response.get('error', 'Unknown error') if response else 'No response'}")
|
|
492
492
|
|
|
493
493
|
return self._handle_response(response)
|
|
494
494
|
except Exception as e:
|
|
@@ -527,10 +527,10 @@ class FacialRecognitionClient:
|
|
|
527
527
|
base_url=self.server_base_url
|
|
528
528
|
)
|
|
529
529
|
|
|
530
|
-
if response.get('success', False):
|
|
530
|
+
if response and response.get('success', False):
|
|
531
531
|
self.logger.info(f"API RESPONSE: Unknown person enrolled successfully")
|
|
532
532
|
else:
|
|
533
|
-
self.logger.warning(f"Failed to enroll unknown person: {response.get('error', 'Unknown error')}")
|
|
533
|
+
self.logger.warning(f"Failed to enroll unknown person: {response.get('error', 'Unknown error') if response else 'No response'}")
|
|
534
534
|
|
|
535
535
|
return self._handle_response(response)
|
|
536
536
|
except Exception as e:
|
|
@@ -551,10 +551,10 @@ class FacialRecognitionClient:
|
|
|
551
551
|
base_url=self.server_base_url
|
|
552
552
|
)
|
|
553
553
|
|
|
554
|
-
if response.get('success', False):
|
|
554
|
+
if response and response.get('success', False):
|
|
555
555
|
self.logger.info(f"API RESPONSE: Service is healthy")
|
|
556
556
|
else:
|
|
557
|
-
self.logger.warning(f"Health check failed: {response.get('error', 'Unknown error')}")
|
|
557
|
+
self.logger.warning(f"Health check failed: {response.get('error', 'Unknown error') if response else 'No response'}")
|
|
558
558
|
|
|
559
559
|
return self._handle_response(response)
|
|
560
560
|
except Exception as e:
|
|
@@ -564,6 +564,11 @@ class FacialRecognitionClient:
|
|
|
564
564
|
def _handle_response(self, response: Dict[str, Any]) -> Dict[str, Any]:
|
|
565
565
|
"""Handle RPC response and errors"""
|
|
566
566
|
try:
|
|
567
|
+
# Handle None response
|
|
568
|
+
if response is None:
|
|
569
|
+
self.logger.error("RPC Error: Received None response from API")
|
|
570
|
+
return {"success": False, "error": "No response received from API"}
|
|
571
|
+
|
|
567
572
|
if response.get("success", True):
|
|
568
573
|
return response
|
|
569
574
|
else:
|
|
@@ -84,19 +84,20 @@ class PeopleActivityLogging:
|
|
|
84
84
|
self.activity_queue.task_done()
|
|
85
85
|
except queue.Empty:
|
|
86
86
|
# Continue loop to check for empty detections
|
|
87
|
+
await asyncio.sleep(0.01)
|
|
87
88
|
continue
|
|
88
89
|
|
|
89
90
|
except Exception as e:
|
|
90
91
|
self.logger.error(f"Error processing activity queue: {e}", exc_info=True)
|
|
91
92
|
await asyncio.sleep(1.0)
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
def enqueue_detection(
|
|
94
95
|
self,
|
|
95
96
|
detection: Dict,
|
|
96
97
|
current_frame: Optional[np.ndarray] = None,
|
|
97
98
|
location: str = "",
|
|
98
99
|
):
|
|
99
|
-
"""Enqueue a detection for background processing"""
|
|
100
|
+
"""Enqueue a detection for background processing (non-blocking)"""
|
|
100
101
|
try:
|
|
101
102
|
activity_data = {
|
|
102
103
|
"detection_type": detection["recognition_status"], # known, unknown
|
|
@@ -135,8 +136,9 @@ class PeopleActivityLogging:
|
|
|
135
136
|
self.last_detection_time = time.time()
|
|
136
137
|
self.empty_detection_logged = False
|
|
137
138
|
|
|
138
|
-
# Use thread-safe
|
|
139
|
-
|
|
139
|
+
# Use thread-safe put_nowait to avoid any potential blocking
|
|
140
|
+
# queue.Queue.put() is already non-blocking with no timeout, but being explicit
|
|
141
|
+
self.activity_queue.put_nowait(activity_data)
|
|
140
142
|
except Exception as e:
|
|
141
143
|
self.logger.error(f"Error enqueueing detection: {e}", exc_info=True)
|
|
142
144
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import easyocr
|
|
2
2
|
import numpy as np
|
|
3
3
|
import torch
|
|
4
|
+
from matrice_common.utils import log_errors
|
|
4
5
|
|
|
5
6
|
class EasyOCRExtractor:
|
|
6
7
|
def __init__(self, lang=['en', 'hi', 'ar'], gpu=False, model_storage_directory=None,
|
|
@@ -30,7 +31,8 @@ class EasyOCRExtractor:
|
|
|
30
31
|
self.recognizer = recognizer
|
|
31
32
|
self.verbose = verbose
|
|
32
33
|
self.reader = None
|
|
33
|
-
|
|
34
|
+
|
|
35
|
+
@log_errors(default_return=None, raise_exception=True, service_name="py_analytics", log_error=True)
|
|
34
36
|
def setup(self):
|
|
35
37
|
"""
|
|
36
38
|
Initializes the EasyOCR reader if not already initialized.
|