如何使用OpenCV检测静止人脸并在其静止5秒后输出提示
人脸静止5秒触发提示的实现方案
核心逻辑
- 每帧同步校验两个状态:是否检测到人脸、是否存在有效运动
- 仅当「人脸存在 + 无运动」两个条件同时满足时累计时长,任一条件不满足直接重置计时
- 新增打印标记位,避免满足条件后重复输出提示
代码修改步骤
1. 新增全局状态变量
在while循环外原有代码下方添加三个状态变量:
# 原有起始时间变量 t1 = time.time() # 新增静止计时相关变量 last_still_start = None motion_detected = False has_printed = False
2. 统一判断人脸是否存在
在四个ROI的人脸检测代码执行完成后,添加人脸存在判断:
# 原有人脸检测、画框逻辑不变,之后新增 face_exist = any([len(faces_rect1), len(faces_rect2), len(faces_rect3), len(faces_rect4)])
3. 运动检测新增状态标记
在运动检测的轮廓遍历逻辑中,检测到有效运动时标记状态:
# 每次检测运动前先重置标记 motion_detected = False for contour in contours: (x, y, w, h) = cv.boundingRect(contour) if cv.contourArea(contour) < 1000: continue # 新增状态标记 motion_detected = True # 原有绘图、文字输出逻辑不变 cv.rectangle(frame1, (x, y), (x+w, y+h), (0,255,0), thickness=2) cv.putText(frame1, 'Status: {}'.format('Movement'), (10,20), cv.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), thickness=3)
4. 新增静止时长校验逻辑
在运动检测代码结束后、按键退出判断前添加计时校验:
current_ts = time.time() if face_exist and not motion_detected: # 第一次进入静止状态,初始化计时起点 if last_still_start is None: last_still_start = current_ts has_printed = False else: # 静止时长满5秒且未打印过,输出提示 if current_ts - last_still_start >= 5 and not has_printed: print("检测到人脸静止满5秒") has_printed = True else: # 状态不满足,重置所有标记 last_still_start = None has_printed = False
修改后完整代码
import cv2 as cv import time # 打开摄像头 cap = cv.VideoCapture(0) # 人脸检测用haar级联分类器 haar_cascade = cv.CascadeClassifier('haar_face.xml') # 校验摄像头是否正常打开 if not cap.isOpened(): raise IOError("Cannot open webcam") # 起始时间 t1 = time.time() # 新增静止计时相关变量 last_still_start = None motion_detected = False has_printed = False # 摄像头开启时执行以下逻辑 while True: ret, frame = cap.read() ret, frame1 = cap.read() ret, frame2 = cap.read() frame = cv.resize(frame, None, fx=1, fy=1, interpolation=cv.INTER_AREA) # 划分帧为感兴趣区域(ROI) ROI1 = frame[0:180, 0:320] ROI2 = frame[0:180, 320:640] ROI3 = frame[180:360, 0:320] ROI4 = frame[180:360, 320:640] # 检测每个ROI中的人脸 faces_rect1 = haar_cascade.detectMultiScale(ROI1, scaleFactor=1.1, minNeighbors=5) faces_rect2 = haar_cascade.detectMultiScale(ROI2, scaleFactor=1.1, minNeighbors=5) faces_rect3 = haar_cascade.detectMultiScale(ROI3, scaleFactor=1.1, minNeighbors=5) faces_rect4 = haar_cascade.detectMultiScale(ROI4, scaleFactor=1.1, minNeighbors=5) # 在检测到的人脸周围绘制矩形 for (x, y, w, h) in faces_rect1: cv.rectangle(ROI1, (x, y), (x+w,y+h), (0,255,0), thickness=2) t2 = time.time() if (t2 - t1) > 1: print('I SEE YOU IN 1') t1 = time.time() # 重置起始时间 for (x, y, w, h) in faces_rect2: cv.rectangle(ROI2, (x, y), (x+w,y+h), (0,255,0), thickness=2) t2 = time.time() if (t2 - t1) > 1: print('I SEE YOU IN 2') t1 = time.time() # 重置起始时间 for (x, y, w, h) in faces_rect3: cv.rectangle(ROI3, (x, y), (x+w,y+h), (0,255,0), thickness=2) t2 = time.time() if (t2 - t1) > 1: print('I SEE YOU IN 3') t1 = time.time() # 重置起始时间 for (x, y, w, h) in faces_rect4: cv.rectangle(ROI4, (x, y), (x+w,y+h), (0,255,0), thickness=2) t2 = time.time() if (t2 - t1) > 1: print('I SEE YOU IN 4') t1 = time.time() # 重置起始时间 # 统一判断是否存在人脸 face_exist = any([len(faces_rect1), len(faces_rect2), len(faces_rect3), len(faces_rect4)]) # 展示所有视频流 cv.imshow('ROI1', ROI1) cv.imshow('ROI2', ROI2) cv.imshow('ROI3', ROI3) cv.imshow('ROI4', ROI4) # 检测运动 # 预处理帧以检测轮廓 diff = cv.absdiff(frame1, frame2) gray = cv.cvtColor(diff, cv.COLOR_BGR2GRAY) blur = cv.GaussianBlur(gray, (5,5), 0) _, thresh = cv.threshold(blur, 20, 255, cv.THRESH_BINARY) dilated = cv.dilate(thresh, None, iterations=3) # 查找轮廓 contours, _ = cv.findContours(dilated, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 每次检测运动前重置标记 motion_detected = False # 在检测到的轮廓周围绘制矩形 for contour in contours: (x, y, w, h) = cv.boundingRect(contour) if cv.contourArea(contour) < 1000: continue motion_detected = True cv.rectangle(frame1, (x, y), (x+w, y+h), (0,255,0), thickness=2) cv.putText(frame1, 'Status: {}'.format('Movement'), (10,20), cv.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), thickness=3) # 展示运动检测流 cv.imshow('Motion Feed', frame1) # 静止时长校验逻辑 current_ts = time.time() if face_exist and not motion_detected: if last_still_start is None: last_still_start = current_ts has_printed = False else: if current_ts - last_still_start >= 5 and not has_printed: print("检测到人脸静止满5秒") has_printed = True else: last_still_start = None has_printed = False # 按ESC键退出 c = cv.waitKey(1) if c == 27: break cap.release() cv.destroyAllWindows()
内容的提问来源于stack exchange,提问作者Ryan Ponsell
相关产品推荐
相关产品推荐

