Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1360,9 +1360,107 @@ def process_video_file(video_file, analysis_types, processing_mode="Hybrid (Goog
|
|
| 1360 |
else:
|
| 1361 |
detection_stats["objects"]["person"] = 1
|
| 1362 |
else:
|
| 1363 |
-
# Using YOLO or another DNN-based detector
|
| 1364 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1365 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1366 |
except Exception as e:
|
| 1367 |
cv2.putText(frame, f"OpenCV Error: {str(e)}", (10, 110),
|
| 1368 |
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
|
|
@@ -2139,6 +2237,49 @@ def main():
|
|
| 2139 |
# OpenCV parameters
|
| 2140 |
st.sidebar.markdown("#### OpenCV Parameters")
|
| 2141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2142 |
track_update_frames = st.sidebar.slider(
|
| 2143 |
"Update OpenCV tracking every N frames",
|
| 2144 |
min_value=1,
|
|
@@ -2255,6 +2396,32 @@ def main():
|
|
| 2255 |
"blend_results": blend_results
|
| 2256 |
})
|
| 2257 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2258 |
# Process the video with the parameters
|
| 2259 |
processed_video, results = process_video_file(uploaded_file, analysis_types, **processing_params)
|
| 2260 |
|
|
|
|
| 1360 |
else:
|
| 1361 |
detection_stats["objects"]["person"] = 1
|
| 1362 |
else:
|
| 1363 |
+
# Using YOLO or another DNN-based detector
|
| 1364 |
+
blob = cv2.dnn.blobFromImage(frame, 1/255.0, (416, 416), swapRB=True, crop=False)
|
| 1365 |
+
opencv_detector.setInput(blob)
|
| 1366 |
+
|
| 1367 |
+
# Get output layer names
|
| 1368 |
+
layer_names = opencv_detector.getLayerNames()
|
| 1369 |
+
output_layers = []
|
| 1370 |
+
|
| 1371 |
+
# Handle different OpenCV versions
|
| 1372 |
+
try:
|
| 1373 |
+
if cv2.__version__.startswith('4'):
|
| 1374 |
+
# OpenCV 4.x
|
| 1375 |
+
output_layers = [layer_names[i - 1] for i in opencv_detector.getUnconnectedOutLayers()]
|
| 1376 |
+
else:
|
| 1377 |
+
# OpenCV 3.x
|
| 1378 |
+
output_layers = [layer_names[i[0] - 1] for i in opencv_detector.getUnconnectedOutLayers()]
|
| 1379 |
+
except:
|
| 1380 |
+
# Fallback method
|
| 1381 |
+
unconnected_layers = opencv_detector.getUnconnectedOutLayers()
|
| 1382 |
+
if isinstance(unconnected_layers[0], list) or isinstance(unconnected_layers[0], tuple):
|
| 1383 |
+
output_layers = [layer_names[i[0] - 1] for i in unconnected_layers]
|
| 1384 |
+
else:
|
| 1385 |
+
output_layers = [layer_names[i - 1] for i in unconnected_layers]
|
| 1386 |
|
| 1387 |
+
outputs = opencv_detector.forward(output_layers)
|
| 1388 |
+
|
| 1389 |
+
# Process detections
|
| 1390 |
+
class_ids = []
|
| 1391 |
+
confidences = []
|
| 1392 |
+
boxes = []
|
| 1393 |
+
|
| 1394 |
+
# Define COCO class names
|
| 1395 |
+
class_names = ["person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat",
|
| 1396 |
+
"traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat",
|
| 1397 |
+
"dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack",
|
| 1398 |
+
"umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball",
|
| 1399 |
+
"kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket",
|
| 1400 |
+
"bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
| 1401 |
+
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair",
|
| 1402 |
+
"couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse",
|
| 1403 |
+
"remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator",
|
| 1404 |
+
"book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"]
|
| 1405 |
+
|
| 1406 |
+
# Process each detection
|
| 1407 |
+
for output in outputs:
|
| 1408 |
+
for detection in output:
|
| 1409 |
+
scores = detection[5:]
|
| 1410 |
+
class_id = np.argmax(scores)
|
| 1411 |
+
confidence = scores[class_id]
|
| 1412 |
+
|
| 1413 |
+
if confidence > confidence_threshold:
|
| 1414 |
+
# Object detected
|
| 1415 |
+
center_x = int(detection[0] * frame.shape[1])
|
| 1416 |
+
center_y = int(detection[1] * frame.shape[0])
|
| 1417 |
+
w = int(detection[2] * frame.shape[1])
|
| 1418 |
+
h = int(detection[3] * frame.shape[0])
|
| 1419 |
+
|
| 1420 |
+
# Rectangle coordinates
|
| 1421 |
+
x = int(center_x - w / 2)
|
| 1422 |
+
y = int(center_y - h / 2)
|
| 1423 |
+
|
| 1424 |
+
boxes.append([x, y, w, h])
|
| 1425 |
+
confidences.append(float(confidence))
|
| 1426 |
+
class_ids.append(class_id)
|
| 1427 |
+
|
| 1428 |
+
# Apply non-maximum suppression
|
| 1429 |
+
indices = cv2.dnn.NMSBoxes(boxes, confidences, confidence_threshold, 0.4)
|
| 1430 |
+
|
| 1431 |
+
# Draw the detections
|
| 1432 |
+
if len(indices) > 0:
|
| 1433 |
+
for i in indices:
|
| 1434 |
+
if isinstance(i, (list, tuple)): # Handle different OpenCV versions
|
| 1435 |
+
i = i[0]
|
| 1436 |
+
|
| 1437 |
+
box = boxes[i]
|
| 1438 |
+
x, y, w, h = box
|
| 1439 |
+
|
| 1440 |
+
# Get class name
|
| 1441 |
+
class_id = class_ids[i]
|
| 1442 |
+
label = f"{class_names[class_id]}: {int(confidences[i] * 100)}%"
|
| 1443 |
+
|
| 1444 |
+
# Different colors for different classes
|
| 1445 |
+
color = (0, 255, 0) # Default color
|
| 1446 |
+
|
| 1447 |
+
# Draw rectangle and label
|
| 1448 |
+
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
|
| 1449 |
+
cv2.putText(frame, label, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
|
| 1450 |
+
|
| 1451 |
+
# Add to object trackers for future frames
|
| 1452 |
+
object_name = class_names[class_id]
|
| 1453 |
+
object_trackers[f"{object_name}_{i}"] = {
|
| 1454 |
+
"bbox": (x, y, w, h),
|
| 1455 |
+
"last_seen": frame_count,
|
| 1456 |
+
"score": confidences[i]
|
| 1457 |
+
}
|
| 1458 |
+
|
| 1459 |
+
# Update detection stats
|
| 1460 |
+
if object_name in detection_stats["objects"]:
|
| 1461 |
+
detection_stats["objects"][object_name] += 1
|
| 1462 |
+
else:
|
| 1463 |
+
detection_stats["objects"][object_name] = 1
|
| 1464 |
except Exception as e:
|
| 1465 |
cv2.putText(frame, f"OpenCV Error: {str(e)}", (10, 110),
|
| 1466 |
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
|
|
|
|
| 2237 |
# OpenCV parameters
|
| 2238 |
st.sidebar.markdown("#### OpenCV Parameters")
|
| 2239 |
|
| 2240 |
+
# Add YOLO model download option if models aren't found
|
| 2241 |
+
models_dir = os.path.join(os.path.dirname(__file__), "models")
|
| 2242 |
+
weights_path = os.path.join(models_dir, "yolov3.weights")
|
| 2243 |
+
config_path = os.path.join(models_dir, "yolov3.cfg")
|
| 2244 |
+
|
| 2245 |
+
if not os.path.exists(models_dir):
|
| 2246 |
+
os.makedirs(models_dir, exist_ok=True)
|
| 2247 |
+
|
| 2248 |
+
if not (os.path.exists(weights_path) and os.path.exists(config_path)):
|
| 2249 |
+
st.sidebar.warning("⚠️ YOLO models not found. Using basic people detector.")
|
| 2250 |
+
|
| 2251 |
+
if st.sidebar.button("Download YOLO Models"):
|
| 2252 |
+
with st.sidebar.spinner("Downloading YOLO models..."):
|
| 2253 |
+
# Ensure models directory exists
|
| 2254 |
+
os.makedirs(models_dir, exist_ok=True)
|
| 2255 |
+
|
| 2256 |
+
# Download YOLOv3 config
|
| 2257 |
+
try:
|
| 2258 |
+
import urllib.request
|
| 2259 |
+
|
| 2260 |
+
# Download config file
|
| 2261 |
+
if not os.path.exists(config_path):
|
| 2262 |
+
urllib.request.urlretrieve(
|
| 2263 |
+
"https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3.cfg",
|
| 2264 |
+
config_path
|
| 2265 |
+
)
|
| 2266 |
+
st.sidebar.success("Downloaded YOLOv3 config file")
|
| 2267 |
+
|
| 2268 |
+
# Download weights file (this is large - about 240MB)
|
| 2269 |
+
if not os.path.exists(weights_path):
|
| 2270 |
+
urllib.request.urlretrieve(
|
| 2271 |
+
"https://pjreddie.com/media/files/yolov3.weights",
|
| 2272 |
+
weights_path
|
| 2273 |
+
)
|
| 2274 |
+
st.sidebar.success("Downloaded YOLOv3 weights file")
|
| 2275 |
+
|
| 2276 |
+
st.sidebar.success("YOLO models downloaded successfully! Please refresh the page.")
|
| 2277 |
+
except Exception as e:
|
| 2278 |
+
st.sidebar.error(f"Error downloading YOLO models: {str(e)}")
|
| 2279 |
+
st.sidebar.info("You can manually download the models from: https://pjreddie.com/darknet/yolo/")
|
| 2280 |
+
else:
|
| 2281 |
+
st.sidebar.success("✅ YOLO models found. Using advanced object detection.")
|
| 2282 |
+
|
| 2283 |
track_update_frames = st.sidebar.slider(
|
| 2284 |
"Update OpenCV tracking every N frames",
|
| 2285 |
min_value=1,
|
|
|
|
| 2396 |
"blend_results": blend_results
|
| 2397 |
})
|
| 2398 |
|
| 2399 |
+
# Add to the OpenCV parameters section:
|
| 2400 |
+
with st.sidebar.expander("YOLO Class Filters"):
|
| 2401 |
+
# Allow users to select which object classes to detect
|
| 2402 |
+
st.markdown("Select which objects to detect:")
|
| 2403 |
+
|
| 2404 |
+
# Create a multiselect with common categories
|
| 2405 |
+
selected_categories = st.multiselect(
|
| 2406 |
+
"Object Categories",
|
| 2407 |
+
["People", "Vehicles", "Animals", "Indoor Objects", "Sports Equipment", "Food", "All"],
|
| 2408 |
+
default=["People", "Vehicles"]
|
| 2409 |
+
)
|
| 2410 |
+
|
| 2411 |
+
# Map categories to actual YOLO classes
|
| 2412 |
+
yolo_classes = []
|
| 2413 |
+
if "People" in selected_categories:
|
| 2414 |
+
yolo_classes.extend(["person"])
|
| 2415 |
+
if "Vehicles" in selected_categories:
|
| 2416 |
+
yolo_classes.extend(["bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck"])
|
| 2417 |
+
if "Animals" in selected_categories:
|
| 2418 |
+
yolo_classes.extend(["bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe"])
|
| 2419 |
+
if "All" in selected_categories:
|
| 2420 |
+
yolo_classes = None # Detect all classes
|
| 2421 |
+
|
| 2422 |
+
# Pass this to your processing function in the processing_params
|
| 2423 |
+
processing_params["yolo_classes"] = yolo_classes
|
| 2424 |
+
|
| 2425 |
# Process the video with the parameters
|
| 2426 |
processed_video, results = process_video_file(uploaded_file, analysis_types, **processing_params)
|
| 2427 |
|