人脸检测分为两种:一种是基于知识的,一种是基于深度学习的。深度不会学习
人脸识别属于目标检测,主要涉及两个方面:
①先对检测的物体进行概率统计,从而知道待检测对象的一些特征,建立其目标的检测模型
②用得到的模型来匹配输入的图像,如果有匹配则则输出匹配的区域,否则什么也不做。
我们看到的图片和计算机不一样,计算机看到的是一串串数字矩阵,图片由多个像素组成,拿我们熟悉的RGB图像来说,每个像素又有红绿蓝三个通道,假如每个像素的单个通道由uint8类型字符组成,那么三通道的像素便会有24位,这是我们常说的24位真彩。如果我们把RGB图像转化为gray图像来处理,那一定会减少很多计算量。
所以第一步应该给图像做预处理,比如先把图像转化为灰度图像。
1 gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
把RGB转gray的方法有很多,有直接求RGB平均值的还有分别赋权重的,opencv用什么方法我暂时没查到。
这样的转化可能会造成图片的灰度值分布不均匀,通常认为,对所有可用像素强度值都均衡使用,才是一副高质量的图像。所以我们需要让图像的灰度直方图尽可能的平稳,opencv提供了一个简单好用的函数
1 cv.equalizeHist(gray, gray)
直方图均衡化是通过拉伸像素强度分布范围来增强图像对比度的一种方法,在一个完全均衡化的直方图中,所有的bins所包含的像素数量是相等的,这也就是说,像素大于128的有一半,像素值小于128的也是一半,像素值小于64的是小于128的一半,以此类推。
当然图像预处理也可以用增强对比度的方法。
下面介绍提高对比度和增加亮度的函数
1 new_img = cv.addWeighted(img, c, new_img, 1-c, b) #c是对比度倍数 b是亮度增加数
图像对比度指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,即指一幅图像灰度反差的大小。差异范围越大代表对比越大,差异范围越小代表对比越小。
图象亮度是指画面的明亮程度,通常用像素值来表示。
利用OpenCV自带的xml文件,可以实时检测摄像头中人脸Haar特征、LBP特征都是常用的特征,描述不同的局部信息Haar描述的是图像在局部范围内像素值明暗变换信息LBP描述的是图像在局部范围内对应的纹理信息,HAAR与LBP区别:
① HAAR特征是浮点数计算,LBP特征是整数计算;
② LBP训练需要的样本数量比HAAR大;
③ LBP的速度一般比HAAR快;
④ 同样的样本HAAR训练出来的检测结果要比LBP准确;
⑤ 扩大LBP的样本数据可达到HAAR的训练效果
haar特征分类器是一个xml文件,文件描述了检测物体的Haar特征值,Haar分类器需要通过大量的数据来训练。Haar特征包括三类特征:边缘特征、、线性特征、中心特征和对角线特征,组合成特征模板。特征模板内有白色和黑色两种矩形,并定义该模板的特征值为白色矩形像素和减去黑色矩形像素和。Haar特征值反映了图像的灰度变化情况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。
下面是特征模板
然后人脸特征矩形对应图片,符合人脸特征的区域会被认定位人脸。
接下来开始人脸检测,加载haar分类器
1 faceadd = "***/Lib/site-packages/cv2/data/haarcascade_frontalface_default.xml" 2 eyeadd = "***/Lib/site-packages/cv2/data/haarcascade_eye.xml" 3 smileadd = "***/Lib/site-packages/cv2/data/haarcascade_smile.xml" 4 5 face_detector = cv.CascadeClassifier(faceadd) 6 eye_detector = cv.CascadeClassifier(eyeadd) 7 smile_detector = cv.CascadeClassifier(smileadd)
检测faces,eyes,smile
1 faces = face_detector.detectMultiScale(gray, 1.15, 5) 2 for x, y, w, h in faces: 3 cv.rectangle(image, (x, y), (x+w, y+h), (0, 0, 255), 2) 4 #把脸单独拿出来检测脸 5 face_img = gray[y:y+h, x:w+x] 6 cv.imshow("face_img", face_img) 7 eyes = eye_detector.detectMultiScale(face_img, 1.3, 5, 0, (40, 40)) 8 for ex, ey, ew, eh in eyes: 9 cv.rectangle(image, (x+ex, y+ey), (x+ex+ew, y+ey+eh), (255, 0, 0), 2) 10 smile = smile_detector.detectMultiScale(face_img, 1.16, 35, 0, (25,25)) 11 if(len(smile) >= 0): 12 print("检测到微笑") 13 cv.putText(image, 'Smile', (x, y-20), 3, 1.3, (0, 255, 0), 2)
循环读取人脸的矩形对象列表,获得人脸矩形的坐标和宽高, 然后在原图片中画出该矩形框,调用的是OpenCV的rectangle 方法,其中矩形框的颜色等是可调整的,putText函数是加文字的(图片,文字,位置,字体,大小,颜色,粗细)。
然后尝试着用最原始的方法,对图像依次更改各个像素值,发现降低蓝绿色的占比时,图像的变化类似于“怀旧”,提高蓝绿色占比或者降低红色占比,图像风格类似于“清新”。暴力循环改像素值,就不展示代码了。
关于马赛克。
马赛克效果原理就是用一个像素点去代替需要被替代的像素点 下面以给人脸打码说明:
1 找到需要被马赛克的区域: 2 face_img = image[y:y+h, x:w+x] 3 马赛克: 4 for i in range(x, w+x, 10): 5 for j in range(y, y+h, 10): 6 a = random.randint(50,120) 7 image[i:10+i, j:j+10] = a 8 把图片拼接回原图: 9 image[y: y + h, x: w + x] = face_img
还有一种暴力抠图法,对除了脸部分的区域进行虚化,效果类似于手机的人像模式。
就是把图片分割为人脸区域和非人脸区域
Part1 |
part2 |
part4 |
Face | ||
part3 |
1 face_img = gray[y:y+h, x:w+x] 2 part1 = image[0:image.shape[0], 0:x] 3 part2 = image[0:y, x:x+w] 4 part3 = image[y+h:image.shape[0], x:w+x] 5 part4 = image[0:image.shape[0], x+w:image.shape[1]]
基于上图给出我的暴力抠图方法。然后对part1~4进行虚化,这里使用高斯滤波,同时把图片拼接到原图
1 image[0:image.shape[0], 0:x] = cv.GaussianBlur(part1, (5, 5), 0) 2 image[0:y, x:x+w] = cv.GaussianBlur(part2, (5, 5), 0) 3 image[y+h:image.shape[0], x:w+x] = cv.GaussianBlur(part3, (5, 5), 0) 4 image[0:image.shape[0], x+w:image.shape[1]] = cv.GaussianBlur(part4, (5, 5), 0)
现在的照相技术太发达了,没找到什么很好说明例子的图片,看头发虚化了一点吧。
关于暴力抠图虚化的bug,好像只能关注一张脸,如果同时存在多张脸会把其他脸也虚化了,背景被强行叠加虚化。
关于图像滤波发现一篇不错的文章:https://xiongyiming.blog.csdn.net/article/details/89788020