尝试使用 OpenCV、Haar Cascades 和 Raspberry PI 对人脸进行计数

Trying to Count Faces Using OpenCV, Haar Cascades and Raspberry PI

所以我有一个小道摄像头项目,通过检测人脸来计算进入小道的人数。没有可用的电源,所以出于电源原因我只能使用 Raspberry Pi 3 B+。我目前正在使用 opencv 和 Haar 级联来检测人脸。我的问题有两个。

  1. 第一个是我的计数器的行为更像一个计时器。在它被锁定在它认为是一张脸的任何东西上的整个时间里,它都会继续增加。我需要的行为是让它在检测到时仅递增一次,直到检测丢失然后重新初始化时才递增。如果检测到多张面孔,我也需要这个来工作。
  2. 第二个问题是 Haar 级联不擅长检测人脸。我一直在玩参数,但似乎无法获得很好的结果。还尝试了其他方法,如 Dlib,但帧率使其在 pi 3 上几乎无法使用。

我将在下面 post 我的代码(通过结合几个示例拼凑而成)。目前,它也被设置为使用线程(另一个试图挤出更多性能的实验)。据我所知,线程正在工作,但似乎并没有真正改善任何东西。非常感谢你们为解决计数器问题或优化 Haar Cascades 以在 Pi 上使用提供的任何帮助。 ** 还应注意使用 Rasp Pi 高质量相机和 Ardu Cam 镜头。

from __future__ import print_function
from imutils.video import VideoStream
from imutils.video.pivideostream import PiVideoStream
from imutils.video import FPS
from picamera.array import PiRGBArray
from picamera import PiCamera
import argparse
import imutils
import time
import cv2

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-c", "--cascade", type=str,
    default="haarcascade_frontalface_default.xml",
    help="path to haar cascade face detector")
args = vars(ap.parse_args())

detector = cv2.CascadeClassifier(args["cascade"])

size = 40
counter = 0

# created threaded video
print("[INFO] using threaded frames")
vs = PiVideoStream().start()
time.sleep(2.0)


# loop over some frames...this time using the threaded stream
while True:
    # grab the frame from the threaded video stream and resize it
    # to have a maximum width of 400 pixels (trying larger frame size)
    frame = vs.read()
    frame = imutils.resize(frame, width=450)
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # perform face detection
    rects = detector.detectMultiScale(gray, scaleFactor=1.05,
        minNeighbors=6, minSize=(size, size),
        flags=cv2.CASCADE_SCALE_IMAGE)


    # loop over the bounding boxes
    for (x, y, w, h) in rects:
        # draw the face bounding box on the image
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
        
        # Increment counter when face is found
        counter += 1
        print(counter)
        

    # show the output frame
    cv2.imshow("Frame", frame)
    key = cv2.waitKey(1) & 0xFF


# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()

首先,你可以像你说的那样使用 Dlib,但你必须使用“HOG”方法(定向梯度直方图)而不是“CNN”来提高性能。

locations = face_recognition.face_locations(frame, model="hog")

但是,如果您真的想获得更快的性能,我建议您为此目的使用 Mediapipe。

在您的 rpi3 上下载 Mediapipe:

sudo pip3 install mediapipe-rpi3

下面是 Mediapipe 文档中的人脸检测器示例代码:

import cv2
import mediapipe as mp

mp_face_detection = mp.solutions.face_detection
mp_drawing = mp.solutions.drawing_utils

# For webcam input:
cap = cv2.VideoCapture(0)
with mp_face_detection.FaceDetection(
    model_selection=0, min_detection_confidence=0.5) as face_detection:
  while cap.isOpened():
    success, image = cap.read()
    if not success:
      print("Ignoring empty camera frame.")
      # If loading a video, use 'break' instead of 'continue'.
      continue

    # To improve performance, optionally mark the image as not writeable to
    # pass by reference.
    image.flags.writeable = False
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    results = face_detection.process(image)

    # Draw the face detection annotations on the image.
    image.flags.writeable = True
    image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
    if results.detections:
      for detection in results.detections:
        mp_drawing.draw_detection(image, detection)
    # Flip the image horizontally for a selfie-view display.
    cv2.imshow('MediaPipe Face Detection', cv2.flip(image, 1))
    if cv2.waitKey(5) & 0xFF == 27:
      break
cap.release()

我不确定您将获得多少 FPS(但肯定比 Dlib 好并且非常准确),但是您可以通过每三帧而不是所有帧检测人脸来提高性能。

其次,您可以采用一种可能会正常工作的简单方法。 您可以在上次检测中提取边界框的中心,如果前一帧的中心在当前帧中人脸的边界框内,则可能是同一个人。

您可以通过确定当前帧中人脸的新中心(他的边界框的中心)是否足够接近上一帧中最后一个中心的偏移量来更准确地完成此操作选择。如果是,那可能是同一张脸所以不要算了。

可视化:

希望它对你有用!