「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」。
OpenCV
介绍
OpenCV 是一个跨平台计算机视觉库, 可以运行在 Linux、Windows、Android 和 Mac OS 操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了 Python、Ruby、MATLAB 等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
安装
在我们编码的过程中,会使用到OpenCV 的两个模块,我们直接使用 pip 安装:
pip install opencv-python
另外一个:
pip install opencv-contrib-python
安装完成后,我们就可以开始学习 OpenCV 的使用了。
使用 OpenCV 处理视频图像
处理图像
读取并显示图像
读取图像和显示图像是图像的最基本操作,在 OpenCV 中实现起来也非常简单,代码如下:
import cv2
# 读取图片
im = cv2.imread('test.png')
# 显示图片,第一个参数为窗口名称
cv2.imshow('img', im)
# 等待键盘输入
cv2.waitKey(0)
# 销毁所有窗口
cv2.destroyAllWindows()
在我们导入模块的时候,是导入 cv2,我们读取图像使用到 imread 函数,显示图像使用到 imshow 函数。因为 imshow 函数只会显示一瞬间,所以我们在后面添加一句 waitkey(),该函数传入毫秒值,当传入0时表示无限等待键盘输入。因为 OpenCV 是使用 C/C++ 实现的,所以我们需要销毁窗口(类似于 free)。
灰度转换
我们可以简单理解为将彩色图像转换为黑白图像,在人脸识别时,我们通常使用灰度转换后的图像进行识别。
import cv2
# 读取图像
im = cv2.imread('test.png')
# 灰度转换
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 保存图像
cv2.imwrite('im.png', grey)
# 销毁所有窗口
cv2.destroyAllWindows()
灰度转换我们使用到 cv2.cvtColor 函数,第一个参数为 ndarray 对象(图像),第二个是一个 cv2 中的常数。我们从常数名称可以看出,对于 OpenCV 来说,图片一般都是 BGR 而不是 RGB 的。
我们灰度转换后,使用 imwrite 函数保存图像。
绘制图形
然后我们来看看如何用 OpenCV 绘制图形:
import cv2
# 读取图像
im = cv2.imread('test.jpg')
# 绘制图形
cv2.rectangle(im, (10, 10), (50, 50), (0, 255, 0), 3)
cv2.circle(im, (100, 100), 50, (0, 0, 255), 2)
# 显示图像
cv2.imshow('im', im)
cv2.waitKey(0)
cv2.destroyAllWindows()
上面代码我们绘制了一个矩形和一个圆形。我们看一下两个方法:
"""
im:ndarray对象
p1:左上角的坐标
p2:右下角的坐标
color:颜色,格式为BGR
thickness:轮廓宽
"""
rectangle(im, p1, p2, color, thickness)
"""
im:ndarray对象
center:圆心坐标
radius:半径
color:颜色BGR格式
thickness:轮廓宽
"""
circle(im, center, radius, color, thickness)
这里只是说了些会用到的参数。代码的效果如下:
后续在我们人脸检测的过程中,我们可以绘制图形,将人脸框起来。
检测人脸
获取特称数据
我们实现人脸检测需要先下载 OpenCV 的特征数据,我们去 OpenCV 的官网下载相应的文件。进入我们可以看到如下界面:
下载后,我们双击运行就可以了。我们进入 opencv\sources\data\haarcascades 目录,会发现里面有许多特征文件。我们通常使用 haarcascade_frontalface_default.xml 作为特征数据。我是直接将特征文件复制到项目根目录下,你们可以选择和我一样,或者直接使用绝对路径。
检测人脸
检测人脸的步骤如下:
- 读取图像
- 灰度转换
- 获取人脸检测器
- 检测人脸
- 遍历人脸
我们将上面的步骤写成代码:
import cv2
# 读取图像
im = cv2.imread('face.jpg')
# 灰度转换
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 获取人脸检测器
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 检测人脸
faces = face_detector.detectMultiScale(grey)
# 遍历检测到的人脸
for x, y, w, h in faces:
# 在人脸区域绘制矩形
cv2.rectangle(im, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 显示图像
cv2.imshow('im', im)
cv2.waitKey(0)
cv2.destroyAllWindows()
我们使用 cv2.CascadeClassifier 方法,加载特征数据。然后我们使用 detectMultiScale 方法检测人脸,该函数返回人脸数据。face.jpg 和绘制矩形后的图形如下:
在试验过程中,发现通常情况下都可以检测出,但是失误的情况也比较多。
训练数据
训练数据主要是需要获得两个数据,一个是人脸标签,另一个是人脸数据。为了方便获取人脸标签,我们先准备好一些图片:
这里有 40 张图片,其中前 20 张是胡歌,后二十张是小罗伯特唐尼。后续我们可以用这些图片作为训练素材。我们识别这些人脸,获取其人脸数据,然后直接将文件名作为标签,这样我们就知道标签大于 20 的就是小罗伯特唐尼,而标签小于 20 的就是胡歌。
训练数据步骤大致如下:
- 获取人脸数据和标签数据
- 获取训练器
- 训练数据
- 保存训练数据
代码如下:
import cv2
import os
import numpy
# 人脸的根目录
root = './face/'
def getFacesAndLables():
# 用于存储人脸数据
faces = []
# 用于存储标签数据
labels = []
# 获取人脸检测器
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 获取图片路径
files = os.listdir(root)
for file in files:
# 读取图像
im = cv2.imread(root + file)
# 灰度转换
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 检测人脸
face = face_detector.detectMultiScale(grey)
for x, y, w, h in face:
# 设置标签
labels.append(int(file.split('.')[0]))
# 设置人脸数据
faces.append(grey[y:y+h, x:x+w])
return faces, labels
# 获取人脸数据和标签
faces, labels = getFacesAndLables()
# 获取训练对象
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 训练数据
recognizer.train(faces, numpy.array(labels))
# 保存训练数据
recognizer.write('./trainer.yml')
这里主要的代码还是获取人脸数据和人脸标签。获取训练对象我们通过 cv2.face.LBPHFaceRecognizer_create() 函数,该函数在 opencv-contrib-python 模块中。训练数据调用 train 函数,然后我们使用 write 保存训练数据。接下来我们就可以进行人脸识别了。
人脸识别
在训练好数据后我们就可以开始识别人脸了,识别人脸的步骤大致如下:
- 读取训练数据
- 读取图像
- 检测人脸
- 匹配数据
我们用代码实现:
import cv2
# 获取训练对象
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 加载训练数据
recognizer.read('trainer.yml')
# 读取图像
im = cv2.imread('Tony.jpg')
# 灰度转换
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 获取人脸检测对象
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 检测人脸
face = face_detector.detectMultiScale(grey)
for x, y, w, h in face:
# 匹配人脸
label, confidence = recognizer.predict(grey[y:y+h, x:x+w])
# 通过label判断识别结果
if confidence <= 60:
if label < 20:
print('胡歌')
elif label > 20:
print('小罗伯特唐尼')
else:
print('未匹配到人脸')
我们使用 read 方法加载训练数据,读取图像和检测人脸的操作我们已经说过了,然后我们使用 recognizer.predict 方法匹配人脸。该方法返回两个参数,一个是人脸标签,还有一个是可信度。confidence 的值越低,可信程度越高。然后我们通过获取的标签来判断,识别的人物是谁。
上面是我用来识别的图片,结果如下:
小罗伯特唐尼
这样我们就实现了人脸识别。因为训练数据比较少,所以识别的准确率也比较低,大家可以多使用一些图片进行进行训练,本文代码连接如下: