当前位置: 首页 > 后端技术 > Python

一行命令自动戴上口罩

时间:2023-03-26 19:24:24 Python

本文同时发表在Prodesire公众号和Prodesireblog。前言2019年底开始蔓延的新冠肺炎疫情牵动着人们的心。作为个人,我们能做的就是尽量宅在家里,少出门。看到有朋友请设计同学帮忙给自己的头像贴上面具。作为一名技术人员,我认为有这种需求的人一定更多。不如自己开发一个简单的程序来实现这个需求,也算是帮设计姐减轻了工作量。于是花了点时间写了一个命令行工具face-mask,可以很方便的给图片中的人像贴上面具,而且面具的方向和大小都是自适应脸型的~使用并安装face-mask来确保Python3.6及以上版本pipinstallface-mask使用face-mask直接指定图片路径给图片中的人像打上遮罩,生成新图片(附加-with-mask后缀):face-mask/path/to/face/picture通过指定--show选项,也可以使用默认图片查看器打开新生成的图片:face-mask/path/to/face/picture--showeffectforapersonwearingamask多人戴口罩,动漫人物戴口罩实现思路要达到上面的效果,我们应该怎么做呢?可以这样想:首先,识别鼻子(nose_bridge)和面部轮廓(chin),确定面部左点(chin_left_point)、面部底部点(chin_bottom_point)和面部右侧点(chin_right_point))通过面部轮廓。单击以确定遮罩尺寸的高度和中心线。将面具的左右两侧分成两部分。调整左侧遮罩的大小。宽度是从面的左点到中心线的距离。调整右侧遮罩的大小。宽度是面的右点到中心线的距离。Mergeleftandright蒙版就是新的蒙版。旋转新蒙版,角度为中心线相对于y轴的旋转角度。将新蒙版放在原始图像的适当位置。对于人脸识别,可以使用face_recognition库进行识别。关于图像处理,可以使用Pillow库进行处理。代码有了思路之后,实现起来就比较容易了。但是,熟悉库和图像变换计算可能需要一些时间。详细代码请阅读face-mask。这里只介绍核心步骤。人脸识别importface_recognitionface_image_np=face_recognition.load_image_file('/path/to/face/picture')face_landmarks=face_recognition.face_landmarks(face_image_np)借助face_recognition库可以轻松识别人像,最终的face_landmarks是一个列表,其中每一个face_landmark代表一个人像数据。face_landmark是一个字典,其中键代表面部特征,值代表该特征的点列表。例如:键nose_bridge代表鼻梁,键chin代表脸颊。我们需要根据每一个face_landmark给对应的头像贴上mask。获取鼻子和脸颊的特征点importnumpyasnpnose_bridge=face_landmark['nose_bridge']nose_point=nose_bridge[len(nose_bridge)*1//4]nose_v=np.array(nose_point)chin=face_landmark['chin']chin_len=len(chin)chin_bottom_point=chin[chin_len//2]chin_bottom_v=np.array(chin_bottom_point)chin_left_point=chin[chin_len//8]chin_right_point=chin[chin_len*7//8]通过上面的代码,我们得到:鼻梁上的一个点nose_point代表脸部左边的点。chin_left_point表示面部的右侧点。chin_right_point表示面部的底部点。/mask/picture')#splitmaskandresizewidth=_mask_img.widthheight=_mask_img.heightwidth_ratio=1.2new_height=int(np.linalg.norm(nose_v-chin_bottom_v))#leftmask_left_img=_mask_img.crop((0,/0,宽度/2,height))mask_left_width=get_distance_from_point_to_line(chin_left_point,nose_point,chin_bottom_point)mask_left_width=int(mask_left_width*width_ratio)mask_left_img=mask_leftt_img.resize((mask_left_width,new_height))#rightmask_right_img=_mask_img.crop((宽度//2,0,width,height))mask_right_width=get_distance_from_point_to_line(chin_right_point,nose_point,chin_bottom_point)mask_right_width=int(mask_right_width*width_ratio)mask_right_img=mask_right_img.resize((mask_right_width,new_height))#mergemasksize=(mask_left_img.width+mask_right_img.width,new_height)mask_img=Image.new('RGBA',size)mask_img.paste(mask_left_img,(0,0),immask_left)mask_img.paste(mask_right_img,(mask_left_img.width,0),mask_right_img)上述代码主要做了以下工作:将mask的左右两边分成两部分,调整左边mask的大小。宽度为脸部左侧点到中线的距离*宽度因子1.2调整右侧面具的大小,宽度为脸部右侧点到中心线的距离*宽度因子1.2合并了left和rightmasksintoanewmaskget_distance_from_point_to_line用于获取一个点到一条线的距离,具体实现可以看源码width_ratio是宽度因子,用于适当展开mask。原因是我们是根据脸颊的宽度来计算口罩的宽度,但是口罩是留在耳朵上的,所以实际的宽度应该更宽一些。旋转蒙版并将其放置在原始图像的适当位置#rotatemaskangle=np.arctan2(chin_bottom_point[1]-nose_point[1],chin_bottom_point[0]-nose_point[0])rotated_mask_img=mask_img.rotate(angle,expand=True)#计算masklocationcenter_x=(nose_point[0]+chin_bottom_point[0])//2center_y=(nose_point[1]+chin_bottom_point[1])//2offset=mask_img.width//2-mask_left_img.widthradian=角度*np。pi/180box_x=center_x+int(offset*np.cos(radian))-rotated_mask_img.width//2box_y=center_y+int(offset*np.sin(radian))-rotated_mask_img.height//2#添加mask_face_img.paste(mask_img,(box_x,box_y),mask_img)上面代码主要做了以下几件事:旋转新的mask,角度是中心线相对于y轴的旋转角度,计算mask应该放置的坐标,把新的mask放到原图计算出来的坐标下最后一步就是把新图保存到本地路径下,代码就不再显示了。总结我们可以借助face_recognition库轻松识别人像,然后根据脸颊的宽度和鼻梁的位置计算出口罩的大小、方向和位置,最后生成佩戴图片一张面具。整个过程并不复杂,只是坐标计算要格外小心,所以我们制作了一个短小精悍的“自动戴上口罩”程序!