小啾带你开天眼 之 人脸检测与识别(以及华强、皇叔、高祖配墨镜特效)【Python-Open_CV系列(十三)】

简介: 小啾带你开天眼 之 人脸检测与识别(以及华强、皇叔、高祖配墨镜特效)【Python-Open_CV系列(十三)】

文章目录

①素材准备

②人脸检测

(一)级联分类器 与 相关方法介绍

(二)检测人脸

③华强、皇叔、高祖配墨镜

④人脸识别

①素材准备

正式开始之前,首先要解决的是素材问题。


大家在学习过程中可以直接从百度上自选图片。比如,小啾准备了以下图片素材。并将其放在demo.py的当前目录下的picture文件夹中。小啾文件命名使用的是演员简称+序号的形式,cdm_1.jpg至cdm_5.jpg,shl_1.jpg至shl_5.jpg,yhw_1.jpg到yhw_5.jpg,共计三个人,十五张图。

image.png

提示:准备图像素材时,尽量选择大小相近的,至少不能有的高>宽,有的宽>高这样的混合选择,否则这样会给后边的处理过程带来很大不便。后边需要把每个图像的shape调整一致。

②人脸检测

所谓人脸检测,即从一幅图片中找出人脸的位置,OpenCV已经将具体的算法封装完毕,我们只需调用即可。

(一)级联分类器 与 相关方法介绍

OpenCV提供了一些已经训练好的级联分类器,这些级联分类器的位置在cv2文件夹内的data文件夹中,如下图所示,这些XML文件即为级联分类器:image.png

其中,不同分类器的功能是也有所不同的。

比如,haarcascade_eye.xml是用来 检测眼睛的;

haarcascade_eye_tree_eyeglasses.xml是用来检测眼镜的;

haarcascade_frontalcatface.xml是用来检测正面猫脸的;

haarcascade_frontalcatface_extended.xml,即正面猫脸的拓展

haarcascade_frontalface_default.xml,haarcascade_frontalface_alt.xml,haarcascade_frontalface_alt2.xml,haarcascade_frontalface_alt_tree.xml是什么都是用来检测正面人脸的。算法不同,效果也可能会有所不同。具体选择要根据对需求的测试和进一步的学习。

haarcascade_fullbody.xml是用来减少人的存在(身体)的;

haarcascade_lefteye_2splits.xml用于检测左眼…


这里就暂先列举这么多,更多级联分类器可以自行了解。


相关的方法

使用级联分类器,首先需要使用cv2.CascadeClassifier()方法创建出一个级联分类器对象Cascade,其语法为


Cascade = cv2.CascadeClassifier(filename)


其中filename即级联分类器的文件名及所在目录。


===============================================


创建好级联分类器后,使用detectMultiScale()方法对图像进行识别,detectMultiScale()方法的语法为


objects = Cascade.detectMultiScale(image, scaleFactor, minNeighbors, flags, minSize, maxSize)


其中,image即原图像,scaleFactor是扫描时的缩放比例(可选);minNeighbors是指每个检测区域至少保留多少个结果才能检测为人脸,值越大分析误差越小,但是也越容易识别不出。(可选)minSize指最小的目标尺寸,maxSize指最大的目标尺寸,都可选。 flags为旧版本OPenCV的参数,可选,建议使用默认。

(二)检测人脸

下边使用级联分类器检测人脸,并在人脸位置画出红框以标记之。

使用不同的分类器效果会有所不同。


使用cv2.CascadeClassifier()方法加载级联分类器,创建出级联分类器对象。参数为级联分类器的文件名,可以将其复制到在方便我们使用的位置,比如当前目录。

使用faceCascade.detectMultiScale()方法对图像进行识别,其中faceCascade是使用cv2.CascadeClassifier()方法创建的级联分类器对象。

如使用haarcascade_frontalface_default.xml 会误把cdm_2.jpg和cdm_5.jpg中的背景也识别为了人脸(如下图所示),而使用haarcascade_frontalface_alt.xml 识别不出yhw_3中的曹操脸,经过测试使用cascades\haarcascade_frontalface_alt2.xml可以不多不少识别出十五张图中的所有人脸。

image.png以检测cdm_4.jpg中的人脸为例,使用cascades\haarcascade_frontalface_alt2.xml级联分类器,

代码如下:

import cv2
# 以检测cdm_4.jpg中的人脸为例
img = cv2.imread("pictures\\cdm_4.jpg")
# 加载识别人脸的级联分类器
# faceCascade = cv2.CascadeClassifier("cascades\\haarcascade_frontalface_default.xml")
# faceCascade = cv2.CascadeClassifier("cascades\\haarcascade_frontalface_alt.xml")
faceCascade = cv2.CascadeClassifier("cascades\\haarcascade_frontalface_alt2.xml")
# 识别出所有人脸
faces = faceCascade.detectMultiScale(img, 1.3)
for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 5)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

图片中人物的人脸成功被识别出。

image.png

其他图片及级联分类器读者可自行尝试,笔者不再展示。

③华强、皇叔、高祖配墨镜

检测出人脸后,我们就可以根据人脸所在的位置,使用其他的含有透明像素的图像来覆盖,就可以实现一系列好用的特效,比如给买瓜的华强和蹦迪的皇叔配上墨镜。


要实现这个特效首先需要准备的就是墨镜的素材图片了:

image.png

算法思路大致如下:


首先定义一个覆盖图像的函数,需要传入的参数有四个,依次是①原背景图像,②调整好大小的覆盖图像,③覆盖图像的左上角在原背景图像中位置的x坐标值X,④要覆图像的左上角在原背景图像中位置的左上角的y轴坐标值Y。

函数执行过程中覆盖图像的像素数组如果不是四通道,这应该改为BGRA四通道格式,然后依次对该BGRA图像上的每个像素点进行判断,如果A通道的值为0,即该位置像素为透明的,则该位置不需要执行覆盖。否则用该位置像素的B、G、R三个通道值替换图像时对应位置的三个通道值。该对应位置表述为在(X, Y)的基础上,加上该像素点在覆盖图像上的坐标点。


此外如果该像素点在原图像上的位置超出了背景图像的边界,则也不予覆盖。


然后就是在调用该函数之前,需要对覆盖图像的大小进行调整。首先选择合适的级联分类器,这里小啾选择的是haarcascade_frontalface_alt2.xml级联分类器,然后对图像中的人脸进行识别以获取到人脸在图像中高度左上角坐标,以及人脸区域的宽、高。


得到这些数据后,就可以对覆盖图像的大小进行调整了调整过程根据背景图像中人脸的大小灵活调整。比如这里将覆盖图像的长调整为人脸在图像中宽度的0.8倍(要记得取整),然后再将覆盖图像的高度按照其宽度缩小的相同的比例进行缩小。


随即,就是要确定覆盖图像覆盖在原背景图中左上角的位置,小啾这里选择的x坐标为,识别出的人脸区域的左上角x坐标加上0.1倍的区域宽度并取整;y轴坐标选择的是识别区域左上角的y坐标加上 三分之一倍的人脸区域的高度并取整。


大家在具体操作过程中可以根据需求自行调试,做出更佳的选择。比如如果背景图像中的人物带了眼镜,我们再给其加墨镜特1效,可能就会因为眼镜框的不完全覆盖导致画面整体的视觉效果较差,这个时候可以考虑增大覆盖图像的高度,或者并做少许下移。


确定好这些数据后,调用上边定义好的函数即可。

import cv2
# 定义覆盖图像函数
def overlay_img(img, img_over, img_over_x, img_over_y):
    img_h, img_w, img_p = img.shape  # 背景图像宽、高、通道数
    img_over_h, img_over_w, img_over_c = img_over.shape  # 覆盖图像高、宽、通道数
    # 如果图像通道数为3,则转换成4通道图像,增加一个表示透明度的。
    if img_over_c == 3:
        img_over = cv2.cvtColor(img_over, cv2.COLOR_BGR2BGRA)
    for h in range(0, img_over_h):
        for w in range(0, img_over_w):
            # 判断该像素点如果不透明,则执行覆盖。否则不用覆盖。
            if img_over[h, w, 3] != 0:
                # 如果该位置超出背景图边界则也不用执行覆盖
                X = img_over_x + w
                Y = img_over_y + h
                if X > img_w or Y > img_h:
                    break
                img[Y, X, 0] = img_over[h, w, 0]
                img[Y, X, 1] = img_over[h, w, 1]
                img[Y, X, 2] = img_over[h, w, 2]
    return img
face_img = cv2.imread("pictures\\shl_4.jpg")  # 读取人脸图像
glass_img = cv2.imread("glass.png", cv2.IMREAD_UNCHANGED)  # 读取眼镜图像,保留图像类型
height, width, channel = glass_img.shape  # 获取眼镜图像高、宽、通道数
# 加载级联分类器 haarcascade_frontalface_alt2.xml
face_cascade = cv2.CascadeClassifier("cascades\\haarcascade_frontalface_alt2.xml")
# garyframe = cv2.cvtColor(face_img, cv2.COLOR_BGR2GRAY)  # 转为黑白图像
faces = face_cascade.detectMultiScale(face_img, 1.3)  # 识别人脸
# 根据人脸大小缩放眼镜 并覆盖
for (x, y, w, h) in faces:  
    gw = int(w * 0.8)   
    gh = int(height * gw / width)  
    glass_img = cv2.resize(glass_img, (gw, gh))  
    overlay_img(face_img, glass_img, int(x + 0.1 * w), y + int(h * 1 / 3))
cv2.imshow("screen", face_img)
cv2.waitKey()
cv2.destroyAllWindows()

对“shl_4.jpg”图像文件,代码执行效果如下:

image.png

对“yhw_2.jpg”,代码的执行效果如下:

image.png

对“cdm_4.jpg”,代码的执行效果如下:

image.png

(因为这里选择的陈道明系列的剧照,头基本上都是歪的,针对这个问题,可以对覆盖图像使用一下仿射变换中的选择操作,旋转一定角度后再执行上述代码效果则会更佳,可自行尝试,这里不再展示)(旋转的同时要保证不需要的区域透明度为零)

人脸识别

OpenCV提供了三种人脸识别的方法,分别是Eigenfaces、Fisherfaces和LBPH三种人脸识别器。三种算法的算法有所不同,各具特色。



Eigenfaces人脸识别器也叫“特征脸”,是根据 主成分分析(PCA)方法实现的。

Fisherfaces人脸识别器是根据提出者的姓名命名的,其是根据 线性判别分析技术(LDA)方法实现的。

LBPH人脸识别器即Local Binary Patter Histogram人脸识别器,是一种基于局部二进制模式算法,这种算法善于捕捉纹理特征。


OpenCV提供的创建人脸识别器的方法为:



recognizer = cv2.face.EigenFaceRecognizer_create(num_components, threshold)


recognizer = cv2.face.FisherFacesRecognizer_create(num_components, threshold)


recognizer = cv2.face.LBPHFaceRecognizer_create(radius, neighbors, grid_x, grid_y, threshold)



这里分别使用每个人物的前四张图像作为样本,第五张图像作为测试图像进行人脸识别。

经过测试,本样本使用Eigenfaces和Fisherfaces的识别结果都不佳(也可能是因为剧中的化妆效果所致)。使用LBPH人脸识别器则可以准确地识别出三个人。


另一个需要注意并保证的细节是,进行人脸识别是,无论是训练集,还是测试集的图像,都应保证shape一致,必需相同大小。


/

import cv2
import numpy as np
# 先读取索引训练集的图像
img1 = cv2.imread("pictures\\cdm_1.jpg", 0)
img2 = cv2.imread("pictures\\cdm_2.jpg", 0)
img3 = cv2.imread("pictures\\cdm_3.jpg", 0)
img4 = cv2.imread("pictures\\cdm_4.jpg", 0)
img6 = cv2.imread("pictures\\shl_1.jpg", 0)
img7 = cv2.imread("pictures\\shl_2.jpg", 0)
img8 = cv2.imread("pictures\\shl_3.jpg", 0)
img9 = cv2.imread("pictures\\shl_4.jpg", 0)
img11 = cv2.imread("pictures\\yhw_1.jpg", 0)
img12 = cv2.imread("pictures\\yhw_2.jpg", 0)
img13 = cv2.imread("pictures\\yhw_3.jpg", 0)
img14 = cv2.imread("pictures\\yhw_4.jpg", 0)
# 以cdm_4.jpg的大小为基准,将其他图像也都调整为该大小。
y, x = img4.shape
img1 = cv2.resize(img1, (x, y))
img2 = cv2.resize(img2, (x, y))
img3 = cv2.resize(img3, (x, y))
img6 = cv2.resize(img6, (x, y))
img7 = cv2.resize(img7, (x, y))
img8 = cv2.resize(img8, (x, y))
img9 = cv2.resize(img9, (x, y))
img11 = cv2.resize(img11, (x, y))
img12 = cv2.resize(img12, (x, y))
img13 = cv2.resize(img13, (x, y))
img14 = cv2.resize(img14, (x, y))
# 将样本图像和标签都分别添加进列表中
# cdm的图像标签为0,shl的图像标签为1,yhw的图像标签为2
photos = list()
lables = list()
photos.append(img1)
lables.append(0)
photos.append(img2)
lables.append(0)
photos.append(img3)
lables.append(0)
photos.append(img4)
lables.append(0)
photos.append(img6)
lables.append(1)
photos.append(img7)
lables.append(1)
photos.append(img8)
lables.append(1)
photos.append(img9)
lables.append(1)
photos.append(img11)
lables.append(2)
photos.append(img12)
lables.append(2)
photos.append(img13)
lables.append(2)
photos.append(img14)
lables.append(2)
# 用字典匹配每个人的名字和上边设定的标签
names = {"0": "cdm", "1": "shl", "2": "yhw"}
# 创建特征脸识别器
# recognizer = cv2.face.EigenFaceRecognizer_create()
# 创建线性判别分析识别器
# recognizer = cv2.face.FisherFaceRecognizer_create()  
# 创建 LBPH人脸识别器
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 识别器开始训练
recognizer.train(photos, np.array(lables))

模型训练完成,下边开始使用测试集的图像进行识别。


读取测试集图像,并也调整为上述大小:

img5 = cv2.imread("pictures\\cdm_5.jpg", 0)
img10 = cv2.imread("pictures\\shl_5.jpg", 0)
img15 = cv2.imread("pictures\\yhw_5.jpg", 0)
img5 = cv2.resize(img5, (x, y))
img10 = cv2.resize(img10, (x, y))
img15 = cv2.resize(img15, (x, y))

识别img5:cdm_5.jpg

img = img5
label, confidence = recognizer.predict(img)
print("confidence = " + str(confidence))
print("识别结果:", names[str(label)])
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

image.png

image.png

识别img10:shl_5.jpg

img = img10
label, confidence = recognizer.predict(img)
print("confidence = " + str(confidence))
print("识别结果:", names[str(label)])
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

image.png

image.png

识别img15:yhw_5.jpg

img = img15
label, confidence = recognizer.predict(img)
cv2.imshow("img", img)
print("confidence = " + str(confidence))
print("识别结果:", names[str(label)])

image.png

image.png

目录
相关文章
|
编解码 计算机视觉 索引
小啾带你开天眼 之 开启py-OpenCV摄像头及视频处理【Python-Open_CV系列(十二)】
小啾带你开天眼 之 开启py-OpenCV摄像头及视频处理【Python-Open_CV系列(十二)】
658 0
小啾带你开天眼 之 开启py-OpenCV摄像头及视频处理【Python-Open_CV系列(十二)】
|
4天前
|
Python
Python编程中的异常处理:理解与实践
【9月更文挑战第14天】在编码的世界里,错误是不可避免的。它们就像路上的绊脚石,让我们的程序跌跌撞撞。但是,如果我们能够预见并优雅地处理这些错误,我们的程序就能像芭蕾舞者一样,即使在跌倒的边缘,也能轻盈地起舞。本文将带你深入了解Python中的异常处理机制,让你的代码在面对意外时,依然能保持优雅和从容。
139 73
|
4天前
|
人工智能 数据挖掘 数据处理
揭秘Python编程之美:从基础到进阶的代码实践之旅
【9月更文挑战第14天】本文将带领读者深入探索Python编程语言的魅力所在。通过简明扼要的示例,我们将揭示Python如何简化复杂问题,提升编程效率。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开一扇通往高效编码世界的大门。让我们开始这段充满智慧和乐趣的Python编程之旅吧!
|
3天前
|
数据采集 机器学习/深度学习 人工智能
Python编程入门:从零基础到实战应用
【9月更文挑战第15天】本文将引导读者从零开始学习Python编程,通过简单易懂的语言和实例,帮助初学者掌握Python的基本语法和常用库,最终实现一个简单的实战项目。文章结构清晰,分为基础知识、进阶技巧和实战应用三个部分,逐步深入,让读者在学习过程中不断积累经验,提高编程能力。
|
4天前
|
机器学习/深度学习 数据采集 人工智能
探索Python的奥秘:从基础到进阶的编程之旅
在这篇文章中,我们将深入探讨Python编程的基础知识和进阶技巧。通过清晰的解释和实用的示例,无论您是编程新手还是有经验的开发者,都能从中获得有价值的见解。我们将覆盖从变量、数据类型到类和对象的各个方面,助您在编程世界里游刃有余。
21 10
|
2天前
|
存储 机器学习/深度学习 数据挖掘
深入浅出:Python编程入门与实践
【9月更文挑战第16天】本文以“深入浅出”的方式,引领读者步入Python编程的世界。从基础语法到实际应用,我们将一步步探索Python的魅力所在。无论你是编程新手,还是希望拓展技能的老手,这篇文章都将为你提供有价值的信息和指导。通过本文的学习,你将能够编写出简单而实用的Python程序,为进一步深入学习打下坚实的基础。让我们一起开始这段编程之旅吧!
|
2天前
|
存储 Python 容器
Python编程基础第二天学习笔记
Python编程的第二天学习是建立在基础概念上的深化和扩展,强调了基本语法、数据类型、控制结构和函数的重要性。通过实践这些概念,可以增强对Python编程语言的理解,并为后续的高级学习打下坚实的基础。继续实践并逐渐探索更复杂的编程任务将有助于巩固和扩展这些基础知识。
21 7
|
8天前
|
存储 人工智能 数据挖掘
Python编程入门:从基础到实战
【9月更文挑战第10天】本文将引导你进入Python编程的世界,从基本语法到实际项目应用,逐步深入。我们将通过简单的例子和代码片段,帮助你理解并掌握Python编程的精髓。无论你是编程新手还是有一定经验的开发者,都能在这篇文章中找到有价值的信息。让我们一起开始Python编程之旅吧!
|
2天前
|
机器学习/深度学习 存储 人工智能
探索Python编程的魔法:从基础到进阶
【9月更文挑战第16天】本文将带领你进入Python编程的世界,无论你是初学者还是有一定经验的开发者。我们将一起揭开Python编程的神秘面纱,通过实际案例和代码示例,深入浅出地探讨Python的基础语法、数据结构、面向对象编程以及函数式编程等核心概念。文章旨在提供一条清晰的学习路径,帮助你构建坚实的编程基础,并逐步过渡到更高级的编程技巧。无论你的目标是数据分析、网络开发还是机器学习,这篇文章都将为你打下扎实的基础,让你在编程的道路上越走越远。
15 6
|
2天前
|
机器学习/深度学习 数据挖掘 程序员
Python编程基础:从入门到实践
【9月更文挑战第16天】本文是一篇Python编程的入门教程,旨在帮助初学者理解Python的基本概念和语法。文章首先介绍了Python的历史和特点,然后详细讲解了Python的基本语法,包括变量、数据类型、运算符、控制结构等。接着,文章通过一些实例代码,展示了如何使用Python进行基本的编程操作,如输入输出、条件判断、循环等。最后,文章还提供了一些学习资源和建议,帮助读者进一步学习和掌握Python编程。