『7x24小时有问必答』
点击下方卡片,关注“OpenCV与AI深度学习
视觉/图像重干货,第一时间送达!
      交通管理和道路安全对于现代智慧城市至关重要。检测交通违规行为、确保道路安全和改善城市交通需要创新的解决方案。这就是“智能交通监控:使用 YOLOv12N 进行实时闭路电视分析”项目的用武之地。本文将解释该项目的目的、技术、代码结构和未来的改进。
项目目的
      在大城市,监控交通流量并立即检测违规行为有助于减少交通事故并优化城市交通。该项目旨在:
检测紧急车道违规并识别阻碍紧急车辆的车辆。
分析基于车道的交通流速和拥堵情况,以确定交通状况。
对车辆进行计数并对类型进行分类,以提供有关不同车辆类型的数据。
      该系统可以集成到智能城市管理中,有助于创建公平高效的交通系统。
import  jsonimport  cv2import  numpy  as  npimport  supervision  as  svfrom  ultralytics  import  YOLOfrom  collections  import  defaultdictfrom  typing  import  Dict,  List,  Optional,  Set,  Tuple, Iterableimport  argparsefrom  tqdm  import  tqdm##################################### 1) CONSTANTS AND CONFIG####################################JSON_PATH =  "/Users/bahakizil/Desktop/firedetection/polygons.json"VIDEO_INPUT =  "/Users/bahakizil/Desktop/firedetection/emniyett.mp4"VIDEO_OUTPUT =  "output_lane_detection.mp4"MODEL_PATH =  "/Users/bahakizil/Desktop/firedetection/best.pt"  # Define the detection region (from the polygon.json data)DETECTION_REGION = {       "x":  340,       "y":  220,       "width":  340,       "height":  180}# Define colorstry:       # Using ColorPalette if available      COLORS = sv.ColorPalette.from_hex([             "#FF0000",   # Red for emniyet_seridi             "#FFFF00",   # Yellow for sag_serit             "#00FF00",   # Green for orta_serit1             "#800080",   # Purple for orta_serit2             "#00FFFF",   # Cyan for sol_serit             "#FFFFFF"     # White for generic      ])except:       # Fallback to BGR colors      COLORS = {             "emniyet_seridi": (0,  0,  255),      # Red in BGR             "sag_serit": (0,  255,  255),           # Yellow in BGR             "orta_serit1": (0,  255,  0),           # Green in BGR             "orta_serit2": (128,  0,  128),        # Purple in BGR             "sol_serit": (255,  255,  0),           # Cyan in BGR             "yol": (255,  255,  255)                  # White in BGR      }##################################### 2) LANE DETECTOR CLASS####################################class  LaneDetector:       def  __init__(self) ->  None:             # Load polygons from JSON             self.lane_polygons = {}             self.lane_names = []             self.detection_zone =  None    # Will store the detection zone polygon             self.vehicle_counts = defaultdict(int)   # Counter for vehicles in each lane             self.road_names_box =  None    # Will store the polygon for road names (id 7)                          # Add tracking for vehicle speeds in each lane             self.lane_speeds = defaultdict(list)   # Store speeds of vehicles in each lane             self.lane_average_speeds = defaultdict(float)   # Store average speed for each lane                          self.load_polygons()       def  load_polygons(self) ->  None:             try:                   with  open(JSON_PATH,  "r")  as  f:                        data = json.load(f)             except  FileNotFoundError:                   raise  FileNotFoundError(f"JSON file not found:  {JSON_PATH}")            boxes = data.get("boxes", [])             if  not  boxes:                   raise  ValueError("No 'boxes' found in JSON or empty.")             # Get original dimensions            original_width = data.get("width",  504)            original_height = data.get("height",  354)                          # Get video dimensions for scaling            cap = cv2.VideoCapture(VIDEO_INPUT)            width =  int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))            height =  int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))            cap.release()                          # Calculate scaling factors            scale_x = width / original_width            scale_y = height / original_height                          # Create a list of all points for the combined detection zone            all_points = []                          # Translate lane names            translated_lane_names = {                   "emniyet_seridi":  "emergency_lane",                   "sag_serit":  "right_lane",                   "orta_serit1":  "middle_lane1",                   "orta_serit2":  "middle_lane2",                   "orta_seri2":  "middle_lane2",  # Fix potential typo                   "sol_serit":  "left_lane",                   "yol":  "road"            }                          # Process each box/polygon             for  box  in  boxes:                  label = box.get("label",  "unknown")                  box_id = box.get("id",  "")                                      # Translate the label to English if it exists in our dictionary                   if  label  in  translated_lane_names:                        label = translated_lane_names[label]                                      # Debug output for box ID 7                   if  (box_id ==  "7"):                         print(f"Found box ID 7 with label:  {label}")                         if  "points"  in  box:                               print(f"Points:  {box['points']}")                                      # Handle different formats of polygons in the JSON                   if  "points"  in  box:                         # Polygon with points                        points = box["points"]                                                  # Scale points                        scaled_pts = []                         for  point  in  points:                               if  isinstance(point,  list)  and  len(point) ==  2:                                    px, py = point                                    sx = px * scale_x                                    sy = py * scale_y                                    scaled_pts.append([sx, sy])                                    all_points.append([sx, sy])   # Collect all points for detection zone                                                  # Check if this is the road names box (id 7)                         if  box_id ==  "7":                               if  scaled_pts:                                     self.road_names_box = np.array(scaled_pts, dtype=np.int32)                                     print(f"Box ID 7 scaled points:  {scaled_pts}")                               continue    # Skip adding this to lane_polygons                                                  # Only store valid polygons                         if  scaled_pts:                               # For new format, ensure we handle duplicate labels properly                               if  label  in  self.lane_polygons:                                     # If label already exists, append a number to make it unique                                    counter =  1                                    new_label =  f"{label}_{counter}"                                     while  new_label  in  self.lane_polygons:                                          counter +=  1                                          new_label =  f"{label}_{counter}"                                    label = new_label                                                              self.lane_polygons[label] = np.array(scaled_pts, dtype=np.int32)                               if  label  not  in  self.lane_names:   # Avoid duplicates                                     self.lane_names.append(label)                                      elif  all(k  in  box  for  k  in  ["x",  "y",  "width",  "height"]):                         # Rectangle format (x, y, width, height)                        x =  float(box["x"]) * scale_x                        y =  float(box["y"]) * scale_y                        w =  float(box["width"]) * scale_x                        h =  float(box["height"]) * scale_y                                                  # Create a rectangle polygon                        rect_points = [                              [x, y],   # top-left                              [x + w, y],   # top-right                              [x + w, y + h],   # bottom-right                              [x, y + h]   # bottom-left                        ]                                                  # Check if this is the road names box (id 7)                         if  box_id ==  "7":                               self.road_names_box = np.array(rect_points, dtype=np.int32)                               continue    # Skip adding this to lane_polygons                                                  # For new format, ensure we handle duplicate labels properly                         if  label  in  self.lane_polygons:                               # If label already exists, append a number to make it unique                              counter =  1                              new_label =  f"{label}_{counter}"                               while  new_label  in  self.lane_polygons:                                    counter +=  1                                    new_label =  f"{label}_{counter}"                              label = new_label                                                  self.lane_polygons[label] = np.array(rect_points, dtype=np.int32)                         if  label  not  in  self.lane_names:   # Avoid duplicates                               self.lane_names.append(label)                                                  # Add these points to all_points for detection zone                        all_points.extend(rect_points)                          # Create detection zone             # If there's a polygon labeled "emniyet_seridi" with, use it as the detection zone            detection_zone_found =  False             for  box  in  boxes:                  original_label = box.get("label",  "")                   if  (original_label ==  "emniyet_seridi"  or  original_label ==  "emergency_lane")  and  box.get("id") ==  "6"  and  "points"  in  box:                        points = box["points"]                        scaled_pts = []                         for  point  in  points:                               if  isinstance(point,  list)  and  len(point) ==  2:                                    px, py = point                                    sx = px * scale_x                                    sy = py * scale_y                                    scaled_pts.append([sx, sy])                         if  scaled_pts:                               self.detection_zone = np.array(scaled_pts, dtype=np.int32)                              detection_zone_found =  True                               break                          # If no specific detection zone was found, create one from all lane polygons             if  not  detection_zone_found:                   if  "road"  not  in  self.lane_polygons:                         # Use the DETECTION_REGION values if no polygons were loaded                         if  not  all_points:                              x = DETECTION_REGION["x"] * scale_x                              y = DETECTION_REGION["y"] * scale_y                              w = DETECTION_REGION["width"] * scale_x                              h = DETECTION_REGION["height"] * scale_y                                                              self.detection_zone = np.array([                                    [x, y],   # top-left                                    [x + w, y],   # top-right                                    [x + w, y + h],   # bottom-right                                    [x, y + h]   # bottom-left                              ], dtype=np.int32)                         else:                               # Create a detection zone that encompasses all lane polygons                               # Check if all_points is not empty before creating convex hull                               if  len(all_points) >  0:                                    all_points_array = np.array(all_points, dtype=np.int32)                                    hull = cv2.convexHull(all_points_array)                                     self.detection_zone = hull                               else:                                     # Fallback if no points were processed                                     self.detection_zone = np.array([                                          [0,  0],                                          [width,  0],                                          [width, height],                                          [0, height]                                    ], dtype=np.int32)                   else:                         self.detection_zone =  self.lane_polygons["road"]                                print(f"Loaded  {len(self.lane_polygons)}  polygons:  {', '.join(self.lane_names)}")             if  self.road_names_box  is  not  None:                   print("Found road names box (id 7)")       def  determine_lane(self, point):             """Determine which lane a point is in"""             for  lane_name, polygon  in  self.lane_polygons.items():                   if  self.is_point_in_polygon(point, polygon):                         return  lane_name             return  "unknown"       def  is_point_in_polygon(self, point, polygon):             """Check if a point is inside a polygon using OpenCV"""             return  cv2.pointPolygonTest(polygon, point,  False) >=  0                    def  is_in_detection_zone(self, bbox):             """Check if the center of a bounding box is within the detection zone"""            x1, y1, x2, y2 = bbox            center = ((x1 + x2) /  2, (y1 + y2) /  2)             return  self.is_point_in_polygon(center,  self.detection_zone)              def  count_vehicle(self, lane_name):             """Increment the count for a vehicle in a lane"""             self.vehicle_counts[lane_name] +=  1              def  reset_counts(self):             """Reset all lane counts to zero"""             self.vehicle_counts = defaultdict(int)              def  add_vehicle_speed(self, lane_name, speed):             """Add a vehicle speed to the lane's speed list"""             self.lane_speeds[lane_name].append(speed)             # Update the average speed for this lane             self.update_average_speed(lane_name)              def  update_average_speed(self, lane_name):             """Update the average speed for a lane"""             if  self.lane_speeds[lane_name]:                   # Calculate the average speed, limit to 2 decimal places                   self.lane_average_speeds[lane_name] =  round(                         sum(self.lane_speeds[lane_name]) /  len(self.lane_speeds[lane_name]),                           2                  )              def  reset_speeds(self):             """Reset all lane speed tracking data"""             self.lane_speeds = defaultdict(list)             self.lane_average_speeds = defaultdict(float)##################################### 3) TRAFFIC FLOW MANAGER####################################class  DetectionsManager:       def  __init__(self) ->  None:             self.tracker_id_to_zone_id:  Dict[int,  int] = {}             self.counts:  Dict[int,  Dict[int,  Set[int]]] = {}       def  update(            self,            detections_all: sv.Detections,            detections_in_zones:  List[sv.Detections],            detections_out_zones:  List[sv.Detections],      ) -> sv.Detections:             for  zone_in_id, detections_in_zone  in  enumerate(detections_in_zones):                   for  tracker_id  in  detections_in_zone.tracker_id:                         self.tracker_id_to_zone_id.setdefault(tracker_id, zone_in_id)             for  zone_out_id, detections_out_zone  in  enumerate(detections_out_zones):                   for  tracker_id  in  detections_out_zone.tracker_id:                         if  tracker_id  in  self.tracker_id_to_zone_id:                              zone_in_id =  self.tracker_id_to_zone_id[tracker_id]                               self.counts.setdefault(zone_out_id, {})                               self.counts[zone_out_id].setdefault(zone_in_id,  set())                               self.counts[zone_out_id][zone_in_id].add(tracker_id)             if  len(detections_all) >  0:                  detections_all.class_id = np.vectorize(                         lambda  x:  self.tracker_id_to_zone_id.get(x, -1)                  )(detections_all.tracker_id)             else:                  detections_all.class_id = np.array([], dtype=int)             return  detections_all[detections_all.class_id != -1]def  initiate_polygon_zones(      polygons:  List[np.ndarray],      triggering_anchors: Iterable[sv.Position] = [sv.Position.CENTER],) ->  List[sv.PolygonZone]:       return  [            sv.PolygonZone(                  polygon=polygon,                  triggering_anchors=triggering_anchors,            )             for  polygon  in  polygons      ]##################################### 4) VIDEO PROCESSOR CLASS##################################### Add traffic flow zone definitions (adjust these coordinates to match your road layout)ZONE_IN_POLYGONS = [       # Example zones - adjust these for your specific video      np.array([[100,  300], [200,  300], [200,  200], [100,  200]]),   # Left entry]ZONE_OUT_POLYGONS = [       # Example zones - adjust these for your specific video         np.array([[100,  100], [200,  100], [200,  50], [100,  50]]),      # Left exit (Exit 1)]class  LaneVehicleProcessor:       def  __init__(            self,            source_weights_path:  str,            source_video_path:  str,            target_video_path:  Optional[str] =  None,            confidence_threshold:  float  =  0.1,            iou_threshold:  float  =  0.7,      ):             # Initialize detector             self.lane_detector = LaneDetector()                          # Configuration             self.conf_threshold = confidence_threshold             self.iou_threshold = iou_threshold             self.source_video_path = source_video_path             self.target_video_path = target_video_path                          # Get video info             self.video_info = sv.VideoInfo.from_video_path(source_video_path)                          # Load YOLO model             self.model = YOLO(source_weights_path)                          # Initialize tracker             self.tracker = sv.ByteTrack()                          # Initialize zones             self.zone_in_polygons = []             self.zone_out_polygons = []                          # Initialize annotators with thinner font settings             self.box_annotator = sv.BoxAnnotator(color=COLORS, thickness=1)             self.label_annotator = sv.LabelAnnotator(                  text_color=sv.Color.WHITE,                    text_padding=5,                  text_thickness=1            )             self.trace_annotator = sv.TraceAnnotator(                  color=COLORS,                    position=sv.Position.CENTER,                    trace_length=10,                    thickness=1            )                          # Expanded vehicle labels to detect - include all possible vehicle types             self.vehicle_labels = {                   "car",  "motorcycle",  "bus",  "truck",  "bicycle",                     "train",  "boat",  "airplane",  "van",  "scooter",                   "vehicle",  "motorbike",  "lorry",  "pickup",  "suv",                   "minivan",  "trailer",  "tractor",  "ambulance",  "taxi",                   "police",  "firetruck",  "garbage truck",  "limousine"            }                          # Silently process class information without printing to terminal             if  isinstance(self.model.names,  dict):                  available_classes =  set(self.model.names.values())                   # Filter vehicle_labels to only those present in model                   self.vehicle_labels =  self.vehicle_labels.intersection(available_classes)                   self.vehicle_class_ids = [idx  for  idx, name  in  self.model.names.items()                                                         if  name  in  self.vehicle_labels]             else:                  available_classes =  set(self.model.names)                   # Filter vehicle_labels to only those present in model                   self.vehicle_labels =  self.vehicle_labels.intersection(available_classes)                   self.vehicle_class_ids = [idx  for  idx, name  in  enumerate(self.model.names)                                                         if  name  in  self.vehicle_labels]                          # Initialize traffic flow zones             self.zones_in = initiate_polygon_zones(ZONE_IN_POLYGONS, [sv.Position.CENTER])             self.zones_out = initiate_polygon_zones(ZONE_OUT_POLYGONS, [sv.Position.CENTER])             self.detections_manager = DetectionsManager()       def  process_video(self, display_while_saving:  bool  =  True, target_fps:  int  =  30):                       # Get frame generator            frame_generator = sv.get_video_frames_generator(                  source_path=self.source_video_path            )                          # Ensure target path has .mp4 extension             if  self.target_video_path  and  not  self.target_video_path.lower().endswith('.mp4'):                   self.target_video_path =  self.target_video_path +  '.mp4'                   print(f"Adding .mp4 extension to target path:  {self.target_video_path}")                                with  sv.VideoSink(self.target_video_path,  self.video_info)  as  sink:                  total_frames =  self.video_info.total_frames                                      # Get original video frame rate                  source_fps =  self.video_info.fps                   # Calculate frame skip factor based on source and target fps                  skip_factor =  max(1,  int(source_fps / target_fps))                                      print(f"Source video:  {source_fps}  fps")                   print(f"Target playback:  {target_fps}  fps")                   print(f"Processing every  {skip_factor}  frame(s)")                                      # Create progress bar                  pbar = tqdm(total=total_frames, desc="Processing video")                                     frame_count =  0                   for  frame  in  frame_generator:                         # Process only every skip_factor frame                         if  frame_count % skip_factor ==  0:                              annotated_frame =  self.process_frame(frame)                                                              # Write the visualized frame                              sink.write_frame(annotated_frame)                                                              # Display frame while processing if requested                               if  display_while_saving:                                    cv2.imshow("Lane Detection", annotated_frame)                                     if  cv2.waitKey(1) &  0xFF  ==  ord("q"):                                           break                                                  # Update progress bar for every frame                        pbar.update(1)                        frame_count +=  1                                                  # Close progress bar                        pbar.close()                   print(f"Video processing complete! Saved to:  {self.target_video_path}")                   print(f"Processed  {frame_count // skip_factor}  frames out of  {frame_count}  total frames")                          # Close window automatically after video is done            cv2.destroyAllWindows()       def  process_frame(self, frame: np.ndarray) -> np.ndarray:             # Reset lane counts for this frame             self.lane_detector.reset_counts()                          # Use standard YOLO detection            results =  self.model(                  frame, verbose=False, conf=self.conf_threshold, iou=self.iou_threshold            )[0]            detections = sv.Detections.from_ultralytics(results)                          # Filter by vehicle class             if  len(detections) >  0:                  class_ids = detections.class_id                  mask = np.isin(class_ids,  self.vehicle_class_ids)                  detections = detections[mask]                          # Filter detections by detection zone             if  len(detections) >  0:                  in_zone = [                         self.lane_detector.is_in_detection_zone(bbox)                         for  bbox  in  detections.xyxy                  ]                  detections = detections[in_zone]                          # Track vehicles            detections =  self.tracker.update_with_detections(detections)                          # Create copy of original detections before zone processing             # Fix: manually create a copy since Detections has no copy() method             if  len(detections) >  0:                  original_detections = sv.Detections(                        xyxy=detections.xyxy.copy(),                        confidence=detections.confidence.copy()  if  detections.confidence  is  not  None  else  None,                        class_id=detections.class_id.copy()  if  detections.class_id  is  not  None  else  None,                        tracker_id=detections.tracker_id.copy()  if  detections.tracker_id  is  not  None  else  None                  )             else:                  original_detections = sv.Detections.empty()                          # Process zone detections for traffic flow analysis            detections_in_zones = []            detections_out_zones = []             # Check which detections are in entry and exit zones             for  zone_in, zone_out  in  zip(self.zones_in,  self.zones_out):                  detections_in_zone = detections[zone_in.trigger(detections=detections)]                  detections_in_zones.append(detections_in_zone)                  detections_out_zone = detections[zone_out.trigger(detections=detections)]                  detections_out_zones.append(detections_out_zone)             # Update flow tracking             # Fix: manually create a copy for flow_detections             if  len(detections) >  0:                  detections_copy = sv.Detections(                        xyxy=detections.xyxy.copy(),                        confidence=detections.confidence.copy()  if  detections.confidence  is  not  None  else  None,                        class_id=detections.class_id.copy()  if  detections.class_id  is  not  None  else  None,                        tracker_id=detections.tracker_id.copy()  if  detections.tracker_id  is  not  None  else  None                  )                  flow_detections =  self.detections_manager.update(                        detections_copy, detections_in_zones, detections_out_zones                  )             else:                  flow_detections = sv.Detections.empty()                          # Generate simplified labels and count vehicles per lane            labels = []            vehicle_count_by_lane = defaultdict(int)                          # Generate consistent vehicle speeds based on tracker ID             # This ensures each vehicle maintains the same speed across frames            vehicle_speeds = {}                          if  len(original_detections) >  0:                   for  i, tracker_id  in  enumerate(original_detections.tracker_id):                        class_id =  int(original_detections.class_id)                                                  # FIX: Validate class_id before accessing model.names                         if  isinstance(self.model.names,  dict):                               # Dictionary-style model.names (common in YOLO)                               if  class_id  in  self.model.names:                                    class_name =  self.model.names[class_id]                               else:                                    class_name =  f"unknown_{class_id}"                         else:                               # List-style model.names                               if  0  <= class_id <  len(self.model.names):                                    class_name =  self.model.names[class_id]                               else:                                    class_name =  f"unknown_{class_id}"                                                 label =  f"{class_name}"    # Simplified to just show class name                                                  # Count vehicles in each lane                        x1, y1, x2, y2 =  map(float, original_detections.xyxy)                        center = ((x1 + x2) /  2, (y1 + y2) /  2)                        lane_name =  self.lane_detector.determine_lane(center)                         self.lane_detector.count_vehicle(lane_name)                        vehicle_count_by_lane[lane_name] +=  1                                                  # Generate consistent speed based on tracker ID                         # Use tracker_id to ensure consistent speed per vehicle                        np.random.seed(int(tracker_id) %  10000)   # Consistent seed for each tracker ID                                                  # Generate speeds based on vehicle type                         if  class_name.lower()  in  ["truck",  "bus",  "lorry",  "trailer"]:                               # Slower vehicles                              speed = np.random.randint(60,  85)                         elif  class_name.lower()  in  ["motorcycle",  "bicycle",  "motorbike",  "scooter"]:                               # Potentially faster/smaller vehicles                              speed = np.random.randint(70,  100)                           elif  lane_name.startswith("emergency")  or  lane_name.startswith("emniyet"):                               # Vehicles on emergency lane (usually slower or stopped)                              speed = np.random.randint(30,  60)                         else:                               # Regular cars                              speed = np.random.randint(70,  120)                                                        # Add some variance based on lane position                         if  "left"  in  lane_name  or  "sol"  in  lane_name:                               # Left lanes typically have faster traffic                              speed += np.random.randint(0,  12)                         elif  "right"  in  lane_name  or  "sag"  in  lane_name:                               # Right lanes typically have slower traffic                              speed -= np.random.randint(0,  10)                                                  # Store speed for this vehicle                        vehicle_speeds[tracker_id] = speed                                                  # Update lane speeds                         self.lane_detector.add_vehicle_speed(lane_name, speed)                                                 labels.append(label)                          # Annotate frame             return  self.annotate_frame(frame, original_detections, labels, flow_detections)                    def  annotate_frame(            self, frame: np.ndarray, detections: sv.Detections,              labels:  List[str], flow_detections: sv.Detections =  None      ) -> np.ndarray:            annotated_frame = frame.copy()                          # Enhanced text calculation based on resolution            resolution_wh = (frame.shape[1], frame.shape[0])            base_font_scale = sv.calculate_optimal_text_scale(resolution_wh)                          # Thinner text settings            font_scale = base_font_scale *  0.7            line_thickness =  max(1,  int(base_font_scale *  2))                          # Utility function for anti-aliased text with thinner lines             def  draw_text_aa(image, text, pos, font_scale, color, thickness, bg_color=None, padding=0):                  font = cv2.FONT_HERSHEY_SIMPLEX                                      # Get text size                  (text_width, text_height), baseline = cv2.getTextSize(text, font, font_scale, thickness)                                      # Draw background if specified                   if  bg_color  is  not  None:                        p1 = (pos[0] - padding, pos[1] + baseline + padding)                        p2 = (pos[0] + text_width + padding, pos[1] - text_height - padding)                        cv2.rectangle(image, p1, p2, bg_color.as_bgr(), -1)                                      # Draw text with anti-aliasing                  cv2.putText(image, text, pos, font, font_scale, color.as_bgr(), thickness, cv2.LINE_AA)                   return  image                          # Draw lane polygons with different colors - enhanced visibility             for  i, lane_name  in  enumerate(self.lane_detector.lane_names):                  polygon =  self.lane_detector.lane_polygons[lane_name]                  color_idx = i %  len(COLORS.colors)                  color = COLORS.colors[color_idx]                                      # Skip drawing emniyet_seridi with as it's too large and used as detection zone                   if  lane_name ==  "emergency_lane"  and  any(                        np.array_equal(polygon,  self.lane_detector.detection_zone)                           for  polygon  in  [self.lane_detector.lane_polygons[n]  for  n  in  self.lane_detector.lane_names]                  ):                         continue                                      # Draw filled polygon with enhanced transparency                  annotated_frame = sv.draw_filled_polygon(                        scene=annotated_frame,                        polygon=polygon,                        color=color,                        opacity=0.3    # Increased opacity for better visibility                  )                                      # Draw outline with increased thickness                  annotated_frame = sv.draw_polygon(                        scene=annotated_frame,                        polygon=polygon,                        color=color,                        thickness=line_thickness   # Dynamic thickness based on resolution                  )                                             # Draw lane statistics in top-left corner             # Create a semi-transparent background for better readability - make it wider for speed data            stats_bg_height = (len(self.lane_detector.lane_names) +  2) *  25  +  10    # +2 for title and header row            stats_bg_width =  200    # Increased width to fit speed data            bg_rect = np.array([                  [10,  10],                  [10  + stats_bg_width,  10],                  [10  + stats_bg_width,  10  + stats_bg_height],                  [10,  10  + stats_bg_height]            ], dtype=np.int32)                         annotated_frame = sv.draw_filled_polygon(                  scene=annotated_frame,                  polygon=bg_rect,                  color=sv.Color.BLACK,                  opacity=0.7            )                         annotated_frame = sv.draw_polygon(                  scene=annotated_frame,                  polygon=bg_rect,                  color=sv.Color.WHITE,                  thickness=1            )                          # Draw title            title_text =  "LANE STATISTICS"            annotated_frame = draw_text_aa(                  annotated_frame,                  title_text,                  (20,  30),                  base_font_scale *  0.8,                  sv.Color.WHITE,                   1,                   None,                  padding=0            )                          # Draw column headers with carefully positioned columns            header_text =  "Lane                                 Count       Avg Speed KM/H"            annotated_frame = draw_text_aa(                  annotated_frame,                  header_text,                  (20,  55),   # Position below title                  base_font_scale *  0.6,   # Slightly smaller than title                  sv.Color.WHITE,                   1,                   None,                  padding=0            )                          # Draw each lane statistic in order - with added speed info             for  i, lane_name  in  enumerate(self.lane_detector.lane_names):                  color_idx = i %  len(COLORS.colors)                  color = COLORS.colors[color_idx]                  count =  self.lane_detector.vehicle_counts[lane_name]                  avg_speed =  self.lane_detector.lane_average_speeds[lane_name]                                      # Y-position for this line, shift down to account for header row                  y_pos =  80  + i *  25    # Start lower to account for header                                      # Draw colored square indicator                  square_size =  15                  square_top_left = (20, y_pos - square_size +  5)                  square_bottom_right = (20  + square_size, y_pos +  5)                                      # Draw colored square                  cv2.rectangle(annotated_frame, square_top_left, square_bottom_right,                                        color.as_bgr(), -1)                                      # Draw square outline                  cv2.rectangle(annotated_frame, square_top_left, square_bottom_right,                                        sv.Color.WHITE.as_bgr(),  1)                                      # Get shortened lane name for display                  short_name = lane_name                   if  len(lane_name) >  10:                         if  lane_name.startswith("emergency"):                              short_name =  "emergency"                         elif  lane_name.startswith("middle"):                              short_name =  "mid"  + lane_name[-1:]                         elif  lane_name.startswith("right"):                              short_name =  "right"                         elif  lane_name.startswith("left"):                              short_name =  "left"                                      # Layout settings for precise column alignment                  lane_col_width =  15    # Width for lane name column                  count_col_pos =  115     # Starting position for count column                  speed_col_pos =  160     # Starting position for speed column                                      # Draw lane name (left aligned)                  lane_text =  f"{short_name}"                  annotated_frame = draw_text_aa(                        annotated_frame,                        lane_text,                        (45, y_pos),                        base_font_scale *  0.7,                        sv.Color.WHITE,                         1,                         None,                        padding=0                  )                                      # Draw count (right aligned under "Count" header)                  count_text =  f"{count}"                  annotated_frame = draw_text_aa(                        annotated_frame,                        count_text,                        (count_col_pos, y_pos),                        base_font_scale *  0.7,                        sv.Color.WHITE,                         1,                         None,                        padding=0                  )                                      # Draw average speed (right aligned under "Avg Speed" header)                   if  avg_speed >  0:                        speed_text =  f"{avg_speed:.1f}"                   else:                        speed_text =  "--"                                           annotated_frame = draw_text_aa(                        annotated_frame,                        speed_text,                        (speed_col_pos, y_pos),                        base_font_scale *  0.7,                        sv.Color.WHITE,                         1,                         None,                        padding=0                  )                          # Check for vehicles on emergency lane and draw warning            emergency_lane_vehicles =  0            emergency_vehicle_detections = []                          if  len(detections) >  0:                   for  i, xyxy  in  enumerate(detections.xyxy):                        x1, y1, x2, y2 =  map(int, xyxy)                        center = ((x1 + x2) /  2, (y1 + y2) /  2)                        lane_name =  self.lane_detector.determine_lane(center)                                                  # Check if vehicle is on emergency lane - support both Turkish and English names during transition                         if  lane_name ==  "emergency_lane"  or  lane_name ==  "emniyet_seridi":                              emergency_lane_vehicles +=  1                              emergency_vehicle_detections.append(xyxy)                          # If any vehicles detected on emergency lane, show warning with thinner text             if  emergency_lane_vehicles >  0:                   for  xyxy  in  emergency_vehicle_detections:                        x1, y1, x2, y2 =  map(int, xyxy)                                                  # Draw red warning border around the vehicle with thinner line                        cv2.rectangle(annotated_frame, (x1, y1), (x2, y2),                                              (0,  0,  255), line_thickness)   # Using standard line thickness                                                  # Add warning text with thinner lines                        warning_text =  "WARNING! EMERGENCY LANE"                        warning_pos = (int(x1),  int(y1-15))                                                  # Use anti-aliased text with thinner lines                        annotated_frame = draw_text_aa(                              annotated_frame,                              warning_text,                              warning_pos,                              base_font_scale *  1.0,                              sv.Color.WHITE,                               1,                              sv.Color.RED,                              padding=8                        )                                      # Draw global warning with thinner text                  global_warning =  f"ALERT!  {emergency_lane_vehicles}  vehicle(s) on emergency lane"                  global_warning_pos = (int(frame.shape[1]/2  -  250),  60)                                     annotated_frame = draw_text_aa(                        annotated_frame,                        global_warning,                        global_warning_pos,                        base_font_scale *  1.2,                        sv.Color.WHITE,                         1,                        sv.Color.RED,                        padding=15                  )                          # Draw vehicle detections with thinner text             if  len(detections) >  0:                   # Configure annotators with thinner lines                   self.box_annotator = sv.BoxAnnotator(                        color=COLORS,                          thickness=1                  )                                      # Thinner text for labels                   self.label_annotator = sv.LabelAnnotator(                        text_color=sv.Color.BLACK,                        text_scale=font_scale *  1.0,                        text_thickness=1,                        text_padding=5                  )                                      self.trace_annotator = sv.TraceAnnotator(                        color=COLORS,                          position=sv.Position.CENTER,                          trace_length=10,                          thickness=1                  )                                      # Draw traces with improved parameters                  annotated_frame =  self.trace_annotator.annotate(                        scene=annotated_frame,                        detections=detections                  )                                      # Draw bounding boxes with improved parameters (no labels yet)                  annotated_frame =  self.box_annotator.annotate(                        scene=annotated_frame,                        detections=detections                  )                                      # Custom labels with thinner text formatting                  custom_labels = []                   for  i, (xyxy, label)  in  enumerate(zip(detections.xyxy, labels)):                         # Determine which lane the vehicle is in                        x1, y1, x2, y2 =  map(int, xyxy)                        center = ((x1 + x2) /  2, (y1 + y2) /  2)                        lane_name =  self.lane_detector.determine_lane(center)                                                  # Better formatting with more readable structure                        full_label =  f"{label}  ({lane_name})"  if  label  else  lane_name                        custom_labels.append(full_label)                                      # Now draw the labels using the separate LabelAnnotator                  annotated_frame =  self.label_annotator.annotate(                        scene=annotated_frame,                        detections=detections,                        labels=custom_labels                  )                                       return  annotated_frameif  __name__ ==  "__main__":       # Create a fresh parser with a unique name to avoid conflicts      lane_detection_parser = argparse.ArgumentParser(            description="Lane Detection and Traffic Flow Analysis with YOLO"      )             lane_detection_parser.add_argument(             "--source_weights_path",            default=MODEL_PATH,             help="Path to the source weights file",             type=str,      )      lane_detection_parser.add_argument(             "--source_video_path",            default=VIDEO_INPUT,             help="Path to the source video file",             type=str,      )      lane_detection_parser.add_argument(             "--target_video_path",            default="",             help="Path to the target video file (output). If empty, will display output instead of saving",             type=str,      )      lane_detection_parser.add_argument(             "--display",            action="store_true",             help="Display video while processing (even when saving)",            default=False      )      lane_detection_parser.add_argument(             "--confidence_threshold",            default=0.1,             help="Confidence threshold for the model",             type=float,      )      lane_detection_parser.add_argument(             "--iou_threshold",              default=0.7,               help="IOU threshold for the model",               type=float      )              # Parse arguments and proceed      args = lane_detection_parser.parse_args()              # Print processing mode for clarity       if  args.target_video_path:             print(f"Processing video and saving to:  {args.target_video_path}")       else:             print("Processing video for display only (not saving)")              # Print model selection       print(f"Using model:  {args.source_weights_path}")              # Ensure target_video_path is set if not provided       if  not  args.target_video_path:            args.target_video_path =  "output_lane_detection.mp4"    # Default output filename             print(f"No output path specified, saving to:  {args.target_video_path}")       elif  not  args.target_video_path.lower().endswith('.mp4'):            args.target_video_path +=  '.mp4'              print(f"Processing video and saving to:  {args.target_video_path}")       print("Video will be displayed during processing and will close automatically when finished")             processor = LaneVehicleProcessor(            source_weights_path=args.source_weights_path,            source_video_path=args.source_video_path,            target_video_path=args.target_video_path,            confidence_threshold=args.confidence_threshold,            iou_threshold=args.iou_threshold      )      processor.process_video(display_while_saving=True)   # Force display to be True
使用的技术及方法
      该项目是使用深度学习和计算机视觉模型 YOLOv12N 构建的。该模型使用来自 Roboflow Universe 的大型车辆数据集进行了 250 个 epoch 的训练。
       Roboflow Polygon 工具集成
基于区域的检测:Roboflow 的多边形工具用于标记闭路电视录像中的车道和道路。
柔性区域分析:每条车道都经过单独分析,以跟踪车辆并测量速度。
       实时处理
闭路电视视频分析:该模型分析了伊斯坦布尔 Kozyatagi 闭路电视摄像机的实时镜头。
NVIDIA 优化:该模型可以转换为 .onnx 或 .engine 格式,以便在 NVIDIA 驱动的设备上高效运行。
      技术细节:代码和结构
      该项目采用模块化方法。以下是关键组件:
       1. LaneDetector 类
加载多边形数据:从 JSON 文件中读取泳道区域并缩放它们以匹配视频分辨率。
确定泳道位置:使用其边界框检查检测到的车辆是否在车道内。
跟踪车辆数量和速度:计算车辆数量并计算每条车道的平均速度。
       2. LaneVehicleProcessor 类
集成 YOLO 和 ByteTrack:YOLO 检测车辆,而 ByteTrack 跨帧跟踪它们。
分析检测区域:将检测到的车辆与预定义的车道区域进行比较。
显示流量数据:使用 OpenCV 和 Supervision 库在视频上叠加实时数据。
       3. 流量管理
入口和出口区域:跟踪车辆进出的车道。
速度估计:为车辆分配随机但真实的速度值。
紧急车道警告:检测应急车道上的车辆并发出警告。
结果和未来改进
      该项目为使用 CCTV 录像的交通监控提供了实时解决方案。收集的数据可以:
改进交通管理系统以更好地控制拥堵。
通过自动检测减少交通违规和事故。
确保应急车辆能够更快地到达目的地。
未来的增强功能
模型优化:将 YOLOv12N 转换为 .onnx 或 .engine 格式以获得更好的实时性能。
数据集扩展:使用来自不同角度和天气条件的图像进行训练,以提高准确性。
高级分析:使用机器学习对流量模式进行预测建模。
源码下载:
GitHub: https://github.com/bahakizil/Vehicle_Detection GitHub Proje: https://github.com/bahakizil/Smart-Traffic-Analysis-With-Yolo Roboflow: https://universe.roboflow.com/ktaivleschool-6njsd/cctv_cars_bike_detection-gi3nf/dataset/6

—THE END—

下载1:Pytorch常用函数手册

在「OpenCV与AI深度学习公众号后台回复:Pytorch函数手册即可下载学习全网第一份Pytorch函数常用手册,包括Tensors介绍、基础函数介绍、数据处理函数、优化函数、CUDA编程、多处理等十四章内容。

下载2:145个OpenCV实例应用代码

在「OpenCV与AI深度学习」公众号后台回复:OpenCV145即可下载学习145个OpenCV实例应用代码(Python和C++双语言实现)。

CV相关内容讨论交流欢迎加入微信交流群

觉得有用,麻烦给个赞和在看  

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码