圣诞节快到了。虽然我们不在这个异域的节日里,但我们还是要凑热闹的。相信已经有不少圣诞帽相关周边在流传。今天我们自己来做,给头像加一个圣诞帽的基础知识准备在电脑里,图片以矩阵的形式保存,先行后列。所以一张width×height×colorchannel=480×256×3的图片会存储在一个256×480×3的三维张量中。图像处理也是按照这个思路计算的(包括OpenCV下的图像处理),即高×宽×颜色通道。数字图像对于数字图像,我们看到的是肉眼可见的真实画面,但对于计算机来说,这张图像只是一堆亮度不同的点。一个大小为M×N的图像可以用一个M×N的矩阵来表示。矩阵元素的值表示该位置像素的亮度。一般来说,像素值越大,点越亮。一般来说,灰度图像用2维矩阵表示,彩色(多通道)图像用3维矩阵(M×N×3)表示。一个图像通道描述一个像素。如果是灰度,那么只需要一个值来描述它,就是单通道。如果一个像素点有RGB的三种颜色来描述它,那就是三个通道。四通道图像是R、G、B加一个A通道,表示透明度。一般称为alpha通道,意思是透明度。ROI和maskSettingRegionofInterest(ROI),翻译成大白话,设置感兴趣区域。Mask就是做图像mask处理,相当于把我们不关心的部分给遮住了,留下ROI部分。上面提到的alpha可以用作遮罩。Matrix(Numpy)知识矩阵索引、切片等,我这里掌握不好,就不多说了,小伙伴们可以自行学习。环境准备有了基础知识之后,我们简单看一下代码。首先安装需要用到的OpenCV和dlib库,使用pip安装pipinstallpython-opencvpipinstalldlib然后在网上手动下载数据模型文件shape_predictor_5_face_landmarks.dat,地址如下:http://dlib.net/files/,下载下来放到项目目录下。有兴趣的同学可以玩玩shape_predictor_68_face_landmarks.dat,识别人脸的关键点多达68个。代码处理帽子处理我们要做的第一件事就是处理帽子。我们使用的图像如下首先提取帽子图像的rgb和alpha值#Hatimagehat_img3=cv2.imread("hat.png",-1)r,g,b,a=cv2.拆分(hat_img3)rgb_hat=cv2.merge((r,g,b))cv2.imwrite(“rgb_hat.jpg”,rgb_hat)cv2.imwrite(“alpha.jpg”,a)打印(a)打印(hat_img3。shape)print(rgb_hat.shape)我们得到的效果如下:对于rgb图像alpha图像打印出来的a值如下:[[000...000][000...000][000...000]...[000...000][000...000][000...000]]人脸检测下面进行人脸检测,由dlib处理。#人脸检测dets=self.detector(img,1)x,y,w,h=dets[0].left(),dets[0].top(),dets[0].right()-dets[0].left(),dets[0].bottom()-dets[0].top()#关键点检测shape=self.predictor(img,dets[0])point1=shape.parts()[0]point2=shape.parts(2)#求两点的中心eyes_center=((point1.x+point2.x)//2,(point1.y+point2.y)//2)下一步是scaledownHatpicture#帽子和脸的转换比例hat_w=int(round(dets[0].right()/1.5))hat_h=int(round(dets[0].bottom()/2))ifhat_h>y:hat_h=y-1hat_newsize=cv2.resize(rgb_hat,(hat_w,hat_h))mask=cv2.resize(a,(hat_w,hat_h))mask_inv=cv2.bitwise_not(mask)dh=0dw=0bg_roi=img[y+dh-hat_h:y+dh,(eyes_center[0]-hat_w//3):(eyes_center[0]+hat_w//3*2)]ROIextractionforROIextraction#使用alpha通道作为maskmask=cv2.resize(a,(resized_hat_w,resized_hat_h))mask_inv=cv2.bitwise_not(mask)掩码变量,帽子区域被取出。mask_inv变量用于提取人脸图像中安装帽子的区域。接下来,取出人脸图像中安装帽子的区域(ROI)#OriginalImageROI#bg_roi=img[y+dh-resized_hat_h:y+dh,x+dw:x+dw+resized_hat_w]bg_roi=img[y+dh-resized_hat_h:y+dh,(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)]然后取出人脸图片中的帽子形状区域#原创imageROI提取放置帽子的区域bg_roi=bg_roi.astype(float)mask_inv=cv2.merge((mask_inv,mask_inv,mask_inv))alpha=mask_inv.astype(float)/255#保证两者相同相乘前的大小(可能由于四舍五入而不一致)alpha=cv2.resize(alpha,(bg_roi.shape[1],bg_roi.shape[0]))#print("alphasize:",alpha.shape)#print("bg_roisize:",bg_roi.shape)bg=cv2.multiply(alpha,bg_roi)bg=bg.astype('uint8')这里是将图片默认的uint8类型转换为float类型进行运算,而最后将其转换回来。合成图片的黑色部分就是我们要放置帽子的地方。从帽子图像中提取帽子部分。#提取帽子区域hat=cv2.bitwise_and(resized_hat,resized_hat,mask=mask)使用新调整大小的帽子图像进行提取。可以看到除了帽子部分,其他区域都被遮住了。以上就是提取ROI的过程,比较难理解,需要慎重考虑,尤其是矩阵的切片和mask处理部分。合成图片的最后一步是将人脸图片和帽子合成在一起,即将人脸空帽子部分的图片区域和只显示帽子区域的帽子图片区域合成(有点啰嗦)。#添加前确保两者大小相同(可能因四舍五入不一致)hat=cv2.resize(hat,(bg_roi.shape[1],bg_roi.shape[0]))#添加两个ROI区域add_hat=cv2.add(bg,hat)的效果如下:恰到好处,完美叠加图片。最后把这个clip放回原来的人脸图片,显示imageimg[y+dh-hat_h:y+dh,(eyes_center[0]-hat_w//3):(eyes_center[0]+hat_w//3*2)]=add_hat美图出来啦!让我们尝试更多不同的图像。整体效果还不错。需要注意的是,在测试的时候,我们尽量选择人脸比例比较大的图片来合成,效果会好很多~
