利用anaconda在python环境下
使用命令:pip install dlib==19.8.1
pip install python-opencv
注意:安装dlib时容易出错,不行的话可以尝试新建环境
需要先下载dlib官方训练好的模型(shape_predictor_68_face_landmarks.dat)。下载链接:http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
然后将其解压到目标文件夹(与提取特征点的代码在同一文件夹)
目标:将人脸特征点保存到txt文档
landmark.py
import dlib
import cv2
# 与人脸检测相同,使用dlib自带的frontal_face_detector作为人脸检测器
detector = dlib.get_frontal_face_detector()
# 使用官方提供的模型构建特征提取器
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
# cv2读取图片
img = cv2.imread("nan.jpg")
# 与人脸检测程序相同,使用detector进行人脸检测 dets为返回的结果
dets = detector(img, 1)
# 使用enumerate 函数遍历序列中的元素以及它们的下标
# 下标k即为人脸序号
# left:人脸左边距离图片左边界的距离 ;right:人脸右边距离图片左边界的距离
# top:人脸上边距离图片上边界的距离 ;bottom:人脸下边距离图片上边界的距离
for k, d in enumerate(dets):
print("dets{}".format(d))
print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
k, d.left(), d.top(), d.right(), d.bottom()))
# 使用predictor进行人脸关键点识别 shape为返回的结果
shape = predictor(img, d)
# 获取第一个和第二个点的坐标(相对于图片而不是框出来的人脸)
print("Part 0: {}, Part 1: {} ...".format(shape.part(0), shape.part(1)))
# 绘制特征点
with open( 'results.txt', 'w' ) as f:
for index, pt in enumerate(shape.parts()):
#将特征点坐标写入txt文档
f.write('Part {}: {}'.format(index, pt))
#画圈
pt_pos = (pt.x, pt.y)
cv2.circle(img, pt_pos, 1, (255, 0, 0), 2)
# 利用cv2.putText输出1-68
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, str(index + 1), pt_pos, font, 0.3, (0, 0, 255), 1, cv2.LINE_AA)
cv2.imshow('img', img)
k = cv2.waitKey()
cv2.destroyAllWindows()
结果:
并生成文档
此文档不符合下一步实验的格式,要改成如下格式
注意:本人所用图像素均改为600*800,此程序只能得到68个特征点坐标,对下一步来说,缺少几处特征点的的坐标,通过手动添加(也可通过程序得到,但我不会)
缺少点的位置如图中红色圆圈
之后在txt文档中添加图片边框的8个点的坐标(依旧手动)
最后将txt文档名字改为”图片名.jpg“
face_morph.py
import numpy as np
import cv2
import sys
# 从文本文件中读取点
def readPoints(file):
# 创建数组存储点
points = []
with open(file) as file:
for line in file:
x, y = line.split()
points.append((int(x), int(y)))
return points
# 将使用srcTri和dstTri计算的仿射变换应用于src并返回结果图像。
def applyAffineTransform(src, srcTri, dstTri, size):
# 给定一对三角形,找到仿射变换
warpMat = cv2.getAffineTransform(np.float32(srcTri), np.float32(dstTri))
# 将仿射变换应用于src图片
dst = cv2.warpAffine(src, warpMat, (size[0], size[1]), None, flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_REFLECT_101)
return dst
# Warp和alpha将img1和img2的三角形区域混合到img中
def morphTriangle(img1, img2, img, t1, t2, t, alpha):
# 找到每个三角形区域的包络矩形
r1 = cv2.boundingRect(np.float32([t1]))
r2 = cv2.boundingRect(np.float32([t2]))
r = cv2.boundingRect(np.float32([t]))
# 各个矩形左上角的偏移点
t1Rect = []
t2Rect = []
tRect = []
for i in range(0, 3):
tRect.append(((t[i][0] - r[0]), (t[i][1] - r[1])))
t1Rect.append(((t1[i][0] - r1[0]), (t1[i][1] - r1[1])))
t2Rect.append(((t2[i][0] - r2[0]), (t2[i][1] - r2[1])))
# 填充三角形来获得掩码
mask = np.zeros((r[3], r[2], 3), dtype=np.float32)
cv2.fillConvexPoly(mask, np.int32(tRect), (1.0, 1.0, 1, 0), 16, 0)
# 将warpImage应用于小矩形块
img1Rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
img2Rect = img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]]
size = (r[2], r[3])
warpImage1 = applyAffineTransform(img1Rect, t1Rect, tRect, size)
warpImage2 = applyAffineTransform(img2Rect, t2Rect, tRect, size)
# Alpha混合矩形补丁
imgRect = (1.0 - alpha) * warpImage1 + alpha * warpImage2
# 将矩形块的三角形区域复制到输出图像
img[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] = img[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] * (1 - mask) + imgRect * mask
if __name__ == '__main__':
filename1 = 'nv.jpg'
filename2 = 'nan.jpg'
#两幅图的融合的比率,范围0到1
alpha = 0.5
# 读取图片
img1 = cv2.imread(filename1)
img2 = cv2.imread(filename2)
# 将矩阵转换为浮点数据
img1 = np.float32(img1)
img2 = np.float32(img2)
# 读取相关点
points1 = readPoints(filename1 + '.txt')
points2 = readPoints(filename2 + '.txt')
points = []
# 计算加权平均点坐标
for i in range(0, len(points1)):
x = (1 - alpha) * points1[i][0] + alpha * points2[i][0]
y = (1 - alpha) * points1[i][1] + alpha * points2[i][1]
points.append((x, y))
# 为最后的输出分配空间
imgMorph = np.zeros(img1.shape, dtype=img1.dtype)
with open("tri.txt") as file:
for line in file:
x, y, z = line.split()
x = int(x)
y = int(y)
z = int(z)
t1 = [points1[x], points1[y], points1[z]]
t2 = [points2[x], points2[y], points2[z]]
t = [points[x], points[y], points[z]]
# 一次合成一个三角形
morphTriangle(img1, img2, imgMorph, t1, t2, t, alpha)
# 输出结果
cv2.imshow("Morphed Face.jpg", np.uint8(imgMorph))
cv2.imwrite("video/001.jpg",np.uint8(imgMorph))
cv2.waitKey(0)
通过逐渐改变融合比率(alpha),输出并保存(imwrite)融合后的图片,图片名为001,002等。我的生成如下图
avi.py
import cv2
import os
#图片路径
im_dir = 'video'
#输出视频路径
video_dir = 'video/result.avi'
#帧率
fps =6
#图片数,图片数+1,因为后面的循环是从1开始
num = 22
#图片尺寸,若和图片本身尺寸不匹配,输出视频是空的
img_size = (600,800)
#fourcc = cv2.cv.CV_FOURCC('M','J','P','G')#opencv2.4
fourcc = cv2.VideoWriter_fourcc(*'MJPG') #opencv3.0
#读取所有帧,生成视频
videoWriter = cv2.VideoWriter(video_dir, fourcc, fps, img_size)
for i in range(1,num):
im_name = os.path.join(im_dir,str(i).zfill(3)+'.jpg')
frame = cv2.imread(im_name)
videoWriter.write(frame)
print(im_name)
这一步是将上一步生成的图片合成视频(我这里不会上传视频,就先这样,哈哈)。