Enhance car detection logic with bbox area validation and update .gitignore
This commit is contained in:
		
							parent
							
								
									356da144fc
								
							
						
					
					
						commit
						34ecff244c
					
				
					 3 changed files with 94 additions and 4 deletions
				
			
		
							
								
								
									
										7
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -17,3 +17,10 @@ feeder/
 | 
				
			||||||
dist/
 | 
					dist/
 | 
				
			||||||
websocket_comm.log
 | 
					websocket_comm.log
 | 
				
			||||||
temp_debug/
 | 
					temp_debug/
 | 
				
			||||||
 | 
					.claude
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Video Test
 | 
				
			||||||
 | 
					video_rtsp/
 | 
				
			||||||
 | 
					multi_stream_viewer.py
 | 
				
			||||||
 | 
					multi_camera_simulator.py
 | 
				
			||||||
 | 
					start_4_cameras.bat
 | 
				
			||||||
							
								
								
									
										30
									
								
								app.py
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								app.py
									
										
									
									
									
								
							| 
						 | 
					@ -1069,10 +1069,34 @@ async def detect(websocket: WebSocket):
 | 
				
			||||||
                    from siwatsystem.pympta import run_lightweight_detection
 | 
					                    from siwatsystem.pympta import run_lightweight_detection
 | 
				
			||||||
                    basic_detection = run_lightweight_detection(cropped_frame, model_tree)
 | 
					                    basic_detection = run_lightweight_detection(cropped_frame, model_tree)
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    any_car_detected = basic_detection and basic_detection.get("car_detected", False)
 | 
					                    # Enhanced car detection: requires both confidence pass AND bbox >= 50% of frame
 | 
				
			||||||
                    logger.debug(f"🔍 Camera {camera_id}: LIGHTWEIGHT - simple car presence check: {any_car_detected}")
 | 
					                    car_detected_confidence = basic_detection and basic_detection.get("car_detected", False)
 | 
				
			||||||
 | 
					                    car_detected_with_bbox_validation = False
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    if any_car_detected:
 | 
					                    if car_detected_confidence:
 | 
				
			||||||
 | 
					                        # Car passed confidence - now check bbox area
 | 
				
			||||||
 | 
					                        best_detection = basic_detection.get("best_detection")
 | 
				
			||||||
 | 
					                        if best_detection and best_detection.get("bbox"):
 | 
				
			||||||
 | 
					                            bbox = best_detection["bbox"]
 | 
				
			||||||
 | 
					                            x1, y1, x2, y2 = bbox
 | 
				
			||||||
 | 
					                            bbox_area = (x2 - x1) * (y2 - y1)
 | 
				
			||||||
 | 
					                            frame_height, frame_width = cropped_frame.shape[:2]
 | 
				
			||||||
 | 
					                            frame_area = frame_height * frame_width
 | 
				
			||||||
 | 
					                            bbox_area_ratio = bbox_area / frame_area if frame_area > 0 else 0
 | 
				
			||||||
 | 
					                            
 | 
				
			||||||
 | 
					                            min_area_ratio = 0.2  # 20% of frame
 | 
				
			||||||
 | 
					                            car_detected_with_bbox_validation = bbox_area_ratio >= min_area_ratio
 | 
				
			||||||
 | 
					                            
 | 
				
			||||||
 | 
					                            if not car_detected_with_bbox_validation:
 | 
				
			||||||
 | 
					                                logger.info(f"🚫 Camera {camera_id}: LIGHTWEIGHT - car detected but bbox {bbox_area_ratio:.1%} < {min_area_ratio:.0%} (too distant) - counting as absent")
 | 
				
			||||||
 | 
					                            else:
 | 
				
			||||||
 | 
					                                logger.debug(f"✅ Camera {camera_id}: LIGHTWEIGHT - car detected with valid bbox {bbox_area_ratio:.1%} >= {min_area_ratio:.0%}")
 | 
				
			||||||
 | 
					                        else:
 | 
				
			||||||
 | 
					                            logger.debug(f"⚠️ Camera {camera_id}: LIGHTWEIGHT - car detected but no bbox info available")
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    logger.debug(f"🔍 Camera {camera_id}: LIGHTWEIGHT - enhanced car presence check: confidence={car_detected_confidence}, bbox_valid={car_detected_with_bbox_validation}")
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    if car_detected_with_bbox_validation:
 | 
				
			||||||
                        # Car detected - reset absence counter, continue sending cached detection dict
 | 
					                        # Car detected - reset absence counter, continue sending cached detection dict
 | 
				
			||||||
                        pipeline_state["absence_counter"] = 0  # Reset absence since cars are present
 | 
					                        pipeline_state["absence_counter"] = 0  # Reset absence since cars are present
 | 
				
			||||||
                        
 | 
					                        
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -733,12 +733,17 @@ def run_detection_with_tracking(frame, node, context=None):
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            # Tracking zone validation removed - process all detections
 | 
					            # Tracking zone validation removed - process all detections
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
 | 
					            # Calculate bbox area
 | 
				
			||||||
 | 
					            x1, y1, x2, y2 = bbox
 | 
				
			||||||
 | 
					            bbox_area = (x2 - x1) * (y2 - y1)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            # Create detection object
 | 
					            # Create detection object
 | 
				
			||||||
            detection = {
 | 
					            detection = {
 | 
				
			||||||
                "class": class_name,
 | 
					                "class": class_name,
 | 
				
			||||||
                "confidence": conf,
 | 
					                "confidence": conf,
 | 
				
			||||||
                "id": track_id,
 | 
					                "id": track_id,
 | 
				
			||||||
                "bbox": bbox,
 | 
					                "bbox": bbox,
 | 
				
			||||||
 | 
					                "bbox_area": bbox_area,
 | 
				
			||||||
                "class_id": cls_id
 | 
					                "class_id": cls_id
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
| 
						 | 
					@ -927,6 +932,31 @@ def update_single_track_stability(node, detection, camera_id, frame_shape=None,
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    current_track_id = detection.get("id") if detection else None
 | 
					    current_track_id = detection.get("id") if detection else None
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    # ─── Bbox Area Validation for Stability ───
 | 
				
			||||||
 | 
					    # Only count detections where bbox area is >=20% of frame (close cars only)
 | 
				
			||||||
 | 
					    if detection and frame_shape is not None:
 | 
				
			||||||
 | 
					        bbox = detection.get("bbox", [0, 0, 0, 0])
 | 
				
			||||||
 | 
					        if bbox and len(bbox) >= 4:
 | 
				
			||||||
 | 
					            x1, y1, x2, y2 = bbox
 | 
				
			||||||
 | 
					            bbox_area = (x2 - x1) * (y2 - y1)
 | 
				
			||||||
 | 
					            frame_height, frame_width = frame_shape[:2]
 | 
				
			||||||
 | 
					            frame_area = frame_height * frame_width
 | 
				
			||||||
 | 
					            bbox_area_ratio = bbox_area / frame_area if frame_area > 0 else 0
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            # Require bbox to be at least 20% of frame area
 | 
				
			||||||
 | 
					            min_area_ratio = 0.2
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if bbox_area_ratio < min_area_ratio:
 | 
				
			||||||
 | 
					                logger.info(f"🚫 Camera {camera_id}: Track {current_track_id} REJECTED for stability - bbox area {bbox_area_ratio:.1%} < {min_area_ratio:.0%} (too small/distant)")
 | 
				
			||||||
 | 
					                # Completely reset - remove track entirely (same as trackId change)
 | 
				
			||||||
 | 
					                if current_track_id and current_track_id in track_counters:
 | 
				
			||||||
 | 
					                    old_count = track_counters.pop(current_track_id, 0)  # Remove completely
 | 
				
			||||||
 | 
					                    stable_tracks.discard(current_track_id)  # Remove from stable
 | 
				
			||||||
 | 
					                    logger.info(f"🔄 Camera {camera_id}: COMPLETELY RESET track {current_track_id} counter from {old_count} to 0 (reason: bbox too small)")
 | 
				
			||||||
 | 
					                return {"validation_complete": False, "stable_tracks": list(stable_tracks), "current_tracks": [], "bbox_too_small": True}
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                logger.debug(f"✅ Camera {camera_id}: Track {current_track_id} bbox area {bbox_area_ratio:.1%} >= {min_area_ratio:.0%} - acceptable for stability")
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    # ═══ MODE-AWARE TRACK VALIDATION ═══
 | 
					    # ═══ MODE-AWARE TRACK VALIDATION ═══
 | 
				
			||||||
    logger.debug(f"📋 Camera {camera_id}: === TRACK VALIDATION ANALYSIS ===")
 | 
					    logger.debug(f"📋 Camera {camera_id}: === TRACK VALIDATION ANALYSIS ===")
 | 
				
			||||||
    logger.debug(f"📋 Camera {camera_id}: Current mode: {current_mode} (validation_mode={is_validation_mode})")
 | 
					    logger.debug(f"📋 Camera {camera_id}: Current mode: {current_mode} (validation_mode={is_validation_mode})")
 | 
				
			||||||
| 
						 | 
					@ -1433,6 +1463,35 @@ def run_pipeline(frame, node: dict, return_bbox: bool=False, context=None, valid
 | 
				
			||||||
            # Normal detection stage - Using structured detection function
 | 
					            # Normal detection stage - Using structured detection function
 | 
				
			||||||
            all_detections, regions_dict, track_validation_result = run_detection_with_tracking(frame, node, context)
 | 
					            all_detections, regions_dict, track_validation_result = run_detection_with_tracking(frame, node, context)
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
 | 
					            # ─── Apply largest bbox area selection for full pipeline mode ───
 | 
				
			||||||
 | 
					            # When we have stable tracks and multiple detections, select the largest bbox area one
 | 
				
			||||||
 | 
					            stable_tracks = track_validation_result.get("stable_tracks", [])
 | 
				
			||||||
 | 
					            if stable_tracks and len(all_detections) > 1:
 | 
				
			||||||
 | 
					                logger.info(f"🔍 PIPELINE: Full pipeline mode - selecting largest bbox area from {len(all_detections)} detections")
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                # Select detection with largest bbox area
 | 
				
			||||||
 | 
					                largest_detection = max(all_detections, key=lambda x: x.get("bbox_area", 0))
 | 
				
			||||||
 | 
					                logger.info(f"🎯 PIPELINE: Selected largest bbox area detection: conf={largest_detection.get('confidence', 0):.3f}, area={largest_detection.get('bbox_area', 0):.0f}")
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                # Update all_detections to only contain the largest bbox area detection
 | 
				
			||||||
 | 
					                all_detections = [largest_detection]
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                # Update regions_dict to reflect the selected detection
 | 
				
			||||||
 | 
					                class_name = largest_detection.get("class", "car")
 | 
				
			||||||
 | 
					                regions_dict = {
 | 
				
			||||||
 | 
					                    class_name: {
 | 
				
			||||||
 | 
					                        "confidence": largest_detection.get("confidence"),
 | 
				
			||||||
 | 
					                        "bbox": largest_detection.get("bbox", [0, 0, 0, 0]),
 | 
				
			||||||
 | 
					                        "detection": largest_detection
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                logger.debug(f"🔄 PIPELINE: Updated regions_dict for largest bbox area selection: {list(regions_dict.keys())}")
 | 
				
			||||||
 | 
					            elif stable_tracks:
 | 
				
			||||||
 | 
					                logger.debug(f"🔄 PIPELINE: Full pipeline mode - single detection, no area selection needed")
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                logger.debug(f"🔄 PIPELINE: No stable tracks yet, proceeding with confidence-based detection")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        # Debug: Save crops for debugging (disabled for production)
 | 
					        # Debug: Save crops for debugging (disabled for production)
 | 
				
			||||||
        # if regions_dict:
 | 
					        # if regions_dict:
 | 
				
			||||||
        #     try:
 | 
					        #     try:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue