目录
随着智能安防需求的增长,基于人工智能和物联网的安保系统逐渐成为趋势。树莓派因其低成本、高扩展性等特点,成为很多AI项目的理想平台。本文将为大家介绍如何使用树莓派打造一款智能安保巡逻机器人。本篇是系列的第一部分,将聚焦于“快速人脸录入与精准人脸识别”的实现步骤。
本篇文章旨在通过搭建基于树莓派的安保巡逻机器人,实现人脸录入和识别功能。巡逻机器人将通过摄像头捕捉人脸信息,进行实时识别和数据存储,以实现自动化安保监控
树莓派5B作为一款小巧、功能强大的计算机设备,为快速人脸录入和精准识别提供了一个理想的硬件平台。本文将通过详细的代码示例,讲解如何利用树莓派5B与Python实现一个高效的人脸检测和识别系统。该系统可以实时捕捉人脸信息,进行边缘检测与处理,适用于智能安防、出入控制等多种场景。
由于不同需求,首先我们先进行一下人脸检测功能
我们将利用Python的Mediapipe和OpenCV库来完成图像处理,Picamera2库驱动树莓派的摄像头。(Mediapipe库是Google开源的多媒体处理框架,适用于多种机器学习任务;而OpenCV则是一个强大的计算机视觉库,广泛应用于图像处理、模式识别等领域。)以下是主要代码片段及其实现细节。
- #!/usr/bin/env python3
- # encoding: utf-8
-
- import mediapipe as mp
- import cv2 as cv
- from picamera2 import Picamera2
为了简化人脸检测的实现,我们定义了一个FaceDetector类。该类使用Mediapipe的人脸检测模块,并在初始化时设置最小检测置信度参数minDetectionCon,以控制检测的灵敏度。
- class FaceDetector:
- def __init__(self, minDetectionCon=0.5):
- # 初始化人脸检测模块,并设置最小检测置信度
- self.mpFaceDetection = mp.solutions.face_detection
- self.facedetection = self.mpFaceDetection.FaceDetection(min_detection_confidence=minDetectionCon)
在findFaces方法中,首先将捕获的图像从BGR格式转换为RGB格式。这样做是因为Mediapipe库使用的是RGB格式的图像输入。随后,调用self.facedetection.process(img_RGB)来检测人脸。
- def findFaces(self, frame):
- # 将图像从BGR转换为RGB,因为MediaPipe使用的是RGB格式
- img_RGB = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
-
- # 处理图像,检测人脸
- results = self.facedetection.process(img_RGB)
-
- # 如果检测到人脸,则在图像上绘制矩形框
- if results.detections:
- for detection in results.detections:
- # 获取人脸的边界框相对坐标
- bboxC = detection.location_data.relative_bounding_box
- ih, iw, _ = frame.shape # 获取图像的高度和宽度
- # 将相对坐标转换为绝对坐标
- bbox = int(bboxC.xmin * iw), int(bboxC.ymin * ih), \
- int(bboxC.width * iw), int(bboxC.height * ih)
- # 在图像上绘制人脸矩形框
- cv.rectangle(frame, (bbox[0], bbox[1]), (bbox[0] + bbox[2], bbox[1] + bbox[3]), (255, 0, 255), 2)
- return frame
在主程序中,我们通过Picamera2捕获视频流,将YUYV格式的图像转换为BGR格式,使用findFaces方法来检测人脸,并将检测到的人脸信息实时显示在窗口中
- if __name__ == '__main__':
- picam2 = Picamera2()
- config = picam2.create_preview_configuration(main={"format": 'YUYV', "size": (320, 240)})
- picam2.configure(config)
- picam2.start()
-
- face_detector = FaceDetector(0.75)
- while True:
- frame = picam2.capture_array()
-
- # 将YUYV格式的图像转换为BGR
- frame = cv.cvtColor(frame, cv.COLOR_YUV2BGR_YUYV)
-
- # 检测人脸并水平翻转图像
- frame = face_detector.findFaces(cv.flip(frame, 1))
-
- cv.imshow('frame', frame)
- if cv.waitKey(1) & 0xFF == ord('q'):
- break
-
- cv.destroyAllWindows()
完整代码如下:
- #!/usr/bin/env python3
- # encoding: utf-8
- import mediapipe as mp
- import cv2 as cv
- from picamera2 import Picamera2
-
- class FaceDetector:
- def __init__(self, minDetectionCon=0.5):
- # 初始化人脸检测模块,并设置最小检测置信度
- self.mpFaceDetection = mp.solutions.face_detection
- self.facedetection = self.mpFaceDetection.FaceDetection(min_detection_confidence=minDetectionCon)
-
- def findFaces(self, frame):
- # 将图像从BGR转换为RGB,因为MediaPipe使用的是RGB格式
- img_RGB = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
-
- # 处理图像,检测人脸
- results = self.facedetection.process(img_RGB)
-
- # 如果检测到人脸,则在图像上绘制矩形框
- if results.detections:
- for detection in results.detections:
- # 获取人脸的边界框相对坐标
- bboxC = detection.location_data.relative_bounding_box
- ih, iw, _ = frame.shape # 获取图像的高度和宽度
- # 将相对坐标转换为绝对坐标
- bbox = int(bboxC.xmin * iw), int(bboxC.ymin * ih), \
- int(bboxC.width * iw), int(bboxC.height * ih)
- # 在图像上绘制人脸矩形框
- cv.rectangle(frame, (bbox[0], bbox[1]), (bbox[0] + bbox[2], bbox[1] + bbox[3]), (255, 0, 255), 2)
- return frame
-
- if __name__ == '__main__':
- picam2 = Picamera2()
- config = picam2.create_preview_configuration(main={"format": 'YUYV', "size": (320, 240)})
- picam2.configure(config)
- picam2.start()
-
- face_detector = FaceDetector(0.75)
- while True:
- frame = picam2.capture_array()
-
- # 将YUYV格式的图像转换为BGR
- frame = cv.cvtColor(frame, cv.COLOR_YUV2BGR_YUYV)
-
- # 检测人脸并水平翻转图像
- frame = face_detector.findFaces(cv.flip(frame, 1))
-
- cv.imshow('frame', frame)
- if cv.waitKey(1) & 0xFF == ord('q'):
- break
-
- cv.destroyAllWindows()
-

在实现人脸识别前,我们需要采集用户的人脸图像样本,建立一个基本的人脸数据库。为确保系统的高效和准确性,需采集多张人脸图像以便后续的人脸识别模型可以更好地学习每个用户的特征。
在本部分中,我们将利用OpenCV库采集人脸样本,并将这些图像存储在本地文件夹中。代码如下:
- #利用opencv采集人脸(拍照)
- import cv2
- import os
- import time
- # 初始化摄像头
- cam = cv2.VideoCapture(0)
- cam.set(3, 640) # 设置视频宽度为640像素
- cam.set(4, 480) # 设置视频高度为480像素
-
- # 加载人脸检测的分类器
- face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
-
- # 输入用户ID,用于标识不同的用户
- face_id = input('\n 输入用户ID并按回车 ==> ')
-
- print("\n [信息] 初始化人脸采集。看向摄像头等待...")
- # 初始化单独采样人脸计数
- count = 0
-
- while(True):
- # 读取摄像头的一帧图像
- ret, img = cam.read()
- # 将图像上下翻转
- img = cv2.flip(img, 1) # 垂直翻转视频图像
- # 将图像转换为灰度图,以提高处理速度
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- # 检测图像中的人脸
- faces = face_detector.detectMultiScale(gray, 1.3, 5)
-
- # 对于检测到的每一个人脸
- for (x,y,w,h) in faces:
- # 在图像上绘制矩形框
- cv2.rectangle(img, (x,y), (x+w,y+h), (255,0,0), 2)
- # 增加人脸计数
- count += 1
-
- # 将捕捉到的人脸保存到datasets文件夹中
- cv2.imwrite("dataset/User." + str(face_id) + '.' + str(count) + ".jpg", gray[y:y+h,x:x+w])
-
- # 显示处理后的图像
- cv2.imshow('image', img)
- print("ok")
- time.sleep(0.2)
-
- # 按ESC退出视频
- k = cv2.waitKey(100) & 0xff
- if k == 27:
- break
- # 如果采集了30个样本,则停止视频
- elif count >= 30:
- break
-
- # 清理工作
- print("\n [信息] 退出程序并清理资源")
- cam.release() # 释放摄像头
- cv2.destroyAllWindows() # 关闭所有OpenCV窗口
运行代码,输入用户ID:

按下回车进行人脸信息采集:
保存数据如下:
在完成了人脸图像的采集之后,接下来我们需要对这些图像进行训练,以便系统能够识别不同的用户。我们将使用OpenCV的LBPH(局部二值模式直方图)人脸识别算法进行训练。
LBPH (Local Binary Patterns Histogram) 是一种常用于人脸识别的特征提取方法,主要基于局部纹理信息来描述图像特征。它通过分析图像局部区域内像素的灰度关系,提取出具有高度差异性的特征,从而能够在光照、表情变化等方面取得较为鲁棒的识别效果。LBPH 是一种经典且有效的人脸识别方法。
以下是训练模型的代码实现:
- import cv2
- import numpy as np
- from PIL import Image
- import os
-
- # 人脸图像数据库的路径
- path = 'dataset'
-
- # 创建LBPH人脸识别器
- recognizer = cv2.face.LBPHFaceRecognizer_create()
- # 使用Haar特征分类器进行人脸检测
- detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml");
-
- # 函数:获取图像和标签数据
- def getImagesAndLabels(path):
- # 获取数据库中所有图像的路径
- imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
- faceSamples = [] # 存储人脸样本
- ids = [] # 存储每张人脸的ID
-
- for imagePath in imagePaths:
- # 打开图像并将其转换为灰度图
- PIL_img = Image.open(imagePath).convert('L')
- # 将灰度图转换为numpy数组
- img_numpy = np.array(PIL_img, 'uint8')
-
- # 获取图像文件名中的ID,假设文件名格式为:User.ID.xxx.jpg
- id = int(os.path.split(imagePath)[-1].split(".")[1])
- # 检测人脸位置
- faces = detector.detectMultiScale(img_numpy)
-
- # 遍历检测到的人脸区域,将每个区域保存到样本和标签列表中
- for (x, y, w, h) in faces:
- faceSamples.append(img_numpy[y:y+h, x:x+w])
- ids.append(id)
-
- return faceSamples, ids
-
- print ("\n [信息] 训练人脸中,请稍候...")
- # 获取所有人脸样本和对应的ID
- faces, ids = getImagesAndLabels(path)
- # 训练LBPH人脸识别器
- recognizer.train(faces, np.array(ids))
-
- # 将训练好的模型保存到trainer/trainer.yml
- recognizer.write('trainer/trainer.yml') # recognizer.save()在Mac上可用,但在Pi上不可用
-
- # 输出训练的人脸数量并结束程序
- print("\n [信息] 训练了 {0} 张人脸。程序结束".format(len(np.unique(ids))))

运行代码进行训练,结果将得到一个trainer.yml文件,此文件保存着用户对应的LBPH相关数值

在成功训练完人脸识别模型后,我们将进入实际的识别环节。接下来,我们会使用摄像头实时捕捉视频流,并通过模型识别出画面中的人脸。
以下是实时人脸识别的代码实现:
- import cv2
- import numpy as np
- import os
- import time
-
- # 创建LBPH人脸识别器并加载训练好的模型
- recognizer = cv2.face.LBPHFaceRecognizer_create()
- recognizer.read('trainer/trainer.yml')
-
- # 加载Haar特征分类器用于人脸检测
- cascadePath = "haarcascade_frontalface_default.xml"
- faceCascade = cv2.CascadeClassifier(cascadePath)
-
- font = cv2.FONT_HERSHEY_SIMPLEX
-
- # 初始化ID计数器
- id = 0
-
- # ID与姓名的对应关系
- names = ['None', 'ID=1', 'ID=2', 'ID=3', 'Z', 'W']
-
- # 初始化并开始实时视频捕捉
- cam = cv2.VideoCapture(0)
- cam.set(3, 640) # 设置视频宽度
- cam.set(4, 480) # 设置视频高度
-
- # 定义识别为人脸的最小窗口大小
- minW = 0.1 * cam.get(3)
- minH = 0.1 * cam.get(4)
- frame_count, pTime, cTime = 0, 0, 0
-
- while True:
- ret, img = cam.read() # 从摄像头读取图像
- img = cv2.flip(img, 1) # 垂直翻转图像
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图
-
- # 检测人脸
- faces = faceCascade.detectMultiScale(
- gray,
- scaleFactor=1.2,
- minNeighbors=5,
- minSize=(int(minW), int(minH)),
- )
-
- # 遍历检测到的人脸
- for (x, y, w, h) in faces:
- cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) # 绘制人脸框
- id, confidence = recognizer.predict(gray[y:y + h, x:x + w]) # 识别人脸
-
- if confidence < 70: # 置信度小于70
- id = names[id] # 获取对应的姓名
- confidence = " {0}%".format(round(100 - confidence)) # 计算置信度
- else:
- id = "unknown" # 识别为未知
- confidence = " {0}%".format(round(100 - confidence))
-
- # 显示姓名和置信度
- cv2.putText(img, str(id), (x + 5, y - 5), font, 1, (255, 255, 255), 2)
- cv2.putText(img, str(confidence), (x + 5, y + h - 5), font, 1, (255, 255, 0), 1)
-
- frame_count += 1 # 帧计数
- cTime = time.time() # 当前时间
- fps = 1 / (cTime - pTime) # 计算FPS
- pTime = cTime # 更新上一帧时间
- text = "FPS : " + str(int(fps)) # 显示FPS
- cv2.putText(img, text, (20, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 1)
-
- cv2.imshow('camera', img) # 显示摄像头画面
- k = cv2.waitKey(10) & 0xff # 按'ESC'键退出视频
- if k == 27:
- break
-
- # 清理工作
- print("\n [信息] 退出程序并清理资源")
- cam.release() # 释放摄像头
- cv2.destroyAllWindows() # 关闭所有OpenCV窗口

此方法可以快速人脸录入(30秒)与模型训练最后依旧可以精准人脸识别。
本文介绍了如何在树莓派5B上实现快速的人脸录入与精准的人脸识别。从采集人脸图像、训练人脸数据库,再到使用LBPH进行实时识别,我们完成了一套简单但有效的人脸识别系统。LBPH特征提取方法在资源有限的设备上表现出色,能够在保证准确率的同时实现实时检测。
完整资料与代码下载:【免费】基于树莓派的安保巡逻机器人-(一、快速人脸录入与精准人脸识别)资源-CSDN文库
参考资料:基于Anirban Kar的代码https://github.com/thecodacus/Face-Recognition