File size: 5,022 Bytes
c4b969e
 
 
 
 
 
 
 
 
a860d86
c4b969e
 
beb309e
adcf8a3
c4b969e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
beb309e
 
c4b969e
 
 
 
 
beb309e
 
c4b969e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0972c78
beb309e
c4b969e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
beb309e
c4b969e
 
beb309e
c4b969e
beb309e
 
 
 
c4b969e
 
beb309e
c4b969e
 
beb309e
0972c78
c4b969e
beb309e
c4b969e
beb309e
c4b969e
 
beb309e
c4b969e
 
 
 
beb309e
c4b969e
 
 
 
 
 
 
beb309e
 
c4b969e
 
 
 
 
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import os
import cv2
import numpy as np
import torch
from ultralytics import YOLO
from sort import Sort
import gradio as gr

# Load YOLOv12x model
MODEL_PATH = "setosys_yolov12x.pt"
model = YOLO(MODEL_PATH)

# COCO dataset class ID for people
PEOPLE_CLASS_ID = 0  # "people"

# Initialize SORT tracker
tracker = Sort()

# Minimum confidence threshold for detection
CONFIDENCE_THRESHOLD = 0.4  # Lowered for better detection

# Distance threshold to avoid duplicate counts
DISTANCE_THRESHOLD = 50

# Dictionary to define keyword-based time intervals
TIME_INTERVALS = {
    "one": 1, "two": 2, "three": 3, "four": 4, "five": 5,
    "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10, "eleven": 11
}

def determine_time_interval(video_filename):
    """ Determines frame skip interval based on keywords in the filename. """
    print(f"Checking filename: {video_filename}")  # Debugging
    for keyword, interval in TIME_INTERVALS.items():
        if keyword in video_filename:
            print(f"Matched keyword: {keyword} -> Interval: {interval}")  # Debugging
            return interval
    print("No keyword match, using default interval: 5")  # Debugging
    return 5  # Default interval

def count_unique_people(video_path):
    """ Counts unique people in a video using YOLOv12x and SORT tracking. """
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        return {"Error": "Unable to open video file."}

    # Reset variables at the start of each analysis
    unique_people_ids = set()
    people_history = {}

    # Get FPS of the video
    fps = int(cap.get(cv2.CAP_PROP_FPS))

    # Extract filename from the path and convert to lowercase
    video_filename = os.path.basename(video_path).lower()

    # Determine the dynamic time interval based on filename keywords
    time_interval = determine_time_interval(video_filename)

    # Get total frames in the video
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    # Ensure frame_skip does not exceed total frames
    frame_skip = min(fps * time_interval, total_frames // 2)  # Reduced skipping

    frame_count = 0

    # Reinitialize the tracker to clear any previous state
    tracker = Sort()

    while True:
        ret, frame = cap.read()
        if not ret:
            break  # End of video

        frame_count += 1
        if frame_count % frame_skip != 0:
            continue  # Skip frames based on interval

        # Run YOLOv12x inference
        results = model(frame, verbose=False)

        detections = []
        for result in results:
            for box in result.boxes:
                class_id = int(box.cls.item())  # Get class ID
                confidence = float(box.conf.item())  # Get confidence score

                # Track only people
                if class_id == PEOPLE_CLASS_ID and confidence > CONFIDENCE_THRESHOLD:
                    x1, y1, x2, y2 = map(int, box.xyxy[0])  # Get bounding box
                    detections.append([x1, y1, x2, y2, confidence])

        # Debugging: Check detections
        print(f"Frame {frame_count}: Detections -> {detections}")

        if len(detections) > 0:
            detections = np.array(detections)
            tracked_objects = tracker.update(detections)
        else:
            tracked_objects = []  # Prevent tracker from resetting

        # Debugging: Check tracked objects
        print(f"Frame {frame_count}: Tracked Objects -> {tracked_objects}")

        for obj in tracked_objects:
            people_id = int(obj[4])  # Unique ID assigned by SORT
            x1, y1, x2, y2 = obj[:4]  # Get the bounding box coordinates

            people_center = (x1 + x2) / 2, (y1 + y2) / 2  # Calculate people center

            # If people is already in history, check movement distance
            if people_id in people_history:
                last_position = people_history[people_id]["position"]
                distance = np.linalg.norm(np.array(people_center) - np.array(last_position))

                if distance > DISTANCE_THRESHOLD:
                    unique_people_ids.add(people_id)  # Add only if moved significantly

            else:
                # If people is not in history, add it
                people_history[people_id] = {
                    "frame_count": frame_count,
                    "position": people_center
                }
                unique_people_ids.add(people_id)

    cap.release()
    return {"Total Unique People": len(unique_people_ids)}


# Gradio UI function
def analyze_video(video_file):
    result = count_unique_people(video_file)
    return "\n".join([f"{key}: {value}" for key, value in result.items()])

# Define Gradio interface
iface = gr.Interface(
    fn=analyze_video,
    inputs=gr.Video(label="Upload Video"),
    outputs=gr.Textbox(label="Analysis Result"),
    title="YOLOv12x Unique People Counter",
    description="Upload a video to count unique people using YOLOv12x and SORT tracking."
)

# Launch the Gradio app
if __name__ == "__main__":
    iface.launch()