话不多说,上视频先看效果!
这里我使用cv_bridge + face_racognition在ROS系统下进行人脸识别项目的开发。关于face_recognition的内容大家可以自行百度,在CSDN可以直接下载整个项目。https://github.com/ageitgey/face_recognition
我这里也提供了我自己整理好的代码文件,github的太全面,不适合小白来看。想玩这个的话,需要熟练Python,熟悉Python OpenCV即可。
关于此次的项目设计,总共有三个功能包,人脸数据采集、人脸模型训练、人脸实时识别,原理的话就是通过usb_cam节点在ROS系统喜爱发布图像话题,通过Python编程订阅后使用cv_bridge转成Python OpenCV的数据格式,进行处理即可。
FaceData是数据集,里面有人脸样本数据、样本数据计算好的模型和haarcascade_frontalface_default分类器,最后这个是OpenCV自带的,我们区网上下载即可。
face_data_collect是人脸数据采集功能包,负责采集人脸图片,并自动进行处理,做成适合训练的样本数据。
face_training是人脸模型训练功能包,执行这个功能包之后会将人脸样本数据进行计算,做出来一个以yml为后缀名的模型文件。
face_recognition是人脸实时识别功能包,这里会调用我们训练好的模型进行实时人脸识别。
face_recognition_Demo是我整理github的face_recognition之后的代码,github的代码过于全面,这里我只留下来了最基础的Python例程。
接下来我们依次来解读这三个功能包。
face_data_collect人脸数据采集功能包
先贴代码,如下。
#!/usr/bin/env python3
#coding:utf-8
import rospy
import cv2
import os
import sys
import easygui
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
face_detector = cv2.CascadeClassifier('/home/ubuntu/catkin_ws/src/face_recognition/FaceData/haarcascade_frontalface_default.xml')
face_id = int(easygui.enterbox(msg="请输入当前人脸ID.",title="Warning"))
print('\n 正在拍摄人脸数据,请等待 ...')
count = 0
class image_converter:
def __init__(self):
# 创建cv_bridge,声明图像的发布者和订阅者
self.image_pub = rospy.Publisher("cv_bridge_image", Image, queue_size=1)
self.bridge = CvBridge()
self.image_sub = rospy.Subscriber("/usb_cam/image_raw", Image, self.callback)
def callback(self,data):
# 使用cv_bridge将ROS的图像数据转换成OpenCV的图像格式
try:
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(str(e))
global count
gray = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(gray, 1.3, 5)
for (x, y, w, h) in faces:
cv2.rectangle(cv_image, (x, y), (x+w, y+w), (255, 0, 0))
count += 1
cv2.imwrite('/home/ubuntu/catkin_ws/src/face_recognition/FaceData/face_data/User.' + str(face_id) + '.' + str(count) + '.jpg', gray[y: y + h, x: x + w])
cv2.imshow('FaceDataCollect', cv_image)
cv2.waitKey(1)
if count >= 100:
cv2.destroyAllWindows()
# 再将opencv格式额数据转换成ros image格式的数据发布
try:
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
except CvBridgeError as e:
print(str(e))
if __name__ == '__main__':
try:
# 初始化ros节点
rospy.init_node("face_data_collect")
rospy.loginfo("Starting face_data_collect node")
image_converter()
rospy.spin()
except KeyboardInterrupt:
print("Shutting down face_data_collect node.")
cv2.destroyAllWindows()
这段代码的作用是订阅/usb_cam/image_raw话题,并通过cv_bridge转换成Python OpenCV的数据格式进行处理。我们这里先将图像转成灰度图,然后使用人脸分类器进行人脸检测,检测到人脸的话会将当前人脸区域保存然后显示实时画面,否则直接显示实时画面。有个count变量是对采集到的人脸数据进行计数,这里我选择采集100章图片作为样本,样本数量越多、质量越好,训练的模型精准度就高,识别效果就越好。
face_training是人脸模型训练功能包
先贴代码,如下。
#!/usr/bin/env python3
#coding:utf-8
import numpy as np
from PIL import Image
import os
import cv2
path = '/home/ubuntu/catkin_ws/src/face_recognition/FaceData/face_data'
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier("/home/ubuntu/catkin_ws/src/face_recognition/FaceData/haarcascade_frontalface_default.xml")
def getImagesAndLabels(path):
imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
faceSamples = []
ids = []
for imagePath in imagePaths:
PIL_img = Image.open(imagePath).convert('L') # convert it to grayscale
img_numpy = np.array(PIL_img, 'uint8')
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('正在训练人脸模型数据,请等待...')
faces, ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
recognizer.write(r'/home/ubuntu/catkin_ws/src/face_recognition/FaceData/face_trainer/trainer.yml')
print("{0}组人脸模型数据训练完成,程序退出".format(len(np.unique(ids))))
这部分的代码没有涉及到ROS,只是读取上一步采集好的数据,通过recognition来进行训练,输出一个train.yml的模型文件即可。我们在识别的程序里面会调用这个文件进行人脸识别。
face_recognition人脸实时识别功能包
先贴代码,如下。
#!/usr/bin/env python3
#coding:utf-8
import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('/home/ubuntu/catkin_ws/src/face_recognition/FaceData/face_trainer/trainer.yml')
faceCascade = cv2.CascadeClassifier("/home/ubuntu/catkin_ws/src/face_recognition/FaceData/haarcascade_frontalface_default.xml")
font = cv2.FONT_HERSHEY_SIMPLEX
idnum = 0
names = ['LiHua', 'Alex','Walt']
minW = 0.1*640
minH = 0.1*480
class image_converter:
def __init__(self):
# 创建cv_bridge,声明图像的发布者和订阅者
self.image_pub = rospy.Publisher("cv_bridge_image", Image, queue_size=1)
self.bridge = CvBridge()
self.image_sub = rospy.Subscriber("/usb_cam/image_raw", Image, self.callback)
def callback(self,data):
# 使用cv_bridge将ROS的图像数据转换成OpenCV的图像格式
try:
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(str(e))
gray = cv2.cvtColor(cv_image, 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(cv_image, (x, y), (x+w, y+h), (0, 255, 0), 2)
idnum, confidence = recognizer.predict(gray[y:y+h, x:x+w])
if confidence < 100:
idnum = names[idnum]
confidence = "{0}%".format(round(100 - confidence))
else:
idnum = "unknown"
confidence = "{0}%".format(round(100 - confidence))
cv2.putText(cv_image, str(idnum), (x+5, y-5), font, 1, (0, 0, 255), 1)
cv2.putText(cv_image, str(confidence), (x+5, y+h-5), font, 1, (0, 0, 0), 1)
cv2.imshow('camera', cv_image)
cv2.waitKey(1)
# 再将opencv格式额数据转换成ros image格式的数据发布
try:
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
except CvBridgeError as e:
print(str(e))
if __name__ == '__main__':
try:
# 初始化ros节点
rospy.init_node("face_rocognition")
rospy.loginfo("Starting face_rocognition node")
image_converter()
rospy.spin()
except KeyboardInterrupt:
print("Shutting down face_rocognition node.")
cv2.destroyAllWindows()
这里的代码实现的就是大家最后看到的效果啦!原理也很简单,订阅/usb_cam/image_raw话题,并通过cv_bridge转换成Python OpenCV的数据格式进行处理。主要是将图像数据传入到我们声明的模型当中即可,通过x、y、w、h四个数值来确定人脸并绘制矩形将人脸框出。我们以confidence准确值来判断当前的人脸信息,并进行标注。
大家也可以自己跑一下,算是一个很简单的Demo吧~
编程的话,主要还是Python + OpenCV,然后使用了ROS的通讯机制——话题通讯、ROS的功能包——cv_bridge和usb_cam、ROS的工具——image_view,当然这个过程肯定是没有离开ROS社区的帮助,毕竟调试不出bug的代码是很罕见的。
最后吧,我还是说一句话~
ROS = 通讯机制+工具箱+功能包+社区
ROS只是一个工具,它不是核心。你的思想、你的代码才是项目的核心,一定一定一定不要本末倒置。
初入门者,切记!
评论(6)
您还未登录,请登录后发表或查看评论