trannam1084's picture
Update app.py
064f359 verified
Raw
History Blame Contribute Delete
6.06 kB
import os
import tempfile
import cv2
import numpy as np
import gradio as gr
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolo11n.pt")
CLASS_NAMES_DICT = model.model.names
SELECTED_CLASS_NAMES = ['car', 'bus', 'truck', 'motorcycle']
SELECTED_CLASS_IDS = [
{value: key for key, value in CLASS_NAMES_DICT.items()}[name]
for name in SELECTED_CLASS_NAMES
]
box_annotator = sv.BoxAnnotator(thickness=4)
label_annotator = sv.LabelAnnotator(text_thickness=2, text_scale=1.5, text_color=sv.Color.BLACK)
trace_annotator = sv.TraceAnnotator(thickness=4, trace_length=50)
line_zone_annotator = sv.LineZoneAnnotator(
thickness=4, text_thickness=2, text_scale=2,
display_in_count=False, display_out_count=False
)
def process_video(video_path, orientation="Ngang"):
"""Xử lý video: nhận dạng phương tiện và trả về video đã annotate."""
if video_path is None:
return None
if isinstance(video_path, dict):
video_path = video_path.get("path", video_path)
video_info = sv.VideoInfo.from_video_path(video_path)
w, h = video_info.width, video_info.height
ori = str(orientation).strip().lower()
is_horizontal = ori.startswith("n") or ori.startswith("h")
if is_horizontal:
line_pos = int(h * 0.5)
line_start = sv.Point(int(w * 0.005), line_pos)
line_end = sv.Point(int(w * 0.995), line_pos)
else:
line_pos = int(w * 0.5)
line_start = sv.Point(line_pos, int(h * 0.005))
line_end = sv.Point(line_pos, int(h * 0.995))
line_zone = sv.LineZone(start=line_start, end=line_end)
byte_tracker = sv.ByteTrack(
track_activation_threshold=0.25,
lost_track_buffer=30,
minimum_matching_threshold=0.8,
frame_rate=video_info.fps or 30,
minimum_consecutive_frames=3
)
byte_tracker.reset()
previous_positions = {}
class_counts = {name: 0 for name in SELECTED_CLASS_NAMES}
crossed_ids = set()
def callback(frame: np.ndarray, index: int) -> np.ndarray:
nonlocal previous_positions, class_counts, crossed_ids
results = model(frame, verbose=False)[0]
detections = sv.Detections.from_ultralytics(results)
detections = detections[np.isin(detections.class_id, SELECTED_CLASS_IDS)]
detections = byte_tracker.update_with_detections(detections)
if detections.tracker_id is not None:
xyxy = detections.xyxy
for i in range(len(detections)):
tid = int(detections.tracker_id[i])
cls_id = int(detections.class_id[i])
cls_name = CLASS_NAMES_DICT[cls_id]
cx = (xyxy[i, 0] + xyxy[i, 2]) / 2
cy = (xyxy[i, 1] + xyxy[i, 3]) / 2
curr_coord = cy if is_horizontal else cx
if tid in previous_positions:
prev_coord = previous_positions[tid]
if prev_coord < line_pos and curr_coord > line_pos and (tid, 'pos') not in crossed_ids:
crossed_ids.add((tid, 'pos'))
class_counts[cls_name] = class_counts.get(cls_name, 0) + 1
elif prev_coord > line_pos and curr_coord < line_pos and (tid, 'neg') not in crossed_ids:
crossed_ids.add((tid, 'neg'))
class_counts[cls_name] = class_counts.get(cls_name, 0) + 1
previous_positions[tid] = curr_coord
labels = [
f"#{tid} {CLASS_NAMES_DICT[cid]} {conf:0.2f}"
for conf, cid, tid in zip(
detections.confidence, detections.class_id, detections.tracker_id
)
]
annotator_frame = frame.copy()
annotator_frame = trace_annotator.annotate(scene=annotator_frame, detections=detections)
annotator_frame = box_annotator.annotate(scene=annotator_frame, detections=detections)
annotator_frame = label_annotator.annotate(scene=annotator_frame, detections=detections, labels=labels)
line_zone.trigger(detections)
annotator_frame = line_zone_annotator.annotate(annotator_frame, line_counter=line_zone)
fh, fw, _ = annotator_frame.shape
box_w, box_h = 280, 50 + len(SELECTED_CLASS_NAMES) * 28
x0, y0 = fw - box_w - 20, 20
overlay = annotator_frame.copy()
cv2.rectangle(overlay, (x0, y0), (x0 + box_w, y0 + box_h), (0, 0, 0), -1)
annotator_frame = cv2.addWeighted(overlay, 0.6, annotator_frame, 0.4, 0)
total = sum(class_counts.values())
cv2.putText(annotator_frame, f'Total: {total}', (x0 + 10, y0 + 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
for i, cls_name in enumerate(SELECTED_CLASS_NAMES):
cnt = class_counts.get(cls_name, 0)
cv2.putText(annotator_frame, f'{cls_name.capitalize()}: {cnt}',
(x0 + 10, y0 + 60 + i * 28),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
return annotator_frame
output_path = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False).name
sv.process_video(
source_path=video_path,
target_path=output_path,
callback=callback
)
return output_path
with gr.Blocks(title="Object Detection", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🚗 Nhận dạng phương tiện (YOLOv8 + ByteTrack)")
gr.Markdown("Tải lên video, hệ thống sẽ nhận dạng phương tiện trong video.")
with gr.Row():
video_input = gr.Video(label="Video đầu vào")
video_output = gr.Video(label="Video đã xử lý")
orientation_input = gr.Radio(
choices=["Ngang", "Dọc"],
value="Ngang",
label="Vị trí line"
)
btn = gr.Button("▶️ Xử lý video")
btn.click(fn=process_video, inputs=[video_input, orientation_input], outputs=video_output)
gr.Markdown("""
### Author: Trần Hải Nam - 223332840
""")
if __name__ == "__main__":
demo.launch()