Update app.py
Browse files
app.py
CHANGED
|
@@ -6,6 +6,30 @@ import cv2
|
|
| 6 |
|
| 7 |
model = YOLO("yolo26s.pt")
|
| 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
def run_tiled_detection(img_bgr, tile_size=640, overlap=0.2, conf=0.50):
|
| 10 |
h, w = img_bgr.shape[:2]
|
| 11 |
step = int(tile_size * (1 - overlap))
|
|
@@ -19,11 +43,13 @@ def run_tiled_detection(img_bgr, tile_size=640, overlap=0.2, conf=0.50):
|
|
| 19 |
results = model(tile, classes=[0], conf=conf, verbose=False)
|
| 20 |
for box in results[0].boxes:
|
| 21 |
bx1, by1, bx2, by2 = map(int, box.xyxy[0])
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
|
|
|
|
|
|
| 27 |
|
| 28 |
if not all_boxes:
|
| 29 |
return []
|
|
@@ -37,13 +63,14 @@ def run_tiled_detection(img_bgr, tile_size=640, overlap=0.2, conf=0.50):
|
|
| 37 |
|
| 38 |
|
| 39 |
def run_standard_detection(img_bgr, conf=0.50):
|
|
|
|
| 40 |
results = model(img_bgr, classes=[0], conf=conf, verbose=False)
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
|
| 48 |
|
| 49 |
def count_people(image, mode):
|
|
@@ -120,7 +147,7 @@ with gr.Blocks(title="People Counter — YOLO26") as demo:
|
|
| 120 |
|
| 121 |
gr.HTML("""
|
| 122 |
<div style='text-align:center; color:#888; font-size:0.8rem; padding: 1.5rem 0 0.5rem;'>
|
| 123 |
-
Powered by <strong>Ultralytics YOLO26</strong> · Model: yolo26s · Conf: 0.50
|
| 124 |
</div>
|
| 125 |
""")
|
| 126 |
|
|
|
|
| 6 |
|
| 7 |
model = YOLO("yolo26s.pt")
|
| 8 |
|
| 9 |
+
def is_valid_person(x1, y1, x2, y2, img_h, img_w):
|
| 10 |
+
"""Filter out partial detections — shoes, legs, hands etc.
|
| 11 |
+
A real full/half person must:
|
| 12 |
+
- Be tall enough relative to image height
|
| 13 |
+
- Have a portrait-ish aspect ratio (taller than wide)
|
| 14 |
+
- Not be tiny
|
| 15 |
+
"""
|
| 16 |
+
box_w = x2 - x1
|
| 17 |
+
box_h = y2 - y1
|
| 18 |
+
|
| 19 |
+
# Minimum size — must be at least 4% of image height
|
| 20 |
+
min_height = img_h * 0.04
|
| 21 |
+
if box_h < min_height:
|
| 22 |
+
return False
|
| 23 |
+
|
| 24 |
+
# Aspect ratio — person box should be taller than wide (portrait)
|
| 25 |
+
# Allow up to 1.2 wide:tall ratio to catch slightly leaning people
|
| 26 |
+
aspect_ratio = box_w / box_h
|
| 27 |
+
if aspect_ratio > 1.2:
|
| 28 |
+
return False
|
| 29 |
+
|
| 30 |
+
return True
|
| 31 |
+
|
| 32 |
+
|
| 33 |
def run_tiled_detection(img_bgr, tile_size=640, overlap=0.2, conf=0.50):
|
| 34 |
h, w = img_bgr.shape[:2]
|
| 35 |
step = int(tile_size * (1 - overlap))
|
|
|
|
| 43 |
results = model(tile, classes=[0], conf=conf, verbose=False)
|
| 44 |
for box in results[0].boxes:
|
| 45 |
bx1, by1, bx2, by2 = map(int, box.xyxy[0])
|
| 46 |
+
# Translate to full image coords
|
| 47 |
+
fx1, fy1, fx2, fy2 = bx1+x, by1+y, bx2+x, by2+y
|
| 48 |
+
if is_valid_person(fx1, fy1, fx2, fy2, h, w):
|
| 49 |
+
all_boxes.append({
|
| 50 |
+
"x1": fx1, "y1": fy1, "x2": fx2, "y2": fy2,
|
| 51 |
+
"conf": float(box.conf[0])
|
| 52 |
+
})
|
| 53 |
|
| 54 |
if not all_boxes:
|
| 55 |
return []
|
|
|
|
| 63 |
|
| 64 |
|
| 65 |
def run_standard_detection(img_bgr, conf=0.50):
|
| 66 |
+
h, w = img_bgr.shape[:2]
|
| 67 |
results = model(img_bgr, classes=[0], conf=conf, verbose=False)
|
| 68 |
+
detections = []
|
| 69 |
+
for b in results[0].boxes:
|
| 70 |
+
x1, y1, x2, y2 = int(b.xyxy[0][0]), int(b.xyxy[0][1]), int(b.xyxy[0][2]), int(b.xyxy[0][3])
|
| 71 |
+
if is_valid_person(x1, y1, x2, y2, h, w):
|
| 72 |
+
detections.append({"x1": x1, "y1": y1, "x2": x2, "y2": y2, "conf": float(b.conf[0])})
|
| 73 |
+
return detections
|
| 74 |
|
| 75 |
|
| 76 |
def count_people(image, mode):
|
|
|
|
| 147 |
|
| 148 |
gr.HTML("""
|
| 149 |
<div style='text-align:center; color:#888; font-size:0.8rem; padding: 1.5rem 0 0.5rem;'>
|
| 150 |
+
Powered by <strong>Ultralytics YOLO26</strong> · Model: yolo26s · Conf: 0.50 · Full-body filter ON
|
| 151 |
</div>
|
| 152 |
""")
|
| 153 |
|