写一个根据用户上传的图片使用OpenCV库读取图片并进行人脸检测。 使用Dlib库定位出人脸关键点,比如眼睛、嘴巴、眉毛等。 将检测到的关键点用于生成一个人脸网格,以便于后面进行形变处理。 使用形变算法将人物的面部特征卡通化,如加大眼睛、改变眉毛形状、加大嘴巴等。 通过卡通处理后的面部特征与原始图片进行融合,生成卡通化后的程序,要求有用户上传图片的功能和保存图片的功能,并注释代码的用途
时间: 2023-05-24 15:00:45 浏览: 161
以下是用于人脸卡通化程序的 Python 代码,其中包含使用 OpenCV 库读取和显示图像、使用 Dlib 库对面部特征进行检测和标记,以及使用卡通化算法对图像进行形变处理。代码旨在将用户上传的图片转换为卡通化人物头像。
#导入所需库
import cv2
import dlib
import numpy as np
#读取并展示图片
image = cv2.imread("filename.jpg")
cv2.imshow("Original Image", image)
cv2.waitKey(0)
#使用 Dlib 库获取人脸关键点
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
rects = detector(gray, 0)
for (i, rect) in enumerate(rects):
shape = predictor(gray, rect)
shape = face_utils.shape_to_np(shape)
#标记人脸关键点
for (x, y) in shape:
cv2.circle(image, (x, y), 2, (0, 255, 0), -1)
cv2.imshow("Facial Landmarks", image)
cv2.waitKey(0)
#获取图像网格并应用形变算法进行卡通化
output = cartoonify(image)
cv2.imshow("Cartoonified Image", output)
cv2.waitKey(0)
#保存卡通化图片
cv2.imwrite("cartoonified_image.jpg", output)
#卡通化算法实现
def cartoonify(image):
# 获取人脸关键点并生成网格
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
rects = detector(gray, 0)
for (i, rect) in enumerate(rects):
shape = predictor(gray, rect)
shape = face_utils.shape_to_np(shape)
# 基于关键点形成网格
(x, y, w, h) = cv2.boundingRect(np.array([shape]))
roi = image[y:y + h, x:x + w]
rows, cols, _ = roi.shape
size = max(rows, cols)
#通过三角形网格化
subdiv = cv2.Subdiv2D((x, y, x + w, y + h))
for p in shape:
subdiv.insert((p[0], p[1]))
triangles = subdiv.getTriangleList()
triangles = np.array(triangles, dtype=np.int32)
for t in triangles:
pt1 = (t[0], t[1])
pt2 = (t[2], t[3])
pt3 = (t[4], t[5])
#扭曲三角形
distorted_triangle(image, pt1, pt2, pt3)
return image
def distorted_triangle(img, pt1, pt2, pt3):
#计算三角形的外接圆半径
x_min, x_max, y_min, y_max = get_bounding_box(pt1, pt2, pt3)
circum_r = (x_max - x_min + y_max - y_min) / 4
circum_center = circumcenter(pt1, pt2, pt3)
#扭曲三角形内的每一个像素
for y in range(y_min, y_max):
for x in range(x_min, x_max):
p = np.array([x, y])
dist = np.linalg.norm(p - circum_center)
if dist > circum_r:
continue
#计算像素在原始图像中的位置
src_x, src_y = get_source_point(p, pt1, pt2, pt3)
if src_x < 0 or src_y < 0 or src_x >= img.shape[1] or src_y >= img.shape[0]:
continue
#将卡通化算法应用于像素
img[y, x] = cartoonify_pixel(img, src_x, src_y, x, y)
#计算三角形的外接圆信息
def get_bounding_box(pt1, pt2, pt3):
x_min = min(pt1[0], pt2[0], pt3[0])
x_max = max(pt1[0], pt2[0], pt3[0])
y_min = min(pt1[1], pt2[1], pt3[1])
y_max = max(pt1[1], pt2[1], pt3[1])
return x_min, x_max, y_min, y_max
#计算三角形的外接圆圆心
def circumcenter(pt1, pt2, pt3):
mat = np.array([
[pt1[0], pt1[1], 1],
[pt2[0], pt2[1], 1],
[pt3[0], pt3[1], 1],
])
a = np.linalg.det(mat[:, [1, 2]])
b = np.linalg.det(mat[:, [2, 0]])
c = np.linalg.det(mat[:, [0, 1]])
if c != 0:
cx = a / (2 * c)
cy = -b / (2 * c)
else:
cx = 0
cy = 0
return np.array([cx, cy])
#获取像素在原始图像中的位置
def get_source_point(pt, pt1, pt2, pt3):
#将三角形拆分为三个小三角形
sub_triangles = [
[pt1, pt2, pt],
[pt2, pt3, pt],
[pt1, pt3, pt],
]
src_points = []
weights = []
#计算每个小三角形中像素在原始图像中的位置和权重
for sub_triangle in sub_triangles:
mat1 = np.array([
[sub_triangle[0][0], sub_triangle[0][1], 1],
[sub_triangle[1][0], sub_triangle[1][1], 1],
[sub_triangle[2][0], sub_triangle[2][1], 1],
])
mat2 = np.array([
[pt[0], pt[1], 1],
[sub_triangle[1][0], sub_triangle[1][1], 1],
[sub_triangle[2][0], sub_triangle[2][1], 1],
])
mat3 = np.array([
[sub_triangle[0][0], sub_triangle[0][1], 1],
[pt[0], pt[1], 1],
[sub_triangle[2][0], sub_triangle[2][1], 1],
])
mat4 = np.array([
[sub_triangle[0][0], sub_triangle[0][1], 1],
[sub_triangle[1][0], sub_triangle[1][1], 1],
[pt[0], pt[1], 1],
])
#分别计算三个矩阵的行列式值,并计算权重
wt1 = np.linalg.det(mat1)
wt2 = np.linalg.det(mat2) / wt1
wt3 = np.linalg.det(mat3) / wt1
wt4 = np.linalg.det(mat4) / wt1
#将像素位置和权重存入数组
src_points.append(sub_triangle)
weights.append([wt2, wt3, wt4])
#计算像素在原始图像中的位置和权重的和
src_wt = np.zeros((1, 3))
src_pos = np.zeros((1, 2))
for i in range(3):
src_pos += weights[i][0] * np.array([[src_points[i][0]], [src_points[i][1]]])
src_wt += weights[i][0] * np.array([[1, 1, 1]])[0]
#除以总权重后返回
src_pos /= src_wt[0]
return int(src_pos[0][0]), int(src_pos[1][0])
#卡通化算法的像素变换函数
def cartoonify_pixel(img, src_x, src_y, dst_x, dst_y):
src_color = img[src_y, src_x] / 255
gray_intensity = np.dot(src_color, [0.2989, 0.5870, 0.1140])
gray_color = np.array([gray_intensity, gray_intensity, gray_intensity])
dst_color = blend_colors(src_color, gray_color, 0.7)
return dst_color * 255
#计算两个颜色的融合
def blend_colors(c1, c2, alpha):
return (1 - alpha) * c1 + alpha * c2
我们还需要编写让用户能够上传和保存图像的代码,以实现完整程序的功能。
阅读全文