Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
@@ -1,15 +1,21 @@
|
|
1 |
import gradio as gr
|
2 |
import cv2
|
3 |
import os
|
4 |
-
import
|
|
|
|
|
5 |
from ultralytics import YOLO
|
6 |
from ultralytics.solutions import object_counter
|
|
|
|
|
7 |
|
8 |
# Initialize the YOLO model
|
9 |
MODEL = "yolov8n.pt"
|
10 |
model = YOLO(MODEL)
|
11 |
model.fuse()
|
12 |
|
|
|
|
|
13 |
# Auxiliary functions
|
14 |
def resize_frame(frame, scale_percent):
|
15 |
width = int(frame.shape[1] * scale_percent / 100)
|
@@ -18,38 +24,129 @@ def resize_frame(frame, scale_percent):
|
|
18 |
resized = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)
|
19 |
return resized
|
20 |
|
21 |
-
@
|
22 |
def process_video(video_file, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness, draw_tracks, view_img, view_in_counts, view_out_counts, track_thickness, region_thickness, line_dist_thresh, persist, conf, iou, classes, verbose):
|
23 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
|
25 |
def preview_line(video_file, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness):
|
26 |
-
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
def gradio_app(video, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness, draw_tracks, view_img, view_in_counts, view_out_counts, track_thickness, region_thickness, line_dist_thresh, persist, conf, iou, classes_to_track, verbose):
|
30 |
-
|
31 |
-
|
32 |
|
33 |
def update_preview(video, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness):
|
34 |
-
|
35 |
-
# Code here
|
36 |
|
37 |
def set_4k_coordinates():
|
38 |
return 0, 1500, 3840, 1500
|
39 |
|
40 |
def set_1080p_coordinates():
|
41 |
return 0, 700, 1920, 700
|
42 |
-
|
43 |
with gr.Blocks(css="style.css", theme="dark") as demo:
|
44 |
with gr.Row():
|
45 |
with gr.Column(scale=1):
|
46 |
video_input = gr.File(label="Upload your video")
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
|
|
53 |
line_thickness = gr.Slider(minimum=1, maximum=10, value=2, label="Line Thickness")
|
54 |
draw_tracks = gr.Checkbox(label="Draw Tracks", value=True)
|
55 |
view_img = gr.Checkbox(label="Display Image with Annotations", value=True)
|
@@ -61,7 +158,7 @@ with gr.Blocks(css="style.css", theme="dark") as demo:
|
|
61 |
persist = gr.Checkbox(label="Persist Tracks", value=True)
|
62 |
conf = gr.Slider(minimum=0.0, maximum=1.0, value=0.1, step=0.05, label="Confidence Threshold")
|
63 |
iou = gr.Slider(minimum=0.0, maximum=1.0, value=0.7, step=0.05, label="IOU Threshold")
|
64 |
-
classes_to_track = gr.Textbox(label="Classes to Track", value="2,3,5,7")
|
65 |
verbose = gr.Checkbox(label="Verbose Tracking", value=True)
|
66 |
scale_percent = gr.Slider(minimum=10, maximum=100, value=100, step=10, label="Scale Percentage")
|
67 |
process_button = gr.Button("Process Video")
|
@@ -70,9 +167,21 @@ with gr.Blocks(css="style.css", theme="dark") as demo:
|
|
70 |
video_output = gr.Video(label="Processed Video")
|
71 |
download_button = gr.File(label="Download Processed Video")
|
72 |
|
73 |
-
|
74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
process_button.click(gradio_app, inputs=[video_input, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness, draw_tracks, view_img, view_in_counts, view_out_counts, track_thickness, region_thickness, line_dist_thresh, persist, conf, iou, classes_to_track, verbose], outputs=[video_output, download_button])
|
76 |
-
video_input.change(update_preview, inputs=[video_input, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness], outputs=[preview_image])
|
77 |
|
78 |
-
demo.launch()
|
|
|
1 |
import gradio as gr
|
2 |
import cv2
|
3 |
import os
|
4 |
+
import pandas as pd
|
5 |
+
import numpy as np
|
6 |
+
import torch
|
7 |
from ultralytics import YOLO
|
8 |
from ultralytics.solutions import object_counter
|
9 |
+
import subprocess
|
10 |
+
import spaces # Import spaces for ZeroGPU integration
|
11 |
|
12 |
# Initialize the YOLO model
|
13 |
MODEL = "yolov8n.pt"
|
14 |
model = YOLO(MODEL)
|
15 |
model.fuse()
|
16 |
|
17 |
+
dict_classes = model.model.names
|
18 |
+
|
19 |
# Auxiliary functions
|
20 |
def resize_frame(frame, scale_percent):
|
21 |
width = int(frame.shape[1] * scale_percent / 100)
|
|
|
24 |
resized = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)
|
25 |
return resized
|
26 |
|
27 |
+
@spaces.GPU
|
28 |
def process_video(video_file, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness, draw_tracks, view_img, view_in_counts, view_out_counts, track_thickness, region_thickness, line_dist_thresh, persist, conf, iou, classes, verbose):
|
29 |
+
# Ensure classes is a list of integers
|
30 |
+
classes = [int(x) for x in classes.split(',') if x.strip().isdigit()] if classes else None
|
31 |
+
|
32 |
+
line_points = [(line_start_x, line_start_y), (line_end_x, line_end_y)]
|
33 |
+
|
34 |
+
cap = cv2.VideoCapture(video_file)
|
35 |
+
if not cap.isOpened():
|
36 |
+
raise ValueError("Failed to open video file")
|
37 |
+
|
38 |
+
tmp_output_path = "processed_output_temp.mp4"
|
39 |
+
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) * scale_percent / 100)
|
40 |
+
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) * scale_percent / 100)
|
41 |
+
fps = int(cap.get(cv2.CAP_PROP_FPS))
|
42 |
+
video_writer = cv2.VideoWriter(tmp_output_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
|
43 |
+
|
44 |
+
counter = object_counter.ObjectCounter(
|
45 |
+
classes_names=model.names,
|
46 |
+
view_img=view_img,
|
47 |
+
reg_pts=line_points,
|
48 |
+
draw_tracks=draw_tracks,
|
49 |
+
line_thickness=int(line_thickness),
|
50 |
+
track_thickness=int(track_thickness),
|
51 |
+
region_thickness=int(region_thickness),
|
52 |
+
line_dist_thresh=line_dist_thresh,
|
53 |
+
view_in_counts=view_in_counts,
|
54 |
+
view_out_counts=view_out_counts,
|
55 |
+
count_reg_color=(255, 0, 255), # Magenta
|
56 |
+
track_color=(0, 255, 0), # Green
|
57 |
+
count_txt_color=(255, 255, 255), # White
|
58 |
+
count_bg_color=(50, 50, 50) # Dark gray
|
59 |
+
)
|
60 |
+
|
61 |
+
prev_frame = None
|
62 |
+
prev_keypoints = None
|
63 |
+
|
64 |
+
while cap.isOpened():
|
65 |
+
ret, frame = cap.read()
|
66 |
+
if not ret:
|
67 |
+
break
|
68 |
+
frame = resize_frame(frame, scale_percent)
|
69 |
+
|
70 |
+
# Adjust line points based on scaling
|
71 |
+
scaled_line_points = [(int(x * scale_percent / 100), int(y * scale_percent / 100)) for x, y in line_points]
|
72 |
+
for point1, point2 in zip(scaled_line_points[:-1], scaled_line_points[1:]):
|
73 |
+
cv2.line(frame, tuple(map(int, point1)), tuple(map(int, point2)), (255, 255, 0), int(line_thickness))
|
74 |
+
|
75 |
+
tracks = model.track(frame, persist=persist, conf=conf, iou=iou, classes=classes, verbose=verbose)
|
76 |
+
|
77 |
+
# Update the counter with the current frame and tracks
|
78 |
+
frame = counter.start_counting(frame, tracks)
|
79 |
+
|
80 |
+
# Check if the previous frame is initialized for optical flow calculation
|
81 |
+
if prev_frame is not None:
|
82 |
+
try:
|
83 |
+
prev_frame_resized = resize_frame(prev_frame, scale_percent)
|
84 |
+
matched_keypoints, status, _ = cv2.calcOpticalFlowPyrLK(prev_frame_resized, frame, prev_keypoints, None)
|
85 |
+
prev_keypoints = matched_keypoints
|
86 |
+
except cv2.error as e:
|
87 |
+
print(f"Error in optical flow calculation: {e}")
|
88 |
+
|
89 |
+
prev_frame = frame.copy()
|
90 |
+
prev_keypoints = cv2.goodFeaturesToTrack(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY), maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)
|
91 |
+
|
92 |
+
video_writer.write(frame)
|
93 |
+
|
94 |
+
cap.release()
|
95 |
+
video_writer.release()
|
96 |
+
|
97 |
+
# Reduce the resolution of the video for download
|
98 |
+
output_path = "processed_output.mp4"
|
99 |
+
if h > 1080:
|
100 |
+
resolution = "1920x1080"
|
101 |
+
else:
|
102 |
+
resolution = "1280x720"
|
103 |
+
|
104 |
+
subprocess.run(
|
105 |
+
["ffmpeg", "-y", "-i", tmp_output_path, "-vf", f"scale={resolution}", "-crf", "18", "-preset", "veryfast", "-hide_banner", "-loglevel", "error", output_path]
|
106 |
+
)
|
107 |
+
os.remove(tmp_output_path)
|
108 |
+
|
109 |
+
return output_path
|
110 |
|
111 |
def preview_line(video_file, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness):
|
112 |
+
cap = cv2.VideoCapture(video_file)
|
113 |
+
ret, frame = cap.read()
|
114 |
+
if not ret:
|
115 |
+
raise ValueError("Failed to read video frame")
|
116 |
+
|
117 |
+
frame = resize_frame(frame, scale_percent)
|
118 |
+
line_points = [(line_start_x, line_start_y), (line_end_x, line_end_y)]
|
119 |
+
scaled_line_points = [(int(x * scale_percent / 100), int(y * scale_percent / 100)) for x, y in line_points]
|
120 |
+
for point1, point2 in zip(scaled_line_points[:-1], scaled_line_points[1:]):
|
121 |
+
cv2.line(frame, tuple(map(int, point1)), tuple(map(int, point2)), (255, 255, 0), int(line_thickness))
|
122 |
+
|
123 |
+
preview_path = "preview_line.jpg"
|
124 |
+
cv2.imwrite(preview_path, frame)
|
125 |
+
return preview_path
|
126 |
|
127 |
def gradio_app(video, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness, draw_tracks, view_img, view_in_counts, view_out_counts, track_thickness, region_thickness, line_dist_thresh, persist, conf, iou, classes_to_track, verbose):
|
128 |
+
output_path = process_video(video.name, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, int(line_thickness), draw_tracks, view_img, view_in_counts, view_out_counts, int(track_thickness), int(region_thickness), line_dist_thresh, persist, conf, iou, classes_to_track, verbose)
|
129 |
+
return output_path, output_path
|
130 |
|
131 |
def update_preview(video, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness):
|
132 |
+
return preview_line(video.name, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, int(line_thickness))
|
|
|
133 |
|
134 |
def set_4k_coordinates():
|
135 |
return 0, 1500, 3840, 1500
|
136 |
|
137 |
def set_1080p_coordinates():
|
138 |
return 0, 700, 1920, 700
|
|
|
139 |
with gr.Blocks(css="style.css", theme="dark") as demo:
|
140 |
with gr.Row():
|
141 |
with gr.Column(scale=1):
|
142 |
video_input = gr.File(label="Upload your video")
|
143 |
+
with gr.Row():
|
144 |
+
set_4k_button = gr.Button("4K")
|
145 |
+
set_1080p_button = gr.Button("1080p")
|
146 |
+
line_start_x = gr.Number(label="Line Start X", value=500, precision=0)
|
147 |
+
line_start_y = gr.Number(label="Line Start Y", value=1500, precision=0)
|
148 |
+
line_end_x = gr.Number(label="Line End X", value=3400, precision=0)
|
149 |
+
line_end_y = gr.Number(label="Line End Y", value=1500, precision=0)
|
150 |
line_thickness = gr.Slider(minimum=1, maximum=10, value=2, label="Line Thickness")
|
151 |
draw_tracks = gr.Checkbox(label="Draw Tracks", value=True)
|
152 |
view_img = gr.Checkbox(label="Display Image with Annotations", value=True)
|
|
|
158 |
persist = gr.Checkbox(label="Persist Tracks", value=True)
|
159 |
conf = gr.Slider(minimum=0.0, maximum=1.0, value=0.1, step=0.05, label="Confidence Threshold")
|
160 |
iou = gr.Slider(minimum=0.0, maximum=1.0, value=0.7, step=0.05, label="IOU Threshold")
|
161 |
+
classes_to_track = gr.Textbox(label="Classes to Track (comma-separated ids)", value="2,3,5,7")
|
162 |
verbose = gr.Checkbox(label="Verbose Tracking", value=True)
|
163 |
scale_percent = gr.Slider(minimum=10, maximum=100, value=100, step=10, label="Scale Percentage")
|
164 |
process_button = gr.Button("Process Video")
|
|
|
167 |
video_output = gr.Video(label="Processed Video")
|
168 |
download_button = gr.File(label="Download Processed Video")
|
169 |
|
170 |
+
def update_preview_and_display(video, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness):
|
171 |
+
preview_path = update_preview(video, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness)
|
172 |
+
return preview_path
|
173 |
+
|
174 |
+
video_input.change(update_preview_and_display, inputs=[video_input, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness], outputs=preview_image)
|
175 |
+
for component in [scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness, draw_tracks, view_img, view_in_counts, view_out_counts, track_thickness, region_thickness, line_dist_thresh, persist, conf, iou, classes_to_track, verbose]:
|
176 |
+
component.change(update_preview_and_display, inputs=[video_input, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness], outputs=preview_image)
|
177 |
+
|
178 |
+
set_4k_button.click(lambda: set_4k_coordinates(), outputs=[line_start_x, line_start_y, line_end_x, line_end_y])
|
179 |
+
set_1080p_button.click(lambda: set_1080p_coordinates(), outputs=[line_start_x, line_start_y, line_end_x, line_end_y])
|
180 |
+
|
181 |
+
def clear_previous_video():
|
182 |
+
return None, None
|
183 |
+
|
184 |
+
process_button.click(clear_previous_video, outputs=[video_output, download_button], queue=False)
|
185 |
process_button.click(gradio_app, inputs=[video_input, scale_percent, line_start_x, line_start_y, line_end_x, line_end_y, line_thickness, draw_tracks, view_img, view_in_counts, view_out_counts, track_thickness, region_thickness, line_dist_thresh, persist, conf, iou, classes_to_track, verbose], outputs=[video_output, download_button])
|
|
|
186 |
|
187 |
+
demo.launch()
|