|
1 | | -import numpy as np |
2 | 1 | import cv2 as cv |
3 | | - |
| 2 | +import sys |
4 | 3 |
|
5 | 4 | def get_camera(camera_source_idx : int) -> cv.VideoCapture: |
6 | 5 | cap = cv.VideoCapture(camera_source_idx) |
7 | 6 |
|
8 | 7 | if not cap.isOpened(): |
9 | 8 | print("Cannot open camera") |
10 | | - exit() |
| 9 | + sys.exit() |
11 | 10 |
|
12 | 11 | return cap |
13 | 12 |
|
| 13 | +def process_frame(frame): |
| 14 | + detect_faces(frame) |
| 15 | + return frame |
| 16 | + |
| 17 | +TEXT_MARGIN = 5 |
| 18 | +last_face = (0, 0) |
| 19 | +last_face_w, last_face_h = (100, 100) |
| 20 | + |
| 21 | +def smooth(last_pos, cur_pos, alpha=0.2, threshold=2): |
| 22 | + dx = cur_pos[0] - last_pos[0] |
| 23 | + dy = cur_pos[1] - last_pos[1] |
| 24 | + |
| 25 | + if abs(dx) < threshold: |
| 26 | + cur_pos = (last_pos[0], cur_pos[1]) |
| 27 | + if abs(dy) < threshold: |
| 28 | + cur_pos = (cur_pos[0], last_pos[1]) |
| 29 | + |
| 30 | + x = int(alpha * cur_pos[0] + (1 - alpha) * last_pos[0]) |
| 31 | + y = int(alpha * cur_pos[1] + (1 - alpha) * last_pos[1]) |
| 32 | + return x, y |
14 | 33 |
|
15 | 34 |
|
| 35 | +def detect_faces(frame): |
| 36 | + global last_face |
| 37 | + global last_face_w, last_face_h |
| 38 | + frame_gray = cv.cvtColor(src=frame, code=cv.COLOR_BGR2GRAY) |
| 39 | + faces = face_cascade.detectMultiScale(image=frame_gray, scaleFactor=1.2, minNeighbors=7) |
| 40 | + |
| 41 | + for (x, y, w, h) in faces: |
| 42 | + x, y = smooth(last_face, (x,y)) |
| 43 | + w, h = smooth((last_face_w, last_face_h), (w, h)) |
| 44 | + frame = cv.rectangle( |
| 45 | + img=frame, |
| 46 | + pt1=(x, y), pt2=(x + w, y + h), |
| 47 | + color=(255, 0, 0), thickness=2) |
| 48 | + add_text(frame, "Face", (x + w + TEXT_MARGIN, y - TEXT_MARGIN), h / 200) |
| 49 | + last_face = (x, y) |
| 50 | + last_face_w, last_face_h = w, h |
| 51 | + |
| 52 | +def add_text(frame, text, point, font_scale = 1, font_face = cv.FONT_HERSHEY_DUPLEX, color = (255, 0, 0), thickness = 1): |
| 53 | + cv.putText(frame, text, point, font_face, font_scale, color, thickness) |
| 54 | + return frame |
| 55 | + |
| 56 | +# TODO: List all cameras let him choose |
16 | 57 | def main(): |
17 | | - #TODO: List all cameras let him choose |
| 58 | + global face_cascade |
| 59 | + |
| 60 | + face_cascade = cv.CascadeClassifier(cv.data.haarcascades + "haarcascade_frontalface_default.xml") |
18 | 61 | cap = get_camera(0) |
19 | 62 |
|
| 63 | + # Main loop |
20 | 64 | while True: |
21 | 65 | res, frame = cap.read() |
| 66 | + frame = process_frame(frame) |
22 | 67 |
|
23 | 68 | if not res: |
24 | 69 | print("Cannot read frame") |
25 | 70 | break |
26 | 71 |
|
27 | 72 | cv.imshow('frame', frame) |
| 73 | + |
28 | 74 | if cv.waitKey(1) & 0xFF == ord('q'): |
29 | 75 | break |
30 | 76 |
|
|
0 commit comments