打开国庆的正确方式,教你用OpenCV-Python轻松生成微信国庆版头像
- 2019 年 10 月 10 日
- 筆記
文章详情:OpenCV
相信最近两天大家都被微信头像的国庆版新装刷爆了朋友圈了,不少人都@微信官方,要求换装为国庆版头像,朋友圈也是各种生成链接满天飞。其实这个事情在小编看来没有那么复杂,这么简单的事情怎么好意思随便@,直接自己100行代码搞定。
好了,废话少说,下面就给大家看看程序运行的效果,是不是辨识度很高,想知道怎么做的吗,继续往下看!

思路分析
01
完整的程序实现分为三个部分完成,第一部分首先需要准备一个模板图像,我准备的模板图像,是从腾讯官方截取的,算是借用吧,显示如下:

然后根据这个 模板图像,生成遮罩图层mask图像,这里主要是通过inRange来实现mask生成,通过imagewatch我观察到模板图中的空白区域的像素值为(216、216、216)所以上下浮点5,最终得到遮罩层mask图像如下:

注意:因为得到mask图像还有一些小的瑕疵,这个时候通过简单的形态学闭操作处理就会的比较好的轮廓外形。
有了mask之后,就可以对输入的模板图像与头像图像,进行融合,生成一张国庆版头像了,这个时候直接的像素相加效果会比较生硬。所以先通过高斯模糊生成边缘的融合权重,这样边缘看上去比较自然。

最后对选择的任意图像,都可以先通过人脸检测,自动定位到人脸区域,然后截取ROI,自动生成,如果无法自动检测到人脸,则会利用输入图像自动生成。人脸检测我这里采用OpenCV DNN的人脸检测方法,效果非常好!命中率很高!
代码实现
02
完整的代码分为三个部分
方法get_face负责输入图像的人脸检测与自动ROI提取与返回。代码如下:
def get_face(image, detect=True): if detect is not True: return image # 定义人脸ROI x = 0 y = 0 width = 0 height = 0 # 加载网络 net = cv.dnn.readNetFromTensorflow(model_bin, config=config_text) h = image.shape[0] w = image.shape[1] # 人脸检测 blobImage = cv.dnn.blobFromImage(image, 1.0, (300, 300), (104.0, 177.0, 123.0), False, False); net.setInput(blobImage) cvOut = net.forward() # Put efficiency information. t, _ = net.getPerfProfile() label = 'Inference time: %.2f ms' % (t * 1000.0 / cv.getTickFrequency()) cv.putText(image, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0)) # 绘制检测矩形 count = 0 for detection in cvOut[0, 0, :, :]: score = float(detection[2]) if score > 0.5: left = detection[3] * w top = detection[4] * h right = detection[5] * w bottom = detection[6] * h count += 1 x = np.int32(left - 100) y = np.int32(top - 100) height = np.int32((bottom - top) + 200) width = np.int32((right - left) + 200) if x < 0: x = 0 if y < 0: y = 0 if x+width > w: width = w - x if y+height > h: height = h - y if count == 1: return image[y:y + height, x:x + width, :] else: return image
方法generate_new_profile负责自动生成国庆版头像,代码如下:
def generate_new_profile(flag_icon, avatar): mask = cv.inRange(icon, (210, 210, 210), (225, 225, 225)) se = cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) mask = cv.morphologyEx(mask, cv.MORPH_CLOSE, se) # mask with gaussian mask = cv.GaussianBlur(mask, (5, 5), 0) cv.imshow("mask", mask) # blend h, w = mask.shape[:2] avatar = cv.resize(avatar, (w, h), interpolation=cv.INTER_CUBIC) cv.imshow("profile", avatar) result = np.zeros_like(avatar) for row in range(h): for col in range(w): pv = mask[row, col] w1 = pv / 255.0 w2 = 1.0 - w1 b1, g1, r1 = avatar[row, col] b2, g2, r2 = icon[row, col] b1 = b1 * w1 + b2 * w2 g1 = g1 * w1 + g2 * w2 r1 = r1 * w1 + r2 * w2 result[row, col] = [np.int32(b1), np.int32(g1), np.int32(r1)] return result
读取本地图像,调用上述两个方法的代码如下:
if __name__ == "__main__": icon = cv.imread("D:/images/flag.png") src = cv.imread("D:/images/zhigang.png") cv.imshow("input", icon) cv.imshow("profile", src) avatar = get_face(src, False) result = generate_new_profile(icon, avatar) cv.imshow("result", result) cv.imwrite("D:/result.png", result) cv.waitKey(0) cv.destroyAllWindows()
运行测试

传送门->代码下载地址:
https://github.com/gloomyfish1998/opencv_tutorial/tree/master/python

