重磅干货,第一时间送达
来源:CVPy
人脸检测历险记
可能跟我一样,人脸检测是很多人学习图像处理的第一个自驱动型的任务,OpenCV刚上手没几天可能就想先跑一跑人脸检测,然后一个坑接着一个坑的往里跳。我个人对人脸检测的大概历程应该是下面这样的:
- 找一个直接能执行的
OpenCV
的人脸检测程序,直接执行看效果。虽然这貌似是最简单的一步,但是由于最初水平实在太低,所以这一步可能是耗时最长的。当时初学的时候还在用C
,想要直接跑程序,首先你要先配置好环境!曾经因为环境问题尝试了不同版本OpenCV
未果、重装VS
未果、重装Windows
系统仍未果...当年的环境配置简直是不堪回首,说多了都是泪。而且根据我的经验,不论是因为版本还是还是系统问题,在网上找一个直接拿来就能跑的代码实在是太难了... - 按照千辛万苦跑起来的程序,自己敲一遍。明明感觉没啥差别,为啥就是跑不起来呢...所有的坑都会自己跳进去,所有的低级错误都会犯不止一遍。
- 尝试找数据或者标注数据,尝试自己训练一个人脸检测模型,
OpenCV
提供了用来训练的exe
,参数超多,一直感觉很难用...当时可谓是屡败屡战,屡战屡败。 - 找一个能直接执行的深度学习的人脸检测程序,直接执行看效果。(虽然这貌似是最简单的一步,但是由于最初水平实在太低,所以这一步可能是耗时最长的。当时初学的时候还在用
Caffe
,想要直接跑程序,首先你要先配置好环境!Caffe
的环境配置...当年的环境配置简直是不堪回首,说多了都是泪。???好像在哪里听过?) - 同2.
- 尝试找数据或者标注数据,尝试自己训练一个人脸检测模型。
Caffe
...对,我当时用的是TensorFlow Object Detection API
(当时这个环境配置过程也很感人)。 - 找一个能直接能用的人脸检测模型,直接跑起来看看效果....如果不能跑,尝试改改,也许就该好了呢。
- 跑起来一个人脸检测模型,加点其他效果?
要不就先看看效果吧,毕竟看到效果才更有动力走下去。【视频有声提示!】
上面用的是深度学习模型的人脸检测,但是在此之前还是稍微回顾下OpenCV自带的人脸检测器。
OpenCV自带的人脸检测
OpenCV自带了基于级联分类器的人脸检测模型,只能检测正脸,在前深度学习时代,效果已经是很好的了。OpenCV中的使用方式是用级联分类器加载人脸检测模型,大家一般默认用haarcascade_frontalface_default.xml
。这个文件在C 源码路径下很容易找到,大概在opencv/sources/data/haarcascades
路径下,Python的话,我用的Anaconda,所以路径在/Anaconda3/Lib/site-packages/cv2/data/
。不同版本想来差异不会太大。
然后用多尺度滑窗法去检测人脸,函数参数含义和代码示例如下:
直接【执行】看效果:【视频有声提示!】
基于深度学习的人脸检测
想要深入学习的小伙伴可以尝试自己训练一个人脸检测模型练手,这里直接在Github上找一个能跑的模型CenterFace
。代码和模型都来自这里https://github.com/Star-Clouds/CenterFace
。由于模型是ONNX
格式的,所以用OpenCV
的readNetFromONNX
函数加载模型centerface.onnx
。
摘取主体代码并注释如下:
代码语言:javascript复制class CenterFace(object):
def __init__(self):
# readNetFromONNX 加载模型
self.net = cv2.dnn.readNetFromONNX(os.path.join(model_path, 'centerface.onnx'))
self.img_h_new, self.img_w_new, self.scale_h, self.scale_w = 0, 0, 0, 0
def __call__(self, img, height, width, threshold=0.5, landmarks=True):
# 圆整图片大小为32的倍数
self.img_h_new, self.img_w_new, self.scale_h, self.scale_w = self.transform(height, width)
# 推理,即前向传播一次
return self.inference_opencv(img, threshold, landmarks)
def inference_opencv(self, img, threshold, landmarks=True):
# 图像预处理,这里主要是 Reisze 和 BGR2RGB
blob = cv2.dnn.blobFromImage(img, scalefactor=1.0, size=(self.img_w_new, self.img_h_new), mean=(0, 0, 0), swapRB=True, crop=False)
self.net.setInput(blob)
begin = time.time()
# 前向传播一次
heatmap, scale, offset, lms = self.net.forward(["537", "538", "539", '540'])
end = time.time()
print("dtime = ", end - begin)
# 后处理,主要是根据阈值 threshold 从输出获取人脸框和人脸关键点的位置
return self.postprocess(heatmap, lms, offset, scale, threshold, landmarks)
def transform(self, h, w):
# 圆整图片大小为32的倍数
img_h_new, img_w_new = int(np.ceil(h / 32) * 32), int(np.ceil(w / 32) * 32)
scale_h, scale_w = img_h_new / h, img_w_new / w
return img_h_new, img_w_new, scale_h, scale_w
这一步模型可以同时给出人脸框和人脸关键点的位置。【视频有声提示!】
人脸卡通化
仅仅是人脸检测,显得略微有些没意思,所以在人脸检测的基础上,加点其他的更有意思的东西,比如上次刚玩过的卡通化。这是国内大佬的一篇文章,开源了代码和模型,在这里:https://github.com/SystemErrorWang/White-box-Cartoonization/
。代码细节可以到这个链接查看,这里只给出人脸检测之后和卡通化结合部分的代码:
def face_detect(self, image, landmarks: bool, cartoon: bool):
# 加载模型
centerface = CenterFace()
h, w = image.shape[:2]
# 人脸检测
dets, lms = centerface(image, h, w, threshold=0.5, landmarks=landmarks)
print("检测到的人脸:", dets)
if len(dets):
for det in dets:
boxes, score = det[:4], det[4]
x1, y1, x2, y2 = int(boxes[0]), int(boxes[1]), int(boxes[2]), int(boxes[3])
box_w, box_h = x2 - x1, y2 - y1
# 人脸框稍微往外扩一点,个人感觉这么会好一点
face_box = image[max(0, y1 - int(box_h * 0.1)): min(y2 int(box_h * 0.1), h), max(
0, x1 - int(box_w * 0.1)):min(x2 int(box_w * 0.1), w)]
if cartoon:
# 人脸卡通化之后
cartoonized_face = cartoonize(face_box)
# 贴回原图,覆盖原图人脸部分
image[max(0, y1 - int(box_h * 0.1)): min(y2 int(box_h * 0.1), h), max(
0, x1 - int(box_w * 0.1)):min(x2 int(box_w * 0.1), w)] = cartoonized_face
# 画出人脸框框
draw_box(image, [x1, y1, x2, y2], color=(0, 255, 255))
# cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 255), min(h, w) // 200)
if landmarks:
for lm in lms:
for i in range(0, 5):
cv2.circle(image, (int(lm[i * 2]), int(lm[i * 2 1])),
min(h, w) // 100, (0, 0, 255), -1)
else:
cv2.putText(image, "No Face?", (int(w * 0.1), int(h * 0.1)), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 255), min(h, w) // 200)
return image
流程如下:
- 先加载
CenterFace
的模型(参考上一节的CenterFace
的__init__
) - 进行人脸检测,获取人脸框和人脸关键点的位置
- 稍微扩充下人脸框,进行卡通化操作
- 把卡通化后的人脸贴回原图中人脸的位置
完整效果
看一下完整的效果吧:【视频有声提示!】
结语-玩一下
想要自己尝试实现的小伙伴,可以按照我给的链接找到源码位置自己跑跑试试。如果想要立刻就体验一下效果的话,想必你已经看出来了,这个人脸检测 & 卡通化已经被我做成了一个体验网页了。手机和电脑均可访问。
- 电脑:
http://cvpy.net/studio/cv/func/DeepLearning/face/face_detection/page/
- 手机:扫码进入体验,觉得不错的话,可以给个在看哦。