show total and current frame count
Browse files
app.py
CHANGED
@@ -92,48 +92,93 @@ interface_image = gr.Interface(
|
|
92 |
examples=path,
|
93 |
cache_examples=False,
|
94 |
)
|
95 |
-
|
|
|
96 |
cap = cv2.VideoCapture(video_path)
|
97 |
if not cap.isOpened():
|
98 |
print("Error: Could not open video.")
|
99 |
return
|
100 |
|
101 |
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
frame_buffer = deque()
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
|
106 |
def process_batch(frames, results):
|
107 |
-
nonlocal ripe_ids, unripe_ids
|
108 |
for frame, output in zip(frames, results):
|
109 |
-
|
|
|
|
|
110 |
boxes = output.boxes
|
111 |
-
|
112 |
-
classes = boxes.cls.cpu().numpy().astype(int)
|
113 |
|
114 |
-
for box,
|
115 |
x1, y1, x2, y2 = map(int, box)
|
116 |
-
class_name = names[
|
117 |
-
|
|
|
118 |
|
119 |
if class_name.lower() == "ripe":
|
120 |
-
|
|
|
121 |
else:
|
122 |
-
|
|
|
123 |
|
124 |
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
|
125 |
-
cv2.putText(frame, f"{class_name.capitalize()} ID:{
|
126 |
(x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
|
127 |
|
128 |
-
#
|
129 |
-
|
130 |
-
(
|
131 |
-
text_x = (frame_width -
|
132 |
-
cv2.putText(frame,
|
133 |
cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
|
134 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
136 |
|
|
|
137 |
while True:
|
138 |
ret, frame = cap.read()
|
139 |
if not ret:
|
@@ -145,13 +190,12 @@ def show_preds_video_batch(video_path, batch_size=16):
|
|
145 |
yield from process_batch(frame_buffer, results)
|
146 |
frame_buffer.clear()
|
147 |
|
148 |
-
# process remaining frames
|
149 |
if frame_buffer:
|
150 |
results = model.track(source=list(frame_buffer), persist=True, tracker="bytetrack.yaml", verbose=False)
|
151 |
yield from process_batch(frame_buffer, results)
|
152 |
|
153 |
cap.release()
|
154 |
-
print(f"Final
|
155 |
|
156 |
# def show_preds_video(video_path):
|
157 |
# results = model.track(source=video_path, persist=True, tracker="bytetrack.yaml", verbose=False, stream=True)
|
@@ -225,7 +269,7 @@ outputs_video = [
|
|
225 |
gr.components.Image(type="numpy", label="Output Image"),
|
226 |
]
|
227 |
interface_video = gr.Interface(
|
228 |
-
fn=
|
229 |
inputs=inputs_video,
|
230 |
outputs=outputs_video,
|
231 |
title="Ripe And Unripe Tomatoes Detection",
|
|
|
92 |
examples=path,
|
93 |
cache_examples=False,
|
94 |
)
|
95 |
+
|
96 |
+
def show_preds_video_batch_centered(video_path, batch_size=16, iou_threshold=0.5):
|
97 |
cap = cv2.VideoCapture(video_path)
|
98 |
if not cap.isOpened():
|
99 |
print("Error: Could not open video.")
|
100 |
return
|
101 |
|
102 |
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
103 |
+
names = model.model.names # cache class names
|
104 |
+
|
105 |
+
# For IoU-based tracking of unique tomatoes
|
106 |
+
unique_objects = {} # id -> (class_name, last_box)
|
107 |
+
next_id = 0
|
108 |
+
total_ripe, total_unripe = 0, 0
|
109 |
+
|
110 |
frame_buffer = deque()
|
111 |
+
|
112 |
+
def compute_iou(box1, box2):
|
113 |
+
xA = max(box1[0], box2[0])
|
114 |
+
yA = max(box1[1], box2[1])
|
115 |
+
xB = min(box1[2], box2[2])
|
116 |
+
yB = min(box1[3], box2[3])
|
117 |
+
|
118 |
+
inter_area = max(0, xB - xA) * max(0, yB - yA)
|
119 |
+
box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1])
|
120 |
+
box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
|
121 |
+
union_area = box1_area + box2_area - inter_area
|
122 |
+
return inter_area / union_area if union_area > 0 else 0
|
123 |
+
|
124 |
+
def match_or_register_object(cls_name, box):
|
125 |
+
nonlocal next_id, total_ripe, total_unripe
|
126 |
+
# Try to match existing object by IoU
|
127 |
+
for obj_id, (existing_cls, existing_box) in unique_objects.items():
|
128 |
+
if compute_iou(existing_box, box) > iou_threshold:
|
129 |
+
unique_objects[obj_id] = (cls_name, box)
|
130 |
+
return obj_id
|
131 |
+
# Register as new object
|
132 |
+
unique_objects[next_id] = (cls_name, box)
|
133 |
+
if cls_name.lower() == "ripe":
|
134 |
+
total_ripe += 1
|
135 |
+
else:
|
136 |
+
total_unripe += 1
|
137 |
+
next_id += 1
|
138 |
+
return next_id - 1
|
139 |
|
140 |
def process_batch(frames, results):
|
|
|
141 |
for frame, output in zip(frames, results):
|
142 |
+
current_ripe, current_unripe = set(), set()
|
143 |
+
|
144 |
+
if output.boxes:
|
145 |
boxes = output.boxes
|
146 |
+
cls_ids = boxes.cls.cpu().numpy().astype(int)
|
|
|
147 |
|
148 |
+
for box, cls_id in zip(boxes.xyxy, cls_ids):
|
149 |
x1, y1, x2, y2 = map(int, box)
|
150 |
+
class_name = names[cls_id]
|
151 |
+
|
152 |
+
obj_id = match_or_register_object(class_name, (x1, y1, x2, y2))
|
153 |
|
154 |
if class_name.lower() == "ripe":
|
155 |
+
current_ripe.add(obj_id)
|
156 |
+
color = (0, 0, 255)
|
157 |
else:
|
158 |
+
current_unripe.add(obj_id)
|
159 |
+
color = (0, 255, 0)
|
160 |
|
161 |
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
|
162 |
+
cv2.putText(frame, f"{class_name.capitalize()} ID:{obj_id}",
|
163 |
(x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
|
164 |
|
165 |
+
# --- Centered current counts ---
|
166 |
+
current_text = f"Current β Ripe: {len(current_ripe)} | Unripe: {len(current_unripe)}"
|
167 |
+
(text_w, _), _ = cv2.getTextSize(current_text, cv2.FONT_HERSHEY_SIMPLEX, 1, 2)
|
168 |
+
text_x = (frame_width - text_w) // 2
|
169 |
+
cv2.putText(frame, current_text, (text_x, 40),
|
170 |
cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
|
171 |
|
172 |
+
# --- Centered total counts ---
|
173 |
+
total_text = f"Total Seen β Ripe: {total_ripe} | Unripe: {total_unripe}"
|
174 |
+
(text_w, _), _ = cv2.getTextSize(total_text, cv2.FONT_HERSHEY_SIMPLEX, 1, 2)
|
175 |
+
text_x = (frame_width - text_w) // 2
|
176 |
+
cv2.putText(frame, total_text, (text_x, 80),
|
177 |
+
cv2.FONT_HERSHEY_SIMPLEX, 1, (200, 200, 0), 2)
|
178 |
+
|
179 |
yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
180 |
|
181 |
+
# --- Read and process in batches ---
|
182 |
while True:
|
183 |
ret, frame = cap.read()
|
184 |
if not ret:
|
|
|
190 |
yield from process_batch(frame_buffer, results)
|
191 |
frame_buffer.clear()
|
192 |
|
|
|
193 |
if frame_buffer:
|
194 |
results = model.track(source=list(frame_buffer), persist=True, tracker="bytetrack.yaml", verbose=False)
|
195 |
yield from process_batch(frame_buffer, results)
|
196 |
|
197 |
cap.release()
|
198 |
+
print(f"Final Totals β Ripe: {total_ripe}, Unripe: {total_unripe}")
|
199 |
|
200 |
# def show_preds_video(video_path):
|
201 |
# results = model.track(source=video_path, persist=True, tracker="bytetrack.yaml", verbose=False, stream=True)
|
|
|
269 |
gr.components.Image(type="numpy", label="Output Image"),
|
270 |
]
|
271 |
interface_video = gr.Interface(
|
272 |
+
fn=show_preds_video_batch_centered,
|
273 |
inputs=inputs_video,
|
274 |
outputs=outputs_video,
|
275 |
title="Ripe And Unripe Tomatoes Detection",
|