树莓派4学习记录(5)-opencv人脸检测/识别(踩坑史....)

0. 安装opencv

当然之前已经安装好了opencv,详情见我的上一篇文章:
树莓派4学习记录(4)-摄像头

1. opencv人脸检测

先上代码:

# coding:utf-8

# 结论:直接使用opnecv可以实时监测人脸:
# imread: 0.0065610408782958984
# gray: 0.0018565654754638672
# classifier: 0.10116839408874512
# detect: 0.05451011657714844
# draw: 0.0002307891845703125
# write: 0.00553131103515625
# all: 0.1702742576599121

import cv2   
import time 

# 准备图片,并使用cv2读取
impath_1 = "new.jpg"
impath_2 = "new_2.jpg"
allstart = time.time()
image_1=cv2.imread(impath_1)
image_2=cv2.imread(impath_2)
print("imread:", time.time()- allstart)

# opencv进行人脸识别是基于灰度图,所以需要先转换为灰度图
start = time.time()
gray_1=cv2.cvtColor(image_1,cv2.COLOR_BGR2GRAY)
gray_2=cv2.cvtColor(image_2,cv2.COLOR_BGR2GRAY)
print("gray:", time.time()-start)

# 加载检测器
start = time.time()
face_cade=cv2.CascadeClassifier(r'./haarcascade_frontalface_default.xml')
print("classifier:", time.time()-start)

# 开始检测人脸
start = time.time()
fa_1=face_cade.detectMultiScale(gray_1,scaleFactor=1.15,minNeighbors=5)
fa_2=face_cade.detectMultiScale(gray_2,scaleFactor=1.15,minNeighbors=5)
print("detect:", time.time()-start)

# 在原始图片中绘制人脸框
start = time.time()
for (x,y,w,h) in fa_1:
    cv2.rectangle(image_1,(x,y),(x+w,y+h),(0,255.0),2)
for (x,y,w,h) in fa_2:
    cv2.rectangle(image_2,(x,y),(x+w,y+h),(0,255.0),2)
print("draw:", time.time()-start)

# 回写
start = time.time()
cv2.imwrite('cv_final.jpg',image_1)
cv2.imwrite('cv_final_2.jpg',image_2)
print("write:", time.time()-start)
print("all:", time.time()-allstart)

很明显发现我这里有很多测试,主要是用来检测每个操作的耗时,验证opencv是否能够作为实时人脸检测的方法。
结论:可以实时监测。
注意
这里我用到了一个opencv给出的人脸检测器,所以需要去opencv的repo中下载下来,放到当前目录中:
haarcascade_frontalface_default.xml
而这个检测器是针对正脸的,所以如果有其他需求,实际上是可以换的。
效果图
在这里插入图片描述

2. opencv+udp人脸实时检测

在已经验证使用opencv可以实时监测人脸后,我决定将其和UDP结合:

  1. 使用opencv获取视频流
  2. 使用opencv的人脸检测得到人脸框
  3. 将人脸框回写到数据流中
  4. 使用UDP传输到本地
  5. 本地显示带有人脸框的视频流

先上代码
server.py:

# coding: utf-8

import cv2
import numpy
import socket
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("192.168.1.6", 6000))
print("UDP bound on port 6000...")

print('now starting to send frames...')
capture=cv2.VideoCapture(0)
data, addr = s.recvfrom(1024)
# 设置分辨率
capture.set(3, 256)
capture.set(4, 256)

face_cade=cv2.CascadeClassifier(r'./haarcascade_frontalface_default.xml')

while True:
	success,frame=capture.read()
	# print(success)
	while not success and frame is None:
		success,frame=capture.read() #获取视频帧
	# the type of variable "frame" is : <class 'numpy.ndarray'>
	
	# 检测并绘制
	gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
	fa=face_cade.detectMultiScale(gray,scaleFactor=1.15,minNeighbors=5)
	for (x,y,w,h) in fa:
		cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255.0),2)
	
	result,imgencode=cv2.imencode('.jpg',frame,[cv2.IMWRITE_JPEG_QUALITY,50])
	s.sendto(struct.pack('i',imgencode.shape[0]), addr)
	s.sendto(imgencode, addr)
	# print('have sent one frame')

s.close()

client.py:

# coding: utf-8

import cv2
import numpy
import socket
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = ("192.168.1.6", 6000)

# 建立连接
data = 'hello'
s.sendto(data.encode(), addr)

print('now waiting for frames...')
while True:
	data, addr = s.recvfrom(65535)
	if len(data)==1 and data[0]==1: #如果收到关闭消息则停止程序
		s.close()
		cv2.destroyAllWindows()
		exit()
	if len(data)!=4: #进行简单的校验,长度值是int类型,占四个字节
		length=0
	else:
		length=struct.unpack('i',data)[0] #长度值
	data,address=s.recvfrom(65535)
	if length!=len(data): #进行简单的校验
		continue
	data=numpy.array(bytearray(data)) #格式转换
	imgdecode=cv2.imdecode(data,1) #解码
	# print('have received one frame')
	cv2.imshow('frames', imgdecode) #窗口显示
	if cv2.waitKey(1)==27: #按下“ESC”退出
		break

s.close()
cv2.destroyAllWindows()

可以发现,相对于之前的UDP+opencv实时视频流传输并没有增加多少的代码量,只是添加了一个读取检测器并识别的部分,相对来说还是很简单的。

3. opencv人脸识别

3.1 正文

当然并不会满足于只是人脸检测了,所以直接开始捣鼓人脸识别。
依旧还是使用opencv内置的人脸识别方法,不过还是需要训练的。
训练比较简单
可以参考这个
基于Opencv快速实现人脸识别(完整版)
基本的结构与作者的一致,不过训练集和测试集还是修改了一下,改成了
[zhoujielun, chenyixun]
应该知道是谁吧 (笑
上代码

# coding: utf-8 

import os
import numpy as np
import cv2

# 检测人脸
def detect_face(img):
    #将测试图像转换为灰度图像,因为opencv人脸检测器需要灰度图像
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
    #加载OpenCV人脸检测分类器Haar
    face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
 
    #检测多尺度图像,返回值是一张脸部区域信息的列表(x,y,宽,高)
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=5)
 
    # 如果未检测到面部,则返回原始图像
    if (len(faces) == 0):
        return None, None
 
    #目前假设只有一张脸,xy为左上角坐标,wh为矩形的宽高
    (x, y, w, h) = faces[0]
 
    #返回图像的正面部分
    return gray[y:y + w, x:x + h], faces[0]
 
 
# 该函数将读取所有的训练图像,从每个图像检测人脸并将返回两个相同大小的列表,分别为脸部信息和标签
def prepare_training_data(data_folder_path):
    # 获取数据文件夹中的目录(每个主题的一个目录)
    dirs = os.listdir(data_folder_path)
 
    # 两个列表分别保存所有的脸部和标签
    faces = []
    labels = []
 
    # 浏览每个目录并访问其中的图像
    for dir_name in dirs:
        # dir_name(str类型)即标签
        label = int(dir_name)
        # 建立包含当前主题主题图像的目录路径
        subject_dir_path = data_folder_path + "/" + dir_name
        # 获取给定主题目录内的图像名称
        subject_images_names = os.listdir(subject_dir_path)
 
        # 浏览每张图片并检测脸部,然后将脸部信息添加到脸部列表faces[]
        for image_name in subject_images_names:
            # 建立图像路径
            image_path = subject_dir_path + "/" + image_name
            # 读取图像
            image = cv2.imread(image_path)
            # 显示图像0.1s
            print("preparing the training images....")
            # cv2.imshow("Training on image...", image)
            # cv2.waitKey(100)
 
            # 检测脸部
            face, rect = detect_face(image)
            # 我们忽略未检测到的脸部
            if face is not None:
                #将脸添加到脸部列表并添加相应的标签
                faces.append(face)
                labels.append(label)
 
    cv2.waitKey(1)
    cv2.destroyAllWindows()
    #最终返回值为人脸和标签列表
    return faces, labels
 
#调用prepare_training_data()函数
faces, labels = prepare_training_data("training_data")
 
#创建LBPH识别器并开始训练,当然也可以选择Eigen或者Fisher识别器
face_recognizer = cv2.face.createLBPHFaceRecognizer()
face_recognizer.train(faces, np.array(labels))
 
#根据给定的(x,y)坐标和宽度高度在图像上绘制矩形
def draw_rectangle(img, rect):
    (x, y, w, h) = rect
    cv2.rectangle(img, (x, y), (x + w, y + h), (128, 128, 0), 2)
# 根据给定的(x,y)坐标标识出人名
def draw_text(img, text, x, y):
    cv2.putText(img, text, (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (128, 128, 0), 2)
 
#建立标签与人名的映射列表(标签只能为整数)
subjects = ["zhoujielun", "chenyixun"]
 
# 此函数识别传递的图像中的人物并在检测到的脸部周围绘制一个矩形及其名称
def predict(test_img):
    #生成图像的副本,这样就能保留原始图像
    img = test_img.copy()
    #检测人脸
    face, rect = detect_face(img)
    #预测人脸
    label = face_recognizer.predict(face)
    # 获取由人脸识别器返回的相应标签的名称
    label_text = subjects[label[0]]
 
    # 在检测到的脸部周围画一个矩形
    draw_rectangle(img, rect)
    # 标出预测的名字
    draw_text(img, label_text, rect[0], rect[1] - 5)
    #返回预测的图像
    return img
 
#加载测试图像
test_img1 = cv2.imread("test_data/test1.jpg")
test_img2 = cv2.imread("test_data/test2.jpg")
 
#执行预测
predicted_img1 = predict(test_img1)
predicted_img2 = predict(test_img2)
 
#显示两个图像
cv2.imshow(subjects[0], predicted_img1)
cv2.imshow(subjects[1], predicted_img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

具体的每一部分实现了什么功能,都显示在代码注释中。
效果
应
还可以吼…

3.2 踩坑(回应题目)
3.2.1 关于API

可以很明显发现,这里人脸识别,先用到了人脸检测,而之前的人脸检测并没有什么大问题,所以很明显问题出现在人脸识别过程中。
人脸识别最主要的两个部分:

  1. 人脸数据集训练
  2. 人脸预测

问题出现在了第一部分:
face_recognizer = cv2.face.createLBPHFaceRecognizer()
刚开始代码使用的并不是这个API,而是:
LBPHFaceRecognizer_create()
肯定会理所当然的报错了,因为我使用的python环境为3.7,所以要使用代码中给出的API,因为换名了…
(我就想说,换个蛇皮的名啊,代码一致性啊,一致性啊,别换来换去的)

3.2.2 关于安装依赖包

如果要运行起来还需要安装一个依赖包:
opencv-contrib-python

pip3 install opencv-contrib-python

安装好之后才能够不出错,如果出现其他错误怎么办?
这个我也不知道,因为我之前已经将其依赖库安装的差不多了,所以最好安装好所有的依赖库,什么apt什么pip尽管安装,准没错。
还有要注意版本一致性,我直接使用的默认版本,如果有特殊要求,最好指定版本。

3.2.3 解决出错
ImportError: /home/pi/cv2/cv2.cpython-37m-arm-linux-gnueabihf.so: undefined symbol: __atomic_fetch_add_8

参考这个:
树莓派上安装Opencv遇到的小bug解决方法
其实就是在配置文件中手动添加一个库。

/usr/lib/arm-linux-gnueabihf/libatomic.so.1

具体的解决办法参考上面的文档。

4. opencv+udp人脸实时识别

这一部分相当于是将人脸识别模块和UDP传输模块结合起来,原理很简单,但是仍然有一部分需要注意,因为要保证实时性,所以某些功能并不能大量重复。需要适当调整代码结构。
server.py:

# coding: utf-8

import cv2
import numpy as np 
import socket
import struct
import os

#加载OpenCV人脸检测分类器Haar
# 放在这儿减少延迟
# face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')

# 检测人脸
def detect_face(img):
    #将测试图像转换为灰度图像,因为opencv人脸检测器需要灰度图像
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
    #检测多尺度图像,返回值是一张脸部区域信息的列表(x,y,宽,高)
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=6)
 
    # 如果未检测到面部,则返回原始图像
    if (len(faces) == 0):
        return None, None
 
    #目前假设只有一张脸,xy为左上角坐标,wh为矩形的宽高
    (x, y, w, h) = faces[0]
 
    #返回图像的正面部分
    return gray[y:y + w, x:x + h], faces[0]

# 该函数将读取所有的训练图像,从每个图像检测人脸并将返回两个相同大小的列表,分别为脸部信息和标签
def prepare_training_data(data_folder_path):
    # 获取数据文件夹中的目录(每个主题的一个目录)
    dirs = os.listdir(data_folder_path)
 
    # 两个列表分别保存所有的脸部和标签
    faces = []
    labels = []
 
    # 浏览每个目录并访问其中的图像
    for dir_name in dirs:
        # dir_name(str类型)即标签
        label = int(dir_name)
        # 建立包含当前主题主题图像的目录路径
        subject_dir_path = data_folder_path + "/" + dir_name
        # 获取给定主题目录内的图像名称
        subject_images_names = os.listdir(subject_dir_path)
 
        # 浏览每张图片并检测脸部,然后将脸部信息添加到脸部列表faces[]
        for image_name in subject_images_names:
            # 建立图像路径
            image_path = subject_dir_path + "/" + image_name
            # 读取图像
            image = cv2.imread(image_path)
            # 显示图像0.1s
            # print("preparing the training images....")
            # cv2.imshow("Training on image...", image)
            # cv2.waitKey(100)
 
            # 检测脸部
            face, rect = detect_face(image)
            # 我们忽略未检测到的脸部
            if face is not None:
                #将脸添加到脸部列表并添加相应的标签
                faces.append(face)
                labels.append(label)
 
    cv2.waitKey(1)
    cv2.destroyAllWindows()
    #最终返回值为人脸和标签列表
    return faces, labels

#根据给定的(x,y)坐标和宽度高度在图像上绘制矩形
def draw_rectangle(img, rect):
    (x, y, w, h) = rect
    cv2.rectangle(img, (x, y), (x + w, y + h), (128, 128, 0), 2)
# 根据给定的(x,y)坐标标识出人名
def draw_text(img, text, x, y):
    cv2.putText(img, text, (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (128, 128, 0), 2)


print("preparing the face model")
#调用prepare_training_data()函数
faces, labels = prepare_training_data("training_data")

#创建LBPH识别器并开始训练,当然也可以选择Eigen或者Fisher识别器
face_recognizer = cv2.face.createLBPHFaceRecognizer()
face_recognizer.train(faces, np.array(labels))

#建立标签与人名的映射列表(标签只能为整数)
subjects = ["mama", "yichen", "jiejie", "xiangyu"]

# 此函数识别传递的图像中的人物并在检测到的脸部周围绘制一个矩形及其名称
def predict(img):
    #生成图像的副本,这样就能保留原始图像
    # img = test_img.copy()
    # print(img)
    #检测人脸
    face, rect = detect_face(img)
    if face is None:
      return img
    #预测人脸
    label = face_recognizer.predict(face)
    print(label)
    # 获取由人脸识别器返回的相应标签的名称
    label_text = subjects[label[0]]
 
    # 在检测到的脸部周围画一个矩形
    draw_rectangle(img, rect)
    # 标出预测的名字
    draw_text(img, label_text, rect[0], rect[1] - 5)
    #返回预测的图像
    return img

# opencv 创建视频抓取对象
capture=cv2.VideoCapture(0)
# 设置分辨率
capture.set(3, 256)
capture.set(4, 256)

# 建立套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("192.168.1.6", 6000))

print("UDP bound on port 6000...")
print("waiting for connection....")

# 等待客户端请求
data, addr = s.recvfrom(1024)

print('now starting to send frames...')
while True:
	# 以下尝试抓取视频帧
	success,frame=capture.read()
	while not success and frame is None:
		success,frame=capture.read() #获取视频帧
  
	# 人脸识别入口
	predicted_img = predict(frame)

	# 编码并发送
	result,imgencode=cv2.imencode('.jpg', predicted_img, [cv2.IMWRITE_JPEG_QUALITY,50])
	s.sendto(struct.pack('i', imgencode.shape[0]), addr)
	s.sendto(imgencode, addr)

s.close()

有点长…不过问题不大,基本上所有功能都在这里了(简单的那种)。
效果还可以:
在这里插入图片描述
不过在实际运行的时候还是有下面的问题:

  1. 检测框抖动,可能过于灵敏
  2. 基本完成了识别任务的功能,但是容易误识别
  3. 无法设置识别阈值(我现在还没找到)
  4. 识别模型可能过于简单,容易出错
  • 1
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要下载树莓派人脸识别SDK,首先需要在官方网站或其他可信的技术网站上搜索相关的SDK。可以使用搜索引擎,输入关键词“树莓派人脸识别SDK下载”来查找相关软件。挑选一个合适的SDK下载链接,确保其与树莓派设备兼容。 点击下载链接后,进入下载页面,选择适用于树莓派的版本,通常会有树莓派的图标或者在系统要求中提到树莓派。确认无误后,点击下载按钮。 下载完成后,将SDK文件保存到树莓派的合适位置,可以选择将其保存到SD卡或者任意目录。 根据SDK的具体要求和文档,进行安装和配置。这一步可以参考SDK提供的官方文档或者操作指南来进行。 安装和配置完成后,就可以开始使用树莓派人脸识别SDK了。根据SDK的使用方式,编写代码,实现人脸识别的功能。可以通过调用SDK的API来实现人脸检测识别和比对等功能。 在使用SDK的过程中,可以根据需求进行自定义设置,如设置阈值、调整人脸识别的精度和速度,以及配置相机和摄像头等参数。 最后,根据自己的实际应用场景,将人脸识别功能好好利用起来,可以用于监控系统、门禁系统、智能家居等方面。 总之,要下载树莓派人脸识别SDK,先搜索并选择合适的SDK,下载并安装到树莓派上,然后根据具体文档进行配置和编程,最终实现人脸识别的功能。 ### 回答2: 要下载树莓派人脸识别SDK,首先需要确定你所需要的SDK具体是哪一家公司或开发者提供的。树莓派作为一款开源硬件,拥有广泛的支持和社区,因此有许多不同的人脸识别SDK可供选择。 一种下载的方式是通过访问官方网站下载。首先,你需要搜索相关的人脸识别SDK提供商的官方网站。在网站的下载页面,通常会提供对于树莓派的支持和下载链接。你可以浏览他们的网站,找到适用于树莓派的SDK版本并下载。在下载之前,确保你选择的版本和树莓派的硬件和操作系统相匹配。 另一种方式是通过基于树莓派的操作系统(如Raspbian)的软件库进行下载。树莓派的操作系统通常会提供一些常用的SDK,并且可以通过包管理器(如apt-get)来安装。你可以在命令行中运行适当的命令来搜索和安装树莓派人脸识别SDK。确保你的操作系统已经更新到最新版本,以保证软件库中有最新的SDK可供下载。 无论你选择哪种方式,下载时要确保选择信誉良好的提供商,以获得更好的技术支持和保障。在下载前,建议查看一些用户对该SDK的评价和反馈,了解其性能和可靠性。另外,阅读相关的文档和教程可以帮助你更好地了解和使用该SDK,以便你能够更好地将其整合到你的树莓派项目中。 ### 回答3: 要下载树莓派人脸识别SDK非常简单。首先,你需要打开树莓派的操作系统,确保你已经连接到互联网。然后,使用浏览器访问相关的网站或官方社区。在搜索框中输入“树莓派人脸识别SDK下载”,然后点击搜索按钮。 在搜索结果中,你会看到各种不同的下载选项。注意选择适合你需求的版本和文件类型。一般来说,官方社区或软件开发者网站是最安全和可靠的下载来源。 点击选定的下载链接后,等待文件下载完成。下载时间取决于你的互联网连接速度和文件大小。 一旦下载完成,你需要找到文件保存的位置并解压缩。这通常涉及到右键点击文件并选择“解压缩”选项。如果你不熟悉解压缩文件的操作,可以搜索相关的指导教程。 解压缩后,你会得到一个包含SDK的文件夹。你可以将该文件夹移动到你喜欢的位置,以便方便访问。 现在,你已经成功下载和准备好使用树莓派人脸识别SDK了。你可以从文件夹中找到示例代码和文档,以帮助你开始开发或使用该SDK。 希望这个简单的指南对你有所帮助!祝你下载并使用SDK时顺利!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值