大家好,今天跟大家分享一个利用python + opencv + dlib 实现一个带滑动条控制的唇色变换案例!
大致内容包括:
1、demo展示
2、思路剖析
3、算法实现
如果内容对你有所帮助的话,这次帮我点个在看分享一下吧
一、demo效果展示
demo已经上传到视频号上了,可以直接点击观看,欢迎关注!
从demo 中可以看到,当我们调整下方的三个RGB 滑动条的时候,可以实现实时的调整嘴唇的颜色。
下面看一下具体的实现思路!
二、思路剖析
具体的思路可以分为下面几个部分:
1、人脸关键点检测
2、嘴唇区域mask提取
3、嘴唇区域上色并与原图融合
1、关键点检测
这里使用的dlib,进行人脸关键点检测(检测到 68 个人脸关键点)
在项目中的 Face_Parts.py 中已实现了对人脸的各个区域的关键点和关键点围成的多边形可视化,后续如果需要对其他部分(非嘴唇区域)进行类似上色,或者变装等,都可以自行拓展使用。
2、嘴唇区域mask提取
通过dlib 检测到的嘴唇区域关键点序列(关键点序号48-61),提取序列并将嘴唇区域关键点连成一个多边形,制作成一个mask,以便后续进行上色处理
3、嘴唇区域上色并与原图融合
这里通过opencv 的滑动条,来进行交互,实现从外部输入 自定义的 rgb 颜色,从而改变唇色,并使用 alpha 融合与原图融合生成最终的效果(PS:这里作者使用高斯模糊处理,让 mask 区域更加的平滑,不会那么尖锐,看起来更加自然)
滑动条的创建和值的获取使用的函数分别是:
cv2.createTrackbar
cv2.getTrackbarPos
三、算法实现
下面是具体的算法实现,这里备注
shape_predictor_68_face_landmarks.dat
可以去 dlib 项目去下载:
import cv2
import numpy as np
import dlib
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
def empty(a):
pass
cv2.namedWindow('BGR')
cv2.resizeWindow('BGR',640,240)
cv2.createTrackbar('Blue','BGR',0,255,empty)
cv2.createTrackbar('Green','BGR',0,255,empty)
cv2.createTrackbar('Red','BGR',0,255,empty)
def createBox(img,points,scale=5,masked=False,cropped = True):
if masked:
mask = np.zeros_like(img)
mask = cv2.fillPoly(mask,[points],(255,255,255))
img = cv2.bitwise_and(img,mask)
# cv2.imshow('Mask',img)
if cropped:
bbox = cv2.boundingRect(points)
x,y,w,h = bbox
imgCrop = img[y:y+h,x:x+w]
imgCrop = cv2.resize(imgCrop,(0,0),None,scale,scale)
return imgCrop
else:
return mask
while True:
# image
# 1 读入图片并进行人脸关键点检测
img = cv2.imread('1.jpg')
img = cv2.resize(img,(0,0),None,0.5,0.5)
imgOriginal = img.copy()
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = detector(imgGray)
for face in faces:
x1,y1 = face.left(),face.top()
x2,y2 = face.right(),face.bottom()
# imgOriginal = cv2.rectangle(img, (x1,y1),(x2,y2),(0,255,0),2)
landmarks = predictor(imgGray,face)
myPoints =[]
for n in range(68):
x = landmarks.part(n).x
y = landmarks.part(n).y
myPoints.append([x,y])
# cv2.circle(imgOriginal,(x,y),5,(50,50,255),cv2.FILLED)
# cv2.putText(imgOriginal,str(n),(x,y-10),cv2.FONT_HERSHEY_COMPLEX_SMALL,0.9,(0,0,255),1)
myPoints = np.array(myPoints)
# imgLeftEye = createBox(img,myPoints[36:42],8)
# cv2.imshow('LeftEye',imgLeftEye)
# 2 嘴唇区域mask提取
imgLips = createBox(img,myPoints[48:61],8,masked=True,cropped=False)
imgColorLips = np.zeros_like(imgLips)
# 3 创建滑动条,以及获取滑动条的值,嘴唇区域上色并与原图融合
b = cv2.getTrackbarPos('Blue','BGR')
g = cv2.getTrackbarPos('Green','BGR')
r = cv2.getTrackbarPos('Red','BGR')
imgColorLips[:] = b,g,r
imgColorLips = cv2.bitwise_and(imgLips,imgColorLips)
imgColorLips = cv2.GaussianBlur(imgColorLips,(7,7),10)
#color_image
imgColorLips = cv2.addWeighted(imgOriginal,1,imgColorLips,0.4,0)
#gray_image
# imgOriginalGray = cv2.cvtColor(imgOriginal,cv2.COLOR_BGR2GRAY)
# imgOriginalGray = cv2.cvtColor(imgOriginalGray,cv2.COLOR_GRAY2BGR)
# imgColorLips = cv2.addWeighted(imgOriginalGray,1,imgColorLips,0.4,0)
cv2.imshow('BGR',imgColorLips)
# cv2.imshow('Lips',imgLips)
print(myPoints)
cv2.imshow("Original",imgOriginal)
cv2.waitKey(1)