人脸关键点检测是人脸识别和分析领域中的关键一步,它是诸如自动人脸识别、表情分析、三维人脸重建及三维动画等其它人脸相关问题的前提和突破口。
paddlehub提供了face_landmark_localization模型,可以快速的提供人脸部68个关键点(人脸轮廓17个点,左右眉毛各5个点,左右眼睛各6个点,鼻子9个点,嘴巴20个点)。
我计划试验在这68个点的基础上,为目标图像进行一个唐代妆容的美化。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200501212047172.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2tlbnNoaW41MTYxNjM=,size_16,color_FFFFFF,t_70)
利用识别出的关键点进行面部区域划定,然后使用opencv的方式进行填充和图像融合。
import paddlehub as hub
import cv2
import numpy as np
from matplotlib import pyplot as plt
import os
import random
%matplotlib inline
#展示图片效果
def img_show_bgr(image,size=8):
#cv2.cvtColor,plt.imshow,plt.axis
#节省空间,不填代码了
#返回两点中点坐标
def mid_point(p1,p2):
point=(np.array(p1)+np.array(p2))/2
point=point.astype(int)
return (point[0],point[1])
#返回两点距离
def dis_point(p1,p2):
x_dis=p1[0]-p2[0]
x_dis**=2
y_dis=p1[1]-p2[1]
y_dis**=2
return (x_dis+y_dis)**0.5
#肤色判定RGB
def skin_rgbrange(R,G,B):
skin = 0
if (abs(R - G) > 15) and (R > G) and (R > B):
if (R > 95) and (G > 40) and (B > 20) and (max(R,G,B) - min(R,G,B) > 15):
skin = 1
elif (R > 220) and (G > 210) and (B > 170):
skin = 1
return skin
关于肤色判定部分,更好的是使用通道识别,这里为了简便,直接使用了RGB
face_landmark = hub.Module(name="face_landmark_localization")
img_path = "./work/face_test01.jpg"
results = face_landmark.keypoint_detection(images=[cv2.imread(img_path)],visualization=True,output_dir="./work/output_face_landmark")
#前额区域 鹅黄
forehead_area=[]
forehead_area.append((points[18-1][0],y_eyebrow_min))
forehead_area.append((points[27-1][0],y_eyebrow_min))
forehead_area.append((points[18-1][0],points[28-1][1]-ot_face_height*1.2))
forehead_area.append((points[27-1][0],points[28-1][1]-ot_face_height*1.2))
forehead_hull=cv2.convexHull(np.array(forehead_area,np.int32).reshape((-1,1,2)))
#core_forehead眉心坐标
core_forehead=mid_point((points[18-1][0],y_eyebrow_min),(points[27-1][0],y_eyebrow_min))
dismax=dis_point(core_forehead,(points[18-1][0],y_eyebrow_min))
#面靥
#左5~49,右55~13 有偏移
#左38x,49y,右45x,55y
#l_face_ye=mid_point(points[5-1],points[49-1])
#r_face_ye=mid_point(points[55-1],points[13-1])
#print(l_face_ye,":",r_face_ye)
l_face_ye=(points[38-1][0],points[49-1][1])
r_face_ye=(points[46-1][0],points[55-1][1])
cv2.circle(image,l_face_ye, 10, (106,106,255), -1)
cv2.circle(image,r_face_ye, 10, (106,106,255), -1)
cv2.circle(image_flag,l_face_ye, 10, (106,106,255), -1)
cv2.circle(image_flag,r_face_ye, 10, (106,106,255), -1)
#斜红
#left 1,37中点,3,right 46,17中点15
l_face=[]
l_face.append(mid_point(points[1-1],points[37-1]))
l_face.append((mid_point(points[18-1],points[1-1])[0],points[3-1][1]))
l_face.append((mid_point(points[2-1],points[37-1])[0],points[2-1][1]))
l_face_hull=cv2.convexHull(np.array(l_face,np.int32).reshape((-1,1,2)))
cv2.drawContours(image,[l_face_hull], -1, (64,64,255), -1)
cv2.drawContours(image_flag,[l_face_hull], -1, (64,64,255), -1)
r_face=[]
r_face.append(mid_point(points[17-1],points[46-1]))
r_face.append((mid_point(points[27-1],points[17-1])[0],points[15-1][1]))
r_face.append((mid_point(points[16-1],points[46-1])[0],points[16-1][1]))
r_face_hull=cv2.convexHull(np.array(r_face,np.int32).reshape((-1,1,2)))
cv2.drawContours(image,[r_face_hull], -1, (0,0,255), -1)
cv2.drawContours(image_flag,[r_face_hull], -1, (0,0,255), -1)
#花钿
img_path_flow="./work/flower1.jpg"
image_flow=cv2.imdecode(np.fromfile(img_path_flow, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
flow_size_y=int(ot_face_height*0.4)
flow_size_x=int((flow_size_y/image_flow.shape[0])*image_flow.shape[1])
flow_zero_x=int(core_forehead[0]-flow_size_x/2)
flow_zero_y=int(core_forehead[1]-flow_size_y)
image_flow=cv2.resize(image_flow,(flow_size_y,flow_size_x))
ycrcb = cv2.cvtColor(image_flow, cv2.COLOR_BGR2YCrCb)
(y, cr, br) = cv2.split(image_flow)
_, cr = cv2.threshold(cr, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
for i in range(0,cr.shape[0]):
for j in range(0,cr.shape[1]):
if cr[i][j]==0:
image[flow_zero_y+i][flow_zero_x+j]=image_flow[i][j]
image_flag[flow_zero_y+i][flow_zero_x+j]=image_flow[i][j]
img_show_bgr(image_flag)
这里没有采用图片叠加的方式。用了直接绘图和像素替换的方法。直接绘图调用cv2的相应函数,如果要做渐变和融合后效果会更好,像素替换先做了图片模式的转换,希望能够最大限度保留素材图片丰富的变化,而不是一个纯色的。最后效果如图:
1.需要继续改进的地方还很多,因为面部的关键点在脸部动态中发挥的作用更大,点头摇头什么的,精确定位还需要考虑比例、肤色、光照等
2.采用图片叠加的方法会破坏原图的一些色调。像素替换只针对局部,对整体破坏会小。