1、介绍:

输入一张图片,控制脸部的轮廓,达到脸部变瘦的特效

2、下载模型

文章百度链接提供

3、配置环境

conda create -n facethin python=3.8
conda activate facethin 
pip install opencv-python
pip install dlib-19.19.0-cp38-cp38-win_amd64.whl

4、核心代码

import cv2
import dlib
import numpy as np

# 获取图像中的人脸关键点
# 输入
# img图像
# det_face人脸检测器
# det_landmarks人脸关键点检测器
def get_landmarks_points(img,det_face,det_landmarks):
    # 转换为灰度
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 检测人脸区域
    face_rects = det_face(gray, 0)
    
    # 获取68个关键点
    landmarks = det_landmarks(gray, face_rects[0])
    
    # 获取关键点的坐标
    landmarks_points = []
    parts = landmarks.parts()
    for part in parts:
        landmarks_points.append((part.x,part.y))
    return landmarks_points
   
# 双线性差值   
def BilinearInsert(src,pt_U):
    ux = pt_U[0]
    uy = pt_U[1]
    
    x1=np.float32(int(ux))
    x2=x1+1
    y1=np.float32(int(uy))
    y2=y1+1
    
    v1 = np.float32(src[int(y1),int(x1)])
    v2 = np.float32(src[int(y1),int(x2)])
    v3 = np.float32(src[int(y2),int(x1)])
    v4 = np.float32(src[int(y2),int(x2)])
    
    part1 = v1 * (x2 - ux) * (y2 - uy)
    part2 = v2 * (ux - x1) * (y2 - uy)
    part3 = v3 * (x2 - ux) * (uy - y1)
    part4 = v4 * (ux - x1) * (uy - y1)
 
    insertValue=part1+part2+part3+part4
    return insertValue.astype(np.uint8)

def localTranslationWap(img,pt_C,pt_M,r,a):
    
    h,w,c = img.shape
    # 文件拷贝
    copy_img = np.zeros_like(img)
    copy_img = img.copy()
    
    # 创建蒙板
    mask = np.zeros((h,w),dtype = np.uint8)
    cv2.circle(mask,pt_C,np.int32(r),255,cv2.FILLED)
    
    # 计算 CM 之间的距离
    pt_C = np.float32(pt_C)
    pt_M = np.float32(pt_M)
    dis_M_C = np.dot((pt_C-pt_M),(pt_C-pt_M))

    # 只对蒙板内大于0的数进行处理
    for i in range(w):
        for j in range(h):
            
            # 只计算半径内的像素
            if mask[j,i] ==0:
                continue
                
            # 计算 XC之间的距离            
            pt_X = np.array([i,j],dtype = np.float32)
            dis_X_C = np.dot((pt_X-pt_C),(pt_X-pt_C))
            
            # 计算缩放比例
            radio = (r*r-dis_X_C)/(r*r-dis_X_C+a*dis_M_C)
            radio = radio*radio
            
            # 计算 目标图像ij处由源图像U点替换
            pt_U = pt_X-radio*(pt_M-pt_C)
            
            # 利用双线性差值法计算U点处的像素值
            # value = BilinearInsert(img,pt_U)
            # copy_img[j,i] = value
            
            # 直接获取U点的值
            pt_u = np.int32(pt_U)
            copy_img[j,i] = img[pt_u[1],pt_u[0]]
                        

    return copy_img

    
# 滑块的响应函数
def empty(a):
    pass

if __name__ == "__main__":
    
    # 创建滑块
    # cv2.namedWindow("TrackBars")
    # cv2.resizeWindow("TrackBars",640,30)
    # cv2.createTrackbar("a","TrackBars",60,200,empty)
        
    # 创建人脸检测器
    det_face = dlib.get_frontal_face_detector()

    # 加载标志点检测器
    ############################################加载模型###############################################################
    det_landmarks = dlib.shape_predictor("shape_predictor_68_face_landmarks_GTX.dat")  # 68
    ###########################################################################################################
    # 打开图片
    ####################################读入图片的地址#####################################################
    img = cv2.imread('./3/1.jpg')
    ###########################################################################################################

    # 获取源图像的68个关键点的坐标
    landmarks = get_landmarks_points(img,det_face,det_landmarks)
    landmarks = np.array(landmarks)
    
    # 瘦脸程度调节 
    a = 0.8
    
    # 右脸参数
    pt_C_right = landmarks[3]
    pt_M = landmarks[30]
    r_right = np.sqrt(np.dot(landmarks[3]-landmarks[5],landmarks[3]-landmarks[5])) 
    
    # 左脸参数
    pt_C_left = landmarks[13]   
    r_left = np.sqrt(np.dot(landmarks[13]-landmarks[11],landmarks[13]-landmarks[11]))
    
    # 减右脸
    img_thin = localTranslationWap(img,pt_C_right,pt_M,r_right,a)
    # 减左脸
    img_thin = localTranslationWap(img_thin,pt_C_left,pt_M,r_left,a)
    
    # 显示
    cv2.imshow('input',img)
    cv2.imshow('output',img_thin)
    while True:
        # a_new = cv2.getTrackbarPos("a","TrackBars")
        ########################################调整瘦脸的参数###################################################################
        a_new = 70
        ###########################################################################################################
        a_new = a_new/100
        
        if a != a_new:
            a = a_new
            print("processing  a= %.2f"%(a))
            # 减右脸
            img_thin = localTranslationWap(img,pt_C_right,pt_M,r_right,a)
            # 减左脸
            img_thin = localTranslationWap(img_thin,pt_C_left,pt_M,r_left,a)
            ##########################################输出图片的路径#############################################################
            cv2.imwrite("6.jpg",img_thin)
            ###########################################################################################################
            cv2.imshow('output',img_thin)
            print("done")
            
    
        key=cv2.waitKey(5000) & 0xFF 
        
        if key == ord('q'):
            break
    
    
    
    # # 右脸缩放
    # pt_C_right = landmarks[3]
    # pt_M = landmarks[30]
    # r_right = np.sqrt(np.dot(landmarks[3]-landmarks[5],landmarks[3]-landmarks[5]))   
    # img_thin = localTranslationWap(img,pt_C_right,pt_M,r_right,a)
    
    # # 左脸缩放
    # pt_C_left = landmarks[13]
    # pt_M = landmarks[30]
    # r_left = np.sqrt(np.dot(landmarks[13]-landmarks[11],landmarks[13]-landmarks[11]))
    # img_thin = localTranslationWap(img_thin,pt_C_left,pt_M,r_left,a)
    
    # # 结果显示
    # cv2.imshow('input',img)
    # cv2.imshow('output',img_thin)
    # # 显示原图
    # cv2.circle(img,landmarks[3],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img,landmarks[5],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img,landmarks[30],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img,landmarks[3],np.int32(r_right),(255,0,0))
    # cv2.line(img,landmarks[3],landmarks[30],(0,255,0),1)
    
    
    # cv2.circle(img,landmarks[13],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img,landmarks[11],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img,landmarks[30],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img,landmarks[13],np.int32(r_left),(255,0,0))
    # cv2.line(img,landmarks[13],landmarks[30],(0,255,0),1)
    
    # cv2.imshow('input',img)
    
    
    # cv2.circle(img_thin,landmarks[3],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img_thin,landmarks[5],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img_thin,landmarks[30],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img_thin,landmarks[3],np.int32(r_right),(255,0,0))
    # cv2.line(img_thin,landmarks[3],landmarks[30],(0,255,0),1)
    
    
    # cv2.circle(img_thin,landmarks[13],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img_thin,landmarks[11],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img_thin,landmarks[30],2,(255,0,0),cv2.FILLED)
    # cv2.circle(img_thin,landmarks[13],np.int32(r_left),(255,0,0))
    # cv2.line(img_thin,landmarks[13],landmarks[30],(0,255,0),1)
    # cv2.imshow('output',img_thin)
    
    
    
    
    
    
  
    # cv2.waitKey(0)
    
    
    
    
   

5、运行

python face_thin.py

6、效果展示

资源下载
免费资源
链接点击下载(提取码: ma87)复制