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
|
#!/usr/bin/env run.sh
"""Person detection module for Kidcam using YOLOv8-nano."""
# : out kidcam-detector
# : dep opencv-python
# : dep ultralytics
# : dep numpy
# : dep pytest
import cv2 as cv
import numpy as np
import sys
class PersonDetector:
"""Detect persons in video frames using YOLOv8-nano."""
def __init__(
self,
model_path: str,
confidence_threshold: float = 0.5,
) -> None:
"""Initialize person detector.
Args:
model_path: Path to YOLOv8 model file
confidence_threshold: Minimum confidence for detection (0.0-1.0)
"""
try:
import ultralytics as ul
self.model = ul.YOLO(model_path)
self.confidence_threshold = confidence_threshold
self.last_bbox: tuple[int, int, int, int] | None = None
except ImportError as e:
msg = "ultralytics library required for YOLOv8"
raise ImportError(msg) from e
def detect_person(self, frame: np.ndarray) -> bool:
"""Detect if person is present in frame.
Args:
frame: BGR image from OpenCV
Returns:
True if person detected above confidence threshold
"""
results = self.model(frame, verbose=False)
self.last_bbox = None
for result in results:
boxes = result.boxes
for box in boxes:
class_id = int(box.cls[0])
confidence = float(box.conf[0])
if class_id == 0 and confidence >= self.confidence_threshold:
x1, y1, x2, y2 = box.xyxy[0].cpu().numpy()
self.last_bbox = (int(x1), int(y1), int(x2), int(y2))
return True
return False
def get_last_detection_bbox(
self,
) -> tuple[int, int, int, int] | None:
"""Get bounding box from last detection.
Returns:
Tuple of (x1, y1, x2, y2) or None if no recent detection
"""
return self.last_bbox
def main() -> None:
"""Test person detection with webcam."""
if "test" in sys.argv:
test()
return
try:
cap = cv.VideoCapture("/dev/video0")
if not cap.isOpened():
sys.exit(1)
detector = PersonDetector("yolov8n.pt", confidence_threshold=0.5)
while True:
ret, frame = cap.read()
if not ret:
break
if detector.detect_person(frame):
bbox = detector.get_last_detection_bbox()
if bbox:
x1, y1, x2, y2 = bbox
cv.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv.imshow("Kidcam - Person Detection", frame)
if cv.waitKey(1) & 0xFF == ord("q"):
break
except FileNotFoundError:
sys.exit(1)
except Exception:
sys.exit(1)
finally:
if "cap" in locals():
cap.release()
cv.destroyAllWindows()
def test() -> None:
"""Basic unit tests for PersonDetector."""
test_frame = np.zeros((480, 640, 3), dtype=np.uint8)
try:
detector = PersonDetector("yolov8n.pt", confidence_threshold=0.5)
assert detector.confidence_threshold == 0.5
assert detector.get_last_detection_bbox() is None
result = detector.detect_person(test_frame)
assert isinstance(result, bool)
bbox = detector.get_last_detection_bbox()
assert bbox is None or (isinstance(bbox, tuple) and len(bbox) == 4)
except ImportError:
pass
except Exception:
sys.exit(1)
if __name__ == "__main__":
main()
|