File size: 4,487 Bytes
c952320
 
 
 
41811d0
c952320
41811d0
c952320
 
 
 
 
 
e074709
c952320
 
 
e39fd29
e074709
 
c952320
e39fd29
c952320
 
 
 
 
e074709
c952320
 
41811d0
e074709
c952320
 
 
 
 
 
 
 
41811d0
c952320
 
e074709
c952320
 
 
 
 
 
 
 
e074709
 
c952320
 
 
 
 
41811d0
c952320
 
 
41811d0
c952320
 
 
 
 
 
 
 
 
41811d0
c952320
 
 
 
 
 
 
e074709
c952320
 
 
 
 
 
 
 
 
 
 
 
41811d0
e074709
 
41811d0
 
e074709
 
 
 
 
 
41811d0
c952320
 
 
e074709
c952320
 
e074709
 
e39fd29
41811d0
c952320
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import gradio as gr
import cv2
from ultralytics import YOLO
import os
from moviepy.editor import VideoFileClip

# 1. Khởi tạo mô hình
model = YOLO('yolov8n.pt')

def process_video(video_path):
    if not video_path:
        return None

    # --- CẤU HÌNH BIẾN ĐẾM (Dựa trên code gốc của bạn) ---
    vehicle_classes = ['car', 'motorcycle', 'bus', 'truck']
    vehicle_class_ids = [2, 3, 5, 7] 
    vehicle_count = {cls: 0 for cls in vehicle_classes}
    
    track_history = {}  
    counted_ids = set() 

    # Đọc video đầu vào
    cap = cv2.VideoCapture(video_path)
    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    
    # Vạch đếm ở 60% chiều cao màn hình
    line_y = int(height * 0.6) 

    # File tạm trung gian (định dạng mp4v)
    temp_output = 'temp_raw.mp4'
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter(temp_output, fourcc, fps, (width, height))

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        # Thực hiện Tracking
        results = model.track(frame, classes=vehicle_class_ids, persist=True, verbose=False)

        # Vẽ vạch đếm màu đỏ
        cv2.line(frame, (0, line_y), (width, line_y), (0, 0, 255), 3)
        cv2.putText(frame, "Counting Line", (10, line_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

        if results[0].boxes.id is not None:
            boxes = results[0].boxes
            ids = boxes.id.cpu().numpy().astype(int)
            classes = boxes.cls.cpu().numpy().astype(int)

            for (x1, y1, x2, y2, obj_id, cls_id) in zip(
                boxes.xyxy[:,0], boxes.xyxy[:,1], boxes.xyxy[:,2], boxes.xyxy[:,3], ids, classes
            ):
                label = model.names[cls_id]
                cx = int((x1 + x2) / 2)
                cy = int((y1 + y2) / 2)

                # Vẽ khung và tâm xe
                cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (255, 255, 0), 2)
                cv2.circle(frame, (cx, cy), 5, (0, 255, 0), -1) 

                # Logic đếm qua vạch
                if obj_id in track_history and obj_id not in counted_ids:
                    prev_cy = track_history[obj_id]
                    if (prev_cy < line_y and cy >= line_y) or (prev_cy > line_y and cy <= line_y):
                        vehicle_count[label] += 1
                        counted_ids.add(obj_id) 
                        cv2.line(frame, (0, line_y), (width, line_y), (0, 255, 0), 5) 
                
                track_history[obj_id] = cy

        # --- BẢNG THỐNG KÊ (Thiết kế gốc của bạn) ---
        total = sum(vehicle_count.values())
        overlay = frame.copy()
        box_w, box_h = 250, 160
        x0, y0 = width - box_w - 20, 20
        cv2.rectangle(overlay, (x0, y0), (x0 + box_w, y0 + box_h), (0, 0, 0), -1)
        frame = cv2.addWeighted(overlay, 0.6, frame, 0.4, 0)

        cv2.putText(frame, f'Total: {total}', (x0 + 10, y0 + 30),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)

        for i, (cls, cnt) in enumerate(vehicle_count.items()):
            cv2.putText(frame, f'{cls.capitalize()}: {cnt}',
                        (x0 + 10, y0 + 60 + i * 25),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)

        out.write(frame)

    cap.release()
    out.release()

    # --- CHUYỂN ĐỔI SANG CHUẨN H.264 ĐỂ XEM TRỰC TIẾP ---
    final_output = 'result_display.mp4'
    try:
        # Chuyển đổi định dạng để trình duyệt web có thể Play trực tiếp
        clip = VideoFileClip(temp_output)
        clip.write_videofile(final_output, codec="libx264", audio=False)
        clip.close()
        if os.path.exists(temp_output):
            os.remove(temp_output)
    except Exception as e:
        print(f"Lỗi encode video: {e}")
        return temp_output
    
    return final_output

# --- GIAO DIỆN GRADIO ---
interface = gr.Interface(
    fn=process_video,
    inputs=gr.Video(label="Tải video của bạn lên"),
    outputs=gr.Video(label="Kết quả đếm xe (Xem trực tiếp)"),
    title="🚗 Hệ thống Đếm Xe Thông Minh (YOLOv8)",
    description="Nhận diện và đếm số lượng xe qua vạch. Kết quả xem được trực tiếp trên web.",
)

if __name__ == "__main__":
    interface.launch()