这几天,你们的朋友圈一定被“请给我一顶圣诞帽@微信官方”刷屏了……很多不明真相的网友也纷纷询问如何给自己的圣诞帽加一顶圣诞帽个人资料图片。圣诞帽火了,亿万人为之疯狂@微信官方圣诞节来了,朋友圈悄悄掀起了加帽子的风潮。大家@微信官方申请给自己的头像加一顶圣诞帽。24小时内圣诞帽热搜指数暴涨:接着,一场花哨的圣诞帽仪式开始刷屏,各种稀奇古怪的东西夹杂其中,没想到我发现@微信官方竟然不能戴圣诞帽,于是我意识到自己被“骗了”。一大波知道真相的网友开始把@微信官方变成许愿池:求钱送礼的,求房子的,求明星的,求博士帽的,求减肥的,给绿帽子的。默默给P戴上圣诞帽……这波戏精我给满分!如何从技术上实现@微信官方头像添加圣诞帽?那么,作为一个程序员,从技术的角度想一想,这个东西能不能做呢?先看网上一只猿的分析:这体现了腾讯强大的人工智能能力。首先,微信收到用户的朋友圈后,获取用户的头像并上传到服务器云端。然后,借助云计算和人脸识别,猪脸识别(朋友京东的技术)和物体识别,根据头像的角度和人物的大小不断调整圣诞帽的大小和位置脸,最后生成圣诞帽的头像。网友@IT大智表示:这个功能目前几乎不可能实现。首先必须明确一点,所有的APP或者网站都是由代码程序实现的。假设微信要给用户添加一顶圣诞帽,必须重新引用圣诞帽的图片地址。如果直接添加,则必须覆盖用户原来的头像。退一步说,腾讯是可以做图片叠加的,所以图片的大小和位置也要定义。所以,微信最多只能在固定位置加一顶一定尺寸的帽子。试想一下,微信用户的头像千差万别,头像的位置也很不确定。如何将圣诞帽添加到个人资料图片的顶部?所以这是一个谣言,类似于“明天是马化腾生日,转发此消息至三个群可获得200Q币”之类的。很多朋友发朋友圈要求加圣诞帽和@微信官方,但其实微信只能@你的朋友,微信还没有推出自己的公众号,所以你可以在朋友圈@微信官方,微信的可以人们收到你的@信息了吗?当然不是。但还有更厉害的:一般来说,当用户在朋友圈发这样一条短信时:请在我的头像上给我戴上圣诞帽@微信官方。微信官方会收到这个爱特,通过用户的openid(微信用户的唯一ID)获取用户的微信头像文件,并将图片和文字传给后台AI。所谓“自然语言”,就是我们人类平时所说的。一般情况下,计算机只能听懂编程语言,听不懂人说的话。而腾讯AI则可以进行“自然语言处理”,对“请给我头上戴一顶圣诞帽”这句话进行分解,并解读其中的意思。至此,腾讯AI已经理解了这段文字的内容,并通过智能图像处理技术,识别人脸和头部,选择合适的大小和方向,将事先准备好的圣诞帽图片与头像叠加,从而生成带有圣诞老人帽子的新头像,并将头像传递到前端。微信收到图片后,通过读取openid正式找到用户,将图片应用到用户头像上,并提醒用户。整个过程不到五分钟。当然,有些情况对AI来说会很困难。例如,如果你的头像图片中有很多人,AI将无法判断你要为哪个人添加圣诞帽。你只能给每个人加一顶圣诞帽。所以,大家不要调戏AI,用美图@微信官方!当然,这只是@微信官方求桑的调侃,但真的有人站出来表示,这件事情可以做。阅文集团高级架构师许海峰先生:他说可以通过大数据分析+AI+动态图像处理来实现。架构图如下:虽然微信暂时没有这个功能,但是不代表程序员不能实现!在人工智能火热的今天,让我们看看程序员是如何用Python为自己戴上圣诞帽的?使用Python为头像添加圣诞帽。大家@官方微信在头像上加了一顶圣诞帽。当然,这种事情用很多P图软件是可以做到的。但是作为一个研究图像处理的技术人员,我们还是觉得有必要写一个程序来做这件事。使用的工具是OpenCVdlib(dlib的人脸检测比OpenCV好,dlib有OpenCV没有的关键点检测。)使用的语言是Python,不过可以换成C++版本。操作流程素材准备首先我们需要准备一个圣诞帽素材,格式最好是PNG,因为PNG我们可以直接使用Alpha通道作为遮罩,使用的圣诞帽如下:通过通道分离我们可以得到圣诞节的alpha帽子图像的通道,代码如下:r,g,b,a=cv2.split(hat_img)rgb_hat=cv2.merge((r,g,b))cv2.imwrite("hat_alpha.jpg",a)for可以用rgb通道的头像图片计算。我们将rgb的三个通道组合成一个rgb的彩色帽子图像。alpha通道的图像如下图所示:人脸检测和人脸关键点检测。测试图:下面我们使用dlib的frontfacedetector进行人脸检测,使用dlib提供的模型提取人脸的五个关键点。代码如下:#dlib人脸关键点检测器predictor_path="shape_predictor_5_face_landmarks.dat"predictor=dlib.shape_predictor(predictor_path)#dlib正面人脸检测器detector=dlib.get_frontal_face_detector()#正面人脸检测dets=detector(img,1)#如果检测到人脸iflen(dets)>0:fordindets:x,y,w,h=d.left(),d.top(),d.right()-d.left(),d.bottom()-d.top()#x,y,w,h=faceRectcv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2,8,0)#关键点检测,5个关键点shape=predictor(img,d)forpointinshape.parts():cv2.circle(img,(point.x,point.y),3,color=(0,255,0))cv2.imshow("image",img)cv2.waitKey()这部分的效果如下图所示:为了调整帽子的大小,我们在眼角处选择两个点,并在放置帽子的x方向找中心作为参考坐标,y方向的坐标用人脸框上线的y坐标表示。然后我们根据人脸检测检测到的人脸大小来调整帽子的大小,让帽子的大小合适。#选择左右眼角的点point1=shape.part(0)point2=shape.part(2)#求两点的中心eyes_center=((point1.x+point2.x)//2,(point1.y+point2.y)//2)#cv2.circle(img,eyes_center,3,color=(0,255,0))#cv2.imshow("image",img)#cv2.waitKey()#根据脸的大小调整帽子大小factor=1.5resized_hat_h=int(round(rgb_hat.shape[0]*w/rgb_hat.shape[1]*factor))resized_hat_w=int(round(rgb_hat.shape[1]*w/rgb_hat.shape[1]*factor))ifresized_hat_h>y:resized_hat_h=y-1#根据脸的大小调整帽子大小resized_hat=cv2.resize(rgb_hat,(resized_hat_w,resized_hat_h))提取帽子和需要添加帽子的区域按照之前描述的去Alpha通道作为掩码并取反。这两个蒙版之一用于移除帽子图中的帽子区域;另一个用于清空角色图中需要填充帽子的区域。#使用alpha通道为maskmask=cv2.resize(a,(resized_hat_w,resized_hat_h))mask_inv=cv2.bitwise_not(mask)后面你会看到:从原图中取出需要加帽子的区域,这里我们使用位运算:#帽子与人脸框上线的偏移量dh=0dw=0#原图ROI#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)]#提取原图的帽子区域imageROIbg_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')这就是背景区域(bg),如下图,可以看出该区域需要装满的帽子不见了。然后我们提取帽子区域。#提取帽子区域hat=cv2.bitwise_and(resized_hat,resized_hat,mask=mask)提取的帽子区域如下图所示,帽子区域正好与之前的背景区域互补。AddSantahat***我们将这两个区域相加并将它们放回原始图像中以获得我们想要的圣诞帽图像。这里需要注意的是,在相加之前,resize要保证两者大小相同,因为四舍五入可能会出现不一致的情况。#添加前确保两者大小相同(可能因四舍五入不一致)hat=cv2.resize(hat,(bg_roi.shape[1],bg_roi.shape[0]))#添加两个ROI区域add_hat=cv2.add(bg,hat)#cv2.imshow("add_hat",add_hat)#把添加的帽子区域放回原图img[y+dh-resized_hat_h:y+dh,(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)]=add_hat***我们得到的效果图如下:
