#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import dlib
import cv2
import numpy as np
import math
import time
predictor_path = 'shape_predictor_68_face_landmarks.dat'
# 使用dlib自带的frontal_face_detector作为我们的特征提取器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(predictor_path)
def landmark_dec_dlib_fun(img_src):
#转灰度图
img_gray = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY)
#cv2.imshow('grayimg',img_gray)
land_marks = []
rects = detector(img_gray, 0)
print(rects)
for i in range(len(rects)):
land_marks_node = np.matrix([[p.x, p.y] for p in predictor(img_gray, rects[i]).parts()])
# for idx,point in enumerate(land_marks_node):
# # 68点坐标
# pos = (point[0,0],point[0,1])
# print(idx,pos)
# # 利用cv2.circle给每个特征点画一个圈,共68个
# cv2.circle(img_src, pos, 5, color=(0, 255, 0))
# # 利用cv2.putText输出1-68
# font = cv2.FONT_HERSHEY_SIMPLEX
# cv2.putText(img_src, str(idx + 1), pos, font, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
land_marks.append(land_marks_node)
return land_marks
'''
方法1: Interactive Image Warping 局部放大算法
'''
def localTranslationWarp1(srcImg, startX, startY, endX, endY, radius):
ddradius = float(radius * radius)
copyImg = np.zeros(srcImg.shape, np.uint8)
copyImg = srcImg.copy()
t1 = time.time()
# 计算公式中的|m-c|^2
ddmc = (endX - startX) * (endX - startX) + (endY - startY) * (endY - startY)
H, W, C = srcImg.shape
for i in range(W):
for j in range(H):
# 计算该点是否在形变圆的范围之内
# 优化,第一步,直接判断是会在(startX,startY)的矩阵框中
if math.fabs(i - startX) > radius and math.fabs(j - startY) > radius:
continue
distance = (i - startX) * (i - startX) + (j - startY) * (j - startY)
if (distance < ddradius):
# 计算出(i,j)坐标的原坐标
# 计算公式中右边平方号里的部分
# ratio = (ddradius - distance) / (ddradius - distance + ddmc)
# ratio = ratio * ratio
rnorm = math.sqrt(distance) / radius
ratio = 1 - (rnorm - 1)*(rnorm - 1)*0.5
# 映射原位置
UX = startX + ratio * (i - startX)
UY = startY + ratio * (j - startY)
# 根据双线性插值法得到UX,UY的值
value = BilinearInsert(srcImg, UX, UY)
# 改变当前 i ,j的值
copyImg[j, i] = value
return copyImg
'''
方法2: Interactive Image Warping 局部平移算法
'''
def localTranslationWarp2(srcImg, startX, startY, endX, endY, radius):
ddradius = float(radius * radius)
copyImg = np.zeros(srcImg.shape, np.uint8)
copyImg = srcImg.copy()
# 计算公式中的|m-c|^2
ddmc = (endX - startX) * (endX - startX) + (endY - startY) * (endY - startY)
H, W, C = srcImg.shape
for i in range(W):
for j in range(H):
# 计算该点是否在形变圆的范围之内
# 优化,第一步,直接判断是会在(startX,startY)的矩阵框中
if math.fabs(i - startX) > radius and math.fabs(j - startY) > radius:
continue
distance = (i - startX) * (i - startX) + (j - startY) * (j - startY)
if (distance < ddradius):
# 计算出(i,j)坐标的原坐标
# 计算公式中右边平方号里的部分
ratio = (ddradius - distance) / (ddradius - distance + ddmc)
ratio = ratio * ratio
# 映射原位置
UX = i - ratio * (endX - startX)
UY = j - ratio * (endY - startY)
# 根据双线性插值法得到UX,UY的值
value = BilinearInsert(srcImg, UX, UY)
# 改变当前 i ,j的值
copyImg[j, i] = value
return copyImg
predictor_path = 'shape_predictor_68_face_landmarks.dat'
# 使用dlib自带的frontal_face_detector作为我们的特征提取器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(predictor_path)
def landmark_dec_dlib_fun(img_src):
#转灰度图
img_gray = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY)
#cv2.imshow('grayimg',img_gray)
land_marks = []
rects = detector(img_gray, 0)
#print(rects)
for i in range(len(rects)):
land_marks_node = np.matrix([[p.x, p.y] for p in predictor(img_gray, rects[i]).parts()])
# for idx,point in enumerate(land_marks_node):
# # 68点坐标
# pos = (point[0,0],point[0,1])
# print(idx,pos)
# # 利用cv2.circle给每个特征点画一个圈,共68个
# cv2.circle(img_src, pos, 5, color=(0, 255, 0))
# # 利用cv2.putText输出1-68
# font = cv2.FONT_HERSHEY_SIMPLEX
# cv2.putText(img_src, str(idx + 1), pos, font, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
land_marks.append(land_marks_node)
return land_marks
# 双线性插值法
def BilinearInsert(src, ux, uy):
w, h, c = src.shape
if c == 3:
x1 = int(ux)
x2 = x1 + 1
y1 = int(uy)
y2 = y1 + 1
part1 = src[y1, x1].astype(np.float64) * (float(x2) - ux) * (float(y2) - uy)
part2 = src[y1, x2].astype(np.float64) * (ux - float(x1)) * (float(y2) - uy)
part3 = src[y2, x1].astype(np.float64) * (float(x2) - ux) * (uy - float(y1))
part4 = src[y2, x2].astype(np.float64) * (ux - float(x1)) * (uy - float(y1))
insertValue = part1 + part2 + part3 + part4
return insertValue.astype(np.int8)
src = cv2.imread('1.jpg')
landmarks = landmark_dec_dlib_fun(src)
# if len(landmarks) == 0:
# return
for landmarks_node in landmarks:
# 第4个点左
left_landmark = landmarks_node[37]
# 第6个点左
left_landmark_down = landmarks_node[27]
# 第14个点右
right_landmark = landmarks_node[44]
# 第16个点右
right_landmark_down = landmarks_node[27]
# 第31个点鼻尖
endPt = landmarks_node[30]
def face_big_auto(x):
#68个关键点二维数组
#landmarks = landmark_dec_dlib_fun(src)
if len(landmarks) == 0:
return
w = cv2.getTrackbarPos('Bigeye', 'How big the eyes do you want')
# 计算第4个点到第6个点的距离作为瘦脸距离
# r_left = math.sqrt(
# (left_landmark[0, 0] - left_landmark_down[0, 0]) * (left_landmark[0, 0] - left_landmark_down[0, 0]) +
# (left_landmark[0, 1] - left_landmark_down[0, 1]) * (left_landmark[0, 1] - left_landmark_down[0, 1]))
#
# # 计算第14个点到第16个点的距离作为瘦脸距离
# r_right = math.sqrt(
# (right_landmark[0, 0] - right_landmark_down[0, 0]) * (right_landmark[0, 0] - right_landmark_down[0, 0]) +
# (right_landmark[0, 1] - right_landmark_down[0, 1]) * (right_landmark[0, 1] - right_landmark_down[0, 1]))
r_left = w
r_right = w
# 瘦左边脸
big_image = localTranslationWarp1(src, left_landmark[0, 0], left_landmark[0, 1], endPt[0, 0], endPt[0, 1],
r_left)
# 瘦右边脸
big_image = localTranslationWarp1(big_image, right_landmark[0, 0], right_landmark[0, 1], endPt[0, 0],
endPt[0, 1], r_right)
# 显示
cv2.imshow('How big the eyes do you want', big_image)
cv2.waitKey(0)
def face_thin_auto(x):
s = cv2.getTrackbarPos('Thinface', 'How big the eyes do you want')
# 如果未检测到人脸关键点,就不进行瘦脸
if len(landmarks) == 0:
return
for landmarks_node in landmarks:
#第4个点左
left_landmark = landmarks_node[3]
#第6个点左
left_landmark_down = landmarks_node[5]
#第14个点右
right_landmark = landmarks_node[13]
#第16个点右
right_landmark_down = landmarks_node[15]
#第31个点鼻尖
endPt = landmarks_node[30]
# 计算第4个点到第6个点的距离作为瘦脸距离
# r_left = math.sqrt(
# (left_landmark[0, 0] - left_landmark_down[0, 0]) * (left_landmark[0, 0] - left_landmark_down[0, 0]) +
# (left_landmark[0, 1] - left_landmark_down[0, 1]) * (left_landmark[0, 1] - left_landmark_down[0, 1]))
#
# # 计算第14个点到第16个点的距离作为瘦脸距离
# r_right = math.sqrt(
# (right_landmark[0, 0] - right_landmark_down[0, 0]) * (right_landmark[0, 0] - right_landmark_down[0, 0]) +
# (right_landmark[0, 1] - right_landmark_down[0, 1]) * (right_landmark[0, 1] - right_landmark_down[0, 1]))
r_left = s
r_right = s
# 瘦左边脸
thin_image = localTranslationWarp2(src, left_landmark[0, 0], left_landmark[0, 1], endPt[0, 0], endPt[0, 1],
r_left)
# 瘦右边脸
thin_image = localTranslationWarp2(thin_image, right_landmark[0, 0], right_landmark[0, 1], endPt[0, 0],
endPt[0, 1], r_right)
# 显示
cv2.imshow('How big the eyes do you want', thin_image)
cv2.waitKey(0)
cv2.namedWindow('How big the eyes do you want')
cv2.createTrackbar('Bigeye', 'How big the eyes do you want', 0, 70, face_big_auto)
cv2.createTrackbar('Thinface', 'How big the eyes do you want', 0, 60, face_thin_auto)
cv2.imshow('How big the eyes do you want',src)
cv2.waitKey(0)
# while True:
# #cv2.imshow('How big the eyes do you want', window)
# ch = cv2.waitKey(1) & 0xFF
# if ch == 27:
# break
cv2.destroyAllWindows()
opencv使用trackbar调控美颜程度
最新推荐文章于 2024-10-06 23:41:31 发布