未验证 提交 588b11d7 编写于 作者: D David-Hown 提交者: GitHub

first-commit

上级
文件已添加
# -*- coding: utf-8 -*-
'''
* @author [v_daweihao]
* @version [2021-08-10]
* 〈按照眼睛关键点对齐人脸〉
* Reference:
https://blog.csdn.net/weixin_35732969/article/details/83714492
https://blog.csdn.net/u013841196/article/details/85720897
https://zhuanlan.zhihu.com/p/32713815
https://blog.csdn.net/qq_20622615/article/details/80929746
https://blog.csdn.net/qq_36560894/article/details/105416273
https://blog.csdn.net/weixin_35732969/article/details/83714492
'''
import cv2
import numpy as np
import os
import dlib
from PIL import Image
import shutil
def get_face_mark(img_path):
'''
代码功能:
1. 用dlib人脸检测器检测出人脸,返回的人脸矩形框
2. 对检测出的人脸进行关键点检测并用圈进行标记
3. 将检测出的人脸关键点信息写到txt文本中
:param img_path:
:return:
'''
global landmarks
predictor_model = 'shape_predictor_68_face_landmarks.dat'
detector = dlib.get_frontal_face_detector() # dlib人脸检测器
predictor = dlib.shape_predictor(predictor_model)
# cv2读取图像
test_img_path = img_path
# output_pos_info = "test_img/Messi.txt"
img = cv2.imread(test_img_path)
# file_handle = open(output_pos_info, 'a')
# 取灰度
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 人脸数rects
rects = detector(img_gray, 0)
print('人脸数:' + str(len(rects)))
for i in range(len(rects)):
landmarks = np.matrix([[p.x, p.y] for p in predictor(img, rects[i]).parts()])
for idx, point in enumerate(landmarks):
# 68点的坐标
pos = (point[0, 0], point[0, 1])
# print(idx + 1, pos)
# pos_info = str(point[0, 0]) + ' ' + str(point[0, 1]) + '\n'
# file_handle.write(pos_info)
# 利用cv2.circle给每个特征点画一个圈,共68个
cv2.circle(img, pos, 3, color=(0, 255, 0))
# 利用cv2.putText输出1-68
# font = cv2.FONT_HERSHEY_SIMPLEX
# cv2.putText(img, str(idx+1), pos, font, 0.5, (0, 0, 255), 1, cv2.LINE_AA)
# file_handle.close()
cv2.imwrite("face_keypoints.png", img)
face_landmarks = []
landmarks = [j for j in np.array(landmarks)]
for i in range(68):
face_landmarks.append((landmarks[i][0], landmarks[i][1]))
return face_landmarks
def get_horizontal_offset(landmarks):
'''获得眼睛水平方向offset
:param landmarks: 68点人脸关键点
:return:
'''
# get list landmarks of left and right eye
left_eye = landmarks[37:43]
right_eye = landmarks[43:49]
# calculate the mean point of landmarks of left and right eye
left_eye_center = np.mean(left_eye, axis=0).astype("int")
right_eye_center = np.mean(right_eye, axis=0).astype("int")
# compute the horizontal distance between the eye centroids
dx = right_eye_center[0] - left_eye_center[0]
# # 计算左眼最左边关键点、右眼最右边关键点
# left_eye_min = np.min(left_eye, axis=0).astype("int")[1]
# right_eye_max = np.max(right_eye, axis=0).astype("int")[1]
# 计算两只眼睛的水平距离
# dx = right_eye_max[0] - left_eye_min[0]
# calculate the center of 2 eyes
# eye_center = ((left_eye_center[0] + right_eye_center[0]) // 2,
# (left_eye_center[1] + right_eye_center[1]) // 2)
return dx
def get_scaled_img(scale_ratio, img):
'''对图片进行等比例缩放
:param scale_ratio: dx_cartoon / dx_asian
:param img:
:return:
'''
# shape (高, 宽)
h = img.shape[0] # 图像的高
w = img.shape[1] # 图像的宽
ori_ratio = w / h
new_height = int(h * scale_ratio)
new_width = int(new_height * ori_ratio)
# (宽, 高)
img_new = cv2.resize(img, (new_width, new_height))
return img_new
def start_crop(split_img_dir, pcg_dir, scaled_dir, crop_dir, result_path, save_path):
'''剪裁亚洲人脸
按照卡通人脸眼睛水平距离缩放图片 --> scaled image
对scaled image进行padding --> result --> resize (512, 512)
join(asian image, cartoon image)
:param split_img_dir:
:param pcg_dir:
:param scaled_dir:
:param crop_dir:
:param result_path:
:param save_path:
:return:
'''
for img in os.listdir(split_img_dir):
try:
img_path = os.path.join(split_img_dir, img)
asian_img = cv2.imread(img_path)
asian_face_landmarks = get_face_mark(img_path)
dx_asian = get_horizontal_offset(asian_face_landmarks)
cartoon_path = os.path.join(pcg_dir, img)
cartoon_face_landmarks = get_face_mark(cartoon_path)
dx_cartoon = get_horizontal_offset(cartoon_face_landmarks)
cartoon_chin_landmarks = cartoon_face_landmarks[0:27]
cartoon_chin_min = np.min(cartoon_chin_landmarks, axis=0).astype("int")[1]
cartoon_chin_max = np.max(cartoon_chin_landmarks, axis=0).astype("int")[1]
upper_offset = cartoon_chin_min
bottom_offset = 512 - cartoon_chin_max
# get scale ratio
scale_ratio = dx_cartoon / dx_asian
scale_img = get_scaled_img(scale_ratio, asian_img)
scale_path = os.path.join(scaled_dir, img)
cv2.imwrite(scale_path, scale_img)
scaled_face_landmarks = get_face_mark(scale_path)
chin_landmarks = scaled_face_landmarks[0:27]
# 计算脸的轮廓 最上边/最下边点
chin_min = np.min(chin_landmarks, axis=0).astype("int")[1]
chin_max = np.max(chin_landmarks, axis=0).astype("int")[1]
delta_upper = chin_min - upper_offset
delta_bottom = chin_max + bottom_offset
# 裁剪图片
crop_img = scale_img[delta_upper:delta_bottom, :]
crop_path = os.path.join(crop_dir, img)
cv2.imwrite(crop_path, crop_img)
# 先固定长边,左右两边补齐至正方形
h, w = crop_img.shape[0], crop_img.shape[1]
max_edge = max(h, w)
min_edge = min(h, w)
supple_length = max_edge - min_edge
# 左右
if h > w:
left = supple_length // 2
right = supple_length // 2
pad_image = cv2.copyMakeBorder(crop_img, 0, 0, left, right, cv2.BORDER_REPLICATE, value=(0, 0, 0))
else:
top = supple_length // 2
bottom = supple_length // 2
pad_image = cv2.copyMakeBorder(crop_img, top, bottom, 0, 0, cv2.BORDER_REPLICATE, value=(0, 0, 0))
result = cv2.resize(pad_image, (512, 512))
padding_path = os.path.join(result_path, img)
cv2.imwrite(padding_path, result)
img1, img2 = Image.open(padding_path), Image.open(cartoon_path)
size1, size2 = img1.size, img2.size
joint = Image.new('RGB', (size1[0] + size2[0], size1[1]))
loc1, loc2 = (0, 0), (size1[0], 0)
joint.paste(img1, loc1)
joint.paste(img2, loc2)
joint.save(save_path + str('/') + img)
except Exception:
pass
continue
def remove_wrong(pcg_dir, save_path, wrong_path):
'''筛掉错误的数据
去除关键点错误的图片
:param pcg_dir:
:param save_path:
:param wrong_path:
:return:
'''
for img in os.listdir(pcg_dir):
cartoon_path = os.path.join(pcg_dir, img)
cartoon_img = cv2.imread(cartoon_path)
# 检测关键点是否存在
predictor_model = 'shape_predictor_68_face_landmarks.dat'
detector = dlib.get_frontal_face_detector() # dlib人脸检测器
predictor = dlib.shape_predictor(predictor_model)
# 取灰度
img_gray = cv2.cvtColor(cartoon_img, cv2.COLOR_RGB2GRAY)
# 人脸数rects
rects = detector(img_gray, 0)
src_path = os.path.join(save_path, img)
dst_path = os.path.join(wrong_path, img)
# if not os.path.exists(src_path):
# continue
# else:
# if len(rects) == 0:
# shutil.move(src_path, dst_path)
if len(rects) == 0:
shutil.move(src_path, dst_path)
else:
pass
if __name__ == '__main__':
split_img_dir = '/data/data_hao/PFLD-pytorch/20200809/split_image/val'
pcg_dir = '/data/data_hao/PFLD-pytorch/20200809/cartoon_pcg/cartoon_pcg_noseg_0807/val'
scaled_dir = '/data/data_hao/PFLD-pytorch/20200809/scaled_img'
crop_dir = '/data/data_hao/PFLD-pytorch/20200809/crop_img'
result_path = '/data/data_hao/PFLD-pytorch/20200809/result'
save_path = '/data/data_hao/PFLD-pytorch/20200809/join/val'
wrong_path = '/data/data_hao/PFLD-pytorch/20200809/wrong_img'
start_crop(split_img_dir, pcg_dir, scaled_dir, crop_dir, result_path, save_path)
remove_wrong(pcg_dir, save_path, wrong_path)
'''
* @author [v_daweihao]
* @version [2021-07-26]
* <融合图像过程中的数据预处理>
'''
import cv2
import numpy as np
import os
import dlib
from PIL import Image
import shutil
import glob
from blend_img_david import blend_img
def start_fusion(img_dir, art_mouth_path, save_path):
'''
对数据集中的所有图片进行融合
:param img_dir:
:return:
'''
# 创建 mouth_level : mouth_path
# level = {'1': '01.png', '3': '02.png', '5': '03.png', '7': '04.png', '9': '05.png'}
level = {'0': '01.png', '2': '02.png', '4': '03.png', '6': '04.png', '8': '05.png'}
# 遍历男生/女生卡通人脸
for image in os.listdir(img_dir):
index = image.split('.jpg')[0].split('_')[1][-1]
# 按照index找到对应的美术嘴巴
img_list = os.listdir(art_mouth_path)
img_list.sort(key=lambda x: int(x[:-4])) # 文件名按数字排序
# 得到待融合的两张图片路径
mouth_path = art_mouth_path + str('/') + level[index]
img_path = img_dir + str('/') + image
# print(mouth_path)
# print(img_path)
# 融合
try:
fusion = blend_img(img_path, mouth_path)
cv2.imwrite(save_path + str('/') + image.split('.jpg')[0] + '.png', fusion,
[int(cv2.IMWRITE_PNG_COMPRESSION), 9])
except Exception:
delete_path = img_dir + str('/') + image
os.remove(delete_path)
continue
def join(asian_dir, cartoon_dir, save_path):
"""
:param png1: path
:param png2: path
:param flag: horizontal or vertical
:return:
"""
for cartoon_img in os.listdir(cartoon_dir):
asian_img = asian_dir + str('/') + cartoon_img.split('.png')[0] + str('.jpg')
img1, img2 = Image.open(asian_img), Image.open(cartoon_dir + str('/') + cartoon_img)
# 统一图片尺寸,可以自定义设置(宽,高)
img1 = img1.resize((512, 512), Image.ANTIALIAS)
img2 = img2.resize((512, 512), Image.ANTIALIAS)
size1, size2 = img1.size, img2.size
joint = Image.new('RGB', (size1[0] + size2[0], size1[1]))
loc1, loc2 = (0, 0), (size1[0], 0)
joint.paste(img1, loc1)
joint.paste(img2, loc2)
joint.save(save_path + str('/') + cartoon_img)
if __name__ == "__main__":
# cartoon_img_dir = '/data/data_hao/seeprettyface-face_editor/tuning_cartoon'
# man_cartoon = '/data/data_hao/seeprettyface-face_editor/tuning_cartoon/man_cartoon'
# woman_cartoon = '/data/data_hao/seeprettyface-face_editor/tuning_cartoon/woman_cartoon'
# with open("man_number.txt", "r") as f:
# for line in f.readlines():
# line = line.strip('\n') # 去掉列表中每一个元素的换行符
# # 0003_000
# for i in range(10):
# img_path = cartoon_img_dir + str('/') + line.split('_')[0] + str('_') + str(i).zfill(3) + '.jpg'
# shutil.move(img_path, man_cartoon)
# os.remove(img_path)
# woman_cartoon_path = glob.glob(os.path.join(cartoon_img_dir + str('/'), '*.jpg'))
# # print(woman_cartoon_path)
# for i in range(len(woman_cartoon_path)):
# shutil.move(woman_cartoon_path[i], woman_cartoon)
# # os.remove(woman_cartoon_path[i])
# man_img_dir = '/data/data_hao/data_base/cartoon_man'
# for image in os.listdir(man_img_dir):
# # 0019_004.jpg
# # 0493_000.jpg
# try:
# last_num = image.split('.jpg')[0].split('_')[1][-1]
# # 选取偶数编号的卡通人脸
# if (int(last_num) % 2) == 0:
# even_path = man_img_dir + str('/') + image
# shutil.move(even_path, '/data/data_hao/data_base/cartoon_man/even_man')
# # print(delete_path)
# except Exception:
# print('wrong')
# continue
#
# man_img_dir = '/data/data_hao/data_base/cartoon_man'
# for image in os.listdir(man_img_dir):
# # 0019_004.jpg
# # 0493_000.jpg
# try:
# last_num = image.split('.jpg')[0].split('_')[1][-1]
# # 选取奇数编号的卡通人脸
# if (int(last_num) % 2) != 0:
# odd_path = man_img_dir + str('/') + image
# shutil.move(odd_path, '/data/data_hao/data_base/cartoon_man/odd_man')
# except Exception:
# print('wrong')
# continue
#
# woman_img_dir = '/data/data_hao/data_base/cartoon_woman'
# for image in os.listdir(woman_img_dir):
# # 0019_004.jpg
# # 0493_000.jpg
# try:
# last_num = image.split('.jpg')[0].split('_')[1][-1]
# # 选取偶数编号的卡通人脸
# if (int(last_num) % 2) == 0:
# even_path = woman_img_dir + str('/') + image
# shutil.move(even_path, '/data/data_hao/data_base/cartoon_woman/even_woman')
# # print(delete_path)
# except Exception:
# print('wrong')
# continue
#
# for image in os.listdir(woman_img_dir):
# # 0019_004.jpg
# # 0493_000.jpg
# try:
# last_num = image.split('.jpg')[0].split('_')[1][-1]
# # 选取奇数编号的卡通人脸
# if (int(last_num) % 2) != 0:
# odd_path = woman_img_dir + str('/') + image
# print(odd_path)
# shutil.move(odd_path, '/data/data_hao/data_base/cartoon_woman/odd_woman')
# except Exception:
# print('wrong')
# continue
# art_man_path = "/data/data_hao/PFLD-pytorch/man_art"
# save_man_path = '/data/data_hao/data_base/man_fusion'
# # 男 偶
# man_img_dir = '/data/data_hao/data_base/cartoon_man/even_man'
# start_fusion(man_img_dir, art_man_path, save_man_path)
# art_woman_path = "/data/data_hao/PFLD-pytorch/woman_art"
# woman_img_dir = '/data/data_hao/data_base/cartoon_woman/even_woman'
# save_woman_path = '/data/data_hao/data_base/woman_fusion'
# start_fusion(woman_img_dir, art_woman_path, save_woman_path)
# 横向拼接后图像保存路径
Asian_man_img_dir = '/data/data_hao/data_base/style_gan2'
save_man_path = '/data/data_hao/data_base/man_fusion'
join_man_path = '/data/data_hao/data_base/man_join'
join(Asian_man_img_dir, save_man_path, join_man_path)
\ No newline at end of file
'''
* @author [v_daweihao]
* @version [2021-07-15]
* 〈卡通化亚洲人脸图像〉
'''
import cv2
import numpy as np
import onnxruntime
import os
class FaceCartoon:
sess = None
# MODEL_PATH = "models/FaceCartoon.pb"
# INPUT_SIZE = 256
MODEL_PATH = "noseg_224_20_0331.onnx"
def __init__(self):
self.sess = onnxruntime.InferenceSession(self.MODEL_PATH)
def infer(self, img):
ori_h, ori_w, _ = img.shape
inp_img = self.input_preprocess(img)
cartoon_face = self.sess.run(["output"], {"input": inp_img})[0]
cartoon_face = np.squeeze(cartoon_face)
cartoon_face = cartoon_face.transpose([1, 2, 0])
cartoon_face = ((cartoon_face + 1.) / 2) * 255.0
cartoon_face = cartoon_face.astype(np.uint8)
cartoon_face = cartoon_face[:, :, ::-1]
return cv2.resize(cartoon_face, (ori_w, ori_h))
def input_preprocess(self, img, size=224):
img = cv2.resize(img, (size, size))
nor = img / 255.0
inp = (nor - 0.5) / 0.5
inp = inp[:, :, ::-1]
inp = inp.transpose([2, 0, 1])
inp = inp.astype(np.float32)
return inp[np.newaxis, :, :, :]
if __name__ == '__main__':
fc = FaceCartoon()
asiac_img = '/data/data_hao/PFLD-pytorch/00140.png'
mg = cv2.imread(asiac_img)
r = fc.infer(mg)
r = cv2.resize(r, (512, 512), interpolation=cv2.INTER_AREA)
cv2.imwrite('/data/data_hao/PFLD-pytorch/CARTOON.png', r)
# 亚洲人脸数据集路径 男
# man_img = '/data/data_hao/style_gan2/man'
# # 生成的卡通人脸存放路径 男
# Cartoon_img = '/data/data_hao/data_base/cartoon_man'
# for image in os.listdir(man_img):
# image_path = os.path.join(man_img, image)
# img = cv2.imread(image_path)
# r = fc.infer(img)
# cv2.imwrite(Cartoon_img + str('/') + image.split('.jpg')[0] + '.jpg', r)
# # 亚洲人脸数据集路径 男
# woman_img = '/data/data_hao/style_gan2/woman'
# # 生成的卡通人脸存放路径 男
# Cartoon_img = '/data/data_hao/data_base/cartoon_woman'
# for image in os.listdir(woman_img):
# image_path = os.path.join(woman_img, image)
# img = cv2.imread(image_path)
# r = fc.infer(img)
# cv2.imwrite(Cartoon_img + str('/') + image.split('.jpg')[0] + '.jpg', r)
'''
* @author [v_daweihao]
* @version [2021-08-03]
* <将美术嘴巴融合到卡通人脸中,卡通化人脸数据集用美术提供的嘴巴进行替换>
* <高斯融合>
'''
import cv2
import numpy as np
import os
import dlib
from PIL import Image
def get_gaussian_filter(w, h, c_x, c_y, variance):
'''
高斯滤波
:param w:
:param h:
:param c_x:
:param c_y:
:param variance:
:return:
'''
# h, w = 1280, 720
heatmap = np.zeros((h, w))
# variance = 60
mul = 1.5
# c_x, c_y = (360, 640)
for x_p in range(0, w):
for y_p in range(0, h):
dist_sq = (x_p - c_x) * (x_p - c_x) + \
(y_p - c_y) * (y_p - c_y)
exponent = dist_sq / 2.0 / variance / variance
new_val = np.exp(-exponent) * mul
new_val = min(1, max(0, new_val))
heatmap[y_p, x_p] = new_val
return heatmap
class FaceLandmark:
'''
获取嘴巴关键点,生成色块颜色
'''
def __init__(self):
predictor_path = "shape_predictor_68_face_landmarks.dat"
# faces_path = "amazing_cartoon/0001_004.jpg"
# faces_path = "sample_imgs/0144_006.jpg"
# 加载dlib自带的人脸检测器
self.detector = dlib.get_frontal_face_detector()
# 加载模型
self.predictor = dlib.shape_predictor(predictor_path)
def __call__(self, img):
# 参数1表示对图片进行上采样一次,有利于检测到更多的人脸
dets = self.detector(img, 1)
shape = self.predictor(img, dets[0])
landmark = np.array([[p.x, p.y] for p in shape.parts()])
# 48 -> 60 是嘴巴的关键点
xmin = np.min(landmark[48:60, 0])
xmax = np.max(landmark[48:60, 0])
ymin = np.min(landmark[48:60, 1])
ymax = np.max(landmark[48:60, 1])
# 获取色块颜色,8 是下巴的点
color_bgr = [0, 0, 0]
for y in range(ymax + 5, landmark[8, 1]):
color_bgr[0] += img[int(y), (xmax + xmin) // 2, 0]
color_bgr[1] += img[int(y), (xmax + xmin) // 2, 1]
color_bgr[2] += img[int(y), (xmax + xmin) // 2, 2]
div = landmark[8, 1] - (ymax + 5)
color_bgr = list(map(lambda _: _ // div, color_bgr))
return [xmin, xmax, ymin, ymax], color_bgr
def blend_img(img_path, art_mouth):
'''
图像融合
:param img_path: 卡通人脸图像
:param art_mouth: 美术嘴巴图像
:return:
'''
# img_path .jpg文件
# art_mouth .png文件
fl = FaceLandmark()
img = cv2.imread(img_path)
box, color = fl(img)
h, w, c = img.shape
c_x = (box[1] + box[0]) // 2
c_y = (box[2] + box[3]) // 2
var = min(box[1] - box[0], box[3] - box[2])
mask = get_gaussian_filter(w, h, c_x, c_y, var)
cv2.imwrite('mask.jpg', mask)
# 色块结合高斯 mask 融合
for ri in range(h):
for ci in range(w):
img_color = img[ri, ci, :]
mask_val = mask[ri, ci]
blend_color = np.array([
mask_val * color[0] + (1 - mask_val) * img_color[0],
mask_val * color[1] + (1 - mask_val) * img_color[1],
mask_val * color[2] + (1 - mask_val) * img_color[2],
])
img[ri, ci, :] = blend_color.astype(np.uint8)
cv2.imwrite('mask_img.jpg', img)
# 把嘴巴贴上去,因为嘴巴的 box 和美术的 box 在尺寸上不一致
# 读取alpha通道
mouth_img = cv2.imread(art_mouth, cv2.IMREAD_UNCHANGED)
mh, mw, _ = mouth_img.shape
# 取嘴巴矩阵框最大那条边为基准,对应美术 05 的 w,需要根据不同情况来设置
# 但有一个最简单的方法是生成多个 slide
# [max_slide * 0.7, max_slide * 1.0, max_slide * 1.3, max_slide * 1.5]
max_slide = max(box[1] - box[0], box[3] - box[2])
factor = max_slide / mw
new_w, new_h = int(max_slide), int(mh * factor)
mouth_img = cv2.resize(mouth_img, (new_w, new_h), cv2.INTER_CUBIC)
# 计算出嘴巴矩阵的中心点,来确定美术嘴巴放置的位置
xmin = max(0, int(c_x - new_w / 2))
xmax = min(w, int(c_x + new_w / 2))
ymin = max(0, int(c_y - new_h / 2))
ymax = min(h, int(c_y + new_h / 2))
for ri in range(ymin, ymax):
for ci in range(xmin, xmax):
img_color = img[ri, ci, :]
mask_val = mouth_img[ri - ymin, ci - xmin, 3].astype(np.float32) / 255.0
mouth_color = mouth_img[ri - ymin, ci - xmin, :3]
blend_color = np.array([
mask_val * mouth_color[0] + (1 - mask_val) * img_color[0],
mask_val * mouth_color[1] + (1 - mask_val) * img_color[1],
mask_val * mouth_color[2] + (1 - mask_val) * img_color[2],
])
img[ri, ci, :] = blend_color.astype(np.uint8)
return img
def select_image(img_dir):
'''
从数据集中选取图片,按照奇数偶数分成两类(分别对应美术提供的嘴巴五种类型)
:param img_dir: 卡通人脸图像路径
'''
for image in os.listdir(img_dir):
# 0019_004.jpg
# 0493_000.jpg
last_num = image.split('.jpg')[0].split('_')[1][-1]
# 选取奇数编号的卡通人脸,偶数编号的卡通人脸移除
if (int(last_num) % 2) == 0:
delete_path = img_dir + str('/') + image
os.remove(delete_path)
# print(delete_path)
else:
continue
def start_fusion(img_dir, art_mouth_path, save_path):
'''
对数据集中的所有图片进行融合
:param img_dir: 卡通人脸图像
:param art_mouth_path: 美术提供的嘴巴图像
:param save_path: 融合后的保存路径
'''
# 创建 mouth_level : mouth_path
# 根据选取的卡通路径是属于奇数还是偶数,选择打卡
level = {'1': '01.png', '3': '02.png', '5': '03.png', '7': '04.png', '9': '05.png'}
# level = {'0': '01.png', '2': '02.png', '4': '03.png', '6': '04.png', '8': '05.png'}
# 遍历男生/女生卡通人脸
for image in os.listdir(img_dir):
index = image.split('.jpg')[0].split('_')[1][-1]
# 按照index找到对应的美术嘴巴
img_list = os.listdir(art_mouth_path)
img_list.sort(key=lambda x: int(x[:-4])) # 文件名按数字排序
# 得到待融合的两张图片路径
mouth_path = art_mouth_path + str('/') + level[index]
img_path = img_dir + str('/') + image
# print(mouth_path)
# print(img_path)
# 融合
fusion = blend_img(img_path, mouth_path)
cv2.imwrite(save_path + str('/') + image.split('.jpg')[0] + '.png', fusion,
[int(cv2.IMWRITE_PNG_COMPRESSION), 9])
# print(fusion)
# print(save_path + str('/') + image.split('.jpg')[0] + '.png')
# except Exception:
# delete_path = img_dir + str('/') + image
# os.remove(delete_path)
# continue
def join(asian_dir, cartoon_dir, save_path):
'''
将亚洲人脸与对应的融合后的卡通人脸进行拼接
:param asian_dir: 亚洲人脸路径
:param cartoon_dir: 融合后的卡通人脸路径
:param save_path: 拼接图像保存路径
'''
for cartoon_img in os.listdir(cartoon_dir):
asian_img = asian_dir + str('/') + cartoon_img.split('.png')[0] + str('.jpg')
img1, img2 = Image.open(asian_img), Image.open(cartoon_dir + str('/') + cartoon_img)
# 统一图片尺寸,可以自定义设置(宽,高)
img1 = img1.resize((512, 512), Image.ANTIALIAS)
img2 = img2.resize((512, 512), Image.ANTIALIAS)
size1, size2 = img1.size, img2.size
joint = Image.new('RGB', (size1[0] + size2[0], size1[1]))
loc1, loc2 = (0, 0), (size1[0], 0)
joint.paste(img1, loc1)
joint.paste(img2, loc2)
joint.save(save_path + str('/') + cartoon_img)
if __name__ == '__main__':
img_path = '/data/data_hao/PFLD-pytorch/0007_005.jpg'
art_mouth= '/data/data_hao/PFLD-pytorch/mouth03.png'
img = blend_img(img_path, art_mouth)
cv2.imwrite('/data/data_hao/PFLD-pytorch/fusion.jpg', img)
# # 处理图片
# Asian_woman_img_dir = '/data/data_hao/seeprettyface-face_editor/amazing_tuning/Asian_woman'
# # woamn_img_dir = '/data/data_hao/PFLD-pytorch/cartoon_face_database/woman'
# # # select_image(woamn_img_dir)
# Asian_man_img_dir = '/data/data_hao/seeprettyface-face_editor/amazing_tuning/Asian_man'
# select_image(man_img_dir)
# 对奇数编号男生进行融合
# art_man_path = "/data/data_hao/PFLD-pytorch/man_art"
# save_man_path = '/data/data_hao/data_base/man_fusion'
# man_img_dir = '/data/data_hao/data_base/cartoon_man/odd_man'
# start_fusion(man_img_dir, art_man_path, save_man_path)
# 对偶数编号男生进行融合 需要调整start_fusion代码level字典
# man_img_dir = '/data/data_hao/seeprettyface-face_editor/tuning_cartoon/man_cartoon/even_man'
# start_fusion(man_img_dir, art_man_path, save_man_path)
# # 横向拼接后图像保存路径
# join_man_path = '/data/data_hao/PFLD-pytorch/save_path/man_join'
# # 横向拼接 男生
# join(Asian_man_img_dir, save_man_path, join_man_path)
# art_woman_path = "/data/data_hao/PFLD-pytorch/woman_art"
# woman_img_dir = '/data/data_hao/data_base/cartoon_woman/odd_woman'
# save_woman_path = '/data/data_hao/data_base/woman_fusion'
# start_fusion(woman_img_dir, art_woman_path, save_woman_path)
# woamn_img_dir = '/data/data_hao/seeprettyface-face_editor/tuning_cartoon/man_cartoon/even_woman'
# start_fusion(woamn_img_dir, art_woman_path, save_woman_path)
# # # 横向拼接后图像保存路径
# join_woman_path = '/data/data_hao/PFLD-pytorch/save_path/woman_join'
# # # 横向拼接 男生
# join(Asian_man_img_dir, save_woman_path, join_woman_path)
# Asian_woman_img_dir = '/data/data_hao/data_base/style_gan2'
# save_woman_path = '/data/data_hao/data_base/woman_fusion'
# join_woman_path = '/data/data_hao/data_base/woman_join'
# join(Asian_woman_img_dir, save_woman_path, join_woman_path)
'''
* @author [v_daweihao]
* @version [2021-08-03]
* 〈亚洲人脸数据集按照男女分类〉
'''
import cv2
import os
import shutil
def getFaceBox(net, frame, conf_threshold=0.7):
frameOpencvDnn = frame.copy()
frameHeight = frameOpencvDnn.shape[0]
frameWidth = frameOpencvDnn.shape[1]
blob = cv2.dnn.blobFromImage(frameOpencvDnn, 1.0, (300, 300), [104, 117, 123], True, False)
net.setInput(blob)
detections = net.forward()
bboxes = []
for i in range(detections.shape[2]):
confidence = detections[0, 0, i, 2]
# print(confidence)
if confidence > conf_threshold:
x1 = int(detections[0, 0, i, 3] * frameWidth)
y1 = int(detections[0, 0, i, 4] * frameHeight)
x2 = int(detections[0, 0, i, 5] * frameWidth)
y2 = int(detections[0, 0, i, 6] * frameHeight)
bboxes.append([x1, y1, x2, y2])
cv2.rectangle(frameOpencvDnn, (x1, y1), (x2, y2), (0, 255, 0), int(round(frameHeight / 150)), 8)
return frameOpencvDnn, bboxes
def genderDetect(img_path):
'''
性别检测
:param img_path:
:return:
'''
global gender
faceProto = "opencv_face_detector.pbtxt"
faceModel = "opencv_face_detector_uint8.pb"
genderProto = "gender_deploy.prototxt"
genderModel = "gender_net.caffemodel"
MODEL_MEAN_VALUES = (78.4263377603, 87.7689143744, 114.895847746)
genderList = ['Male', 'Female']
# Load network
genderNet = cv2.dnn.readNet(genderModel, genderProto)
faceNet = cv2.dnn.readNet(faceModel, faceProto)
# Open a video file or an image file or a camera stream
padding = 20
# Read frame
frame = cv2.imread(img_path)
frameFace, bboxes = getFaceBox(faceNet, frame)
# print(bboxes)
bbox = bboxes[0]
# for bbox in bboxes:
# print(bbox)
face = frame[max(0, bbox[1] - padding):min(bbox[3] + padding, frame.shape[0] - 1),
max(0, bbox[0] - padding):min(bbox[2] + padding, frame.shape[1] - 1)]
blob = cv2.dnn.blobFromImage(face, 1.0, (227, 227), MODEL_MEAN_VALUES, swapRB=False)
genderNet.setInput(blob)
genderPreds = genderNet.forward()
gender = genderList[genderPreds[0].argmax()]
# print("Gender Output : {}".format(genderPreds))
# print("Gender : {}, conf = {:.3f}".format(gender, genderPreds[0].max()))
# cv2.imshow("Age Gender Demo", frameFace)
return gender
if __name__ == '__main__':
asian_dir = '/data/data_hao/style_gan2'
man_dir = '/data/data_hao/style_gan2/man/'
woman_dir = '/data/data_hao/style_gan2/woman/'
for img_name in os.listdir(asian_dir):
img_path = asian_dir + str('/') + img_name
try:
gender = genderDetect(img_path)
if gender == 'Male':
shutil.move(img_path, man_dir)
elif gender == 'Female':
shutil.move(img_path, woman_dir)
except Exception:
pass
continue
# # 亚洲人脸 男生
# man_dir = '/data/data_hao/style_gan2/man/'
# asian_dir = '/data/data_hao/style_gan2'
# for img in os.listdir(man_dir):
# index = img.split('.jpg')[0].split('_')[0]
# for as_img in os.listdir(asian_dir):
# img_path = asian_dir + str('/') + as_img
# as_index = as_img.split('.jpg')[0].split('_')[0]
# if index == as_index:
# shutil.move(img_path, man_dir)
# else:
# pass
#
# # 亚洲人脸 女生
# woman_dir = '/data/data_hao/style_gan2/woman/'
# asian_dir = '/data/data_hao/style_gan2'
# for img in os.listdir(woman_dir):
# index = img.split('.jpg')[0].split('_')[0]
# for as_img in os.listdir(asian_dir):
# img_path = asian_dir + str('/') + as_img
# as_index = as_img.split('.jpg')[0].split('_')[0]
# if index == as_index:
# shutil.move(img_path, woman_dir)
# else:
# pass
\ No newline at end of file
'''
* @author [v_daweihao]
* @version [2021-08-04]
* 〈生成视频图像数据处理〉
'''
import cv2
import numpy as np
import onnxruntime
import os
from PIL import Image
class FaceCartoonTest:
MODEL_PATH = "cartoon_gan_0804.onnx"
def __init__(self, model_path=None):
if model_path is not None:
self.cartoon = onnxruntime.InferenceSession(model_path)
else:
self.cartoon = onnxruntime.InferenceSession(self.MODEL_PATH)
_, _1, self.inp_h, self.inp_w = self.cartoon._sess.inputs_meta[0].shape
def infer(self, frame):
ori_h, ori_w, _ = frame.shape
inp_img = self.input_preprocess(frame)
cartoon_face = self.cartoon.run(["310"], {"input.1": inp_img})[0]
cartoon_face = np.squeeze(cartoon_face)
cartoon_face = cartoon_face.transpose([1, 2, 0])
cartoon_face = ((cartoon_face + 1.) / 2) * 255.0
cartoon_face = cartoon_face.astype(np.uint8)
cartoon_face = cartoon_face[:, :, ::-1]
return cv2.resize(cartoon_face, (ori_w, ori_h))
def input_preprocess(self, img):
img = cv2.resize(img, (self.inp_w, self.inp_h))
nor = img / 255.0
inp = (nor - 0.5) / 0.5
inp = inp[:, :, ::-1]
inp = inp.transpose([2, 0, 1])
inp = inp.astype(np.float32)
return inp[np.newaxis, :, :, :]
if __name__ == '__main__':
# 遍历含有21种属性的亚洲人脸
img_list = []
file_path = 'D:\\20210712\\Test_demo\\results\\results'
for dir in os.listdir(file_path):
sub_dir_path = os.path.join(file_path, dir)
for sub_file in os.listdir(sub_dir_path):
img_path = os.path.join(sub_dir_path, sub_file)
img_list.append(img_path)
# print(img_list[1])
# print(len(img_list))
# 亚洲人脸卡通化
car_list = []
name_list = []
fc = FaceCartoonTest()
for i in range(len(img_list)):
img_dir = img_list[i]
path, file = os.path.split(img_dir)
img_name = file[:-4]
img = cv2.imread(img_dir)
cartoon_img = fc.infer(img)
cartoon_img_dir = 'D:\\20210712\\Test_demo\\results\\cartoon\\{0}.jpg'.format(str(img_name))
cv2.imwrite(cartoon_img_dir, cartoon_img)
car_list.append(cartoon_img_dir)
name_list.append(img_name)
# 拼接所有图片
for i in range(len(img_list)):
asian_img_path = img_list[i]
cartoon_img_path = car_list[i]
save_path = 'D:\\20210712\\Test_demo\\results\\join\\{0}.jpg'.format(str(name_list[i]))
img1, img2 = Image.open(asian_img_path), Image.open(cartoon_img_path)
# 统一图片尺寸,可以自定义设置(宽,高)
img1 = img1.resize((512, 512), Image.ANTIALIAS)
img2 = img2.resize((512, 512), Image.ANTIALIAS)
size1, size2 = img1.size, img2.size
joint = Image.new('RGB', (size1[0] + size2[0], size1[1]))
loc1, loc2 = (0, 0), (size1[0], 0)
joint.paste(img1, loc1)
joint.paste(img2, loc2)
joint.save(save_path)
# 控制属性创建10FPS视频
size = (1024, 512)
# 创建视频对象
object = ['0000', '0008', '0010', '0013', '0016']
for i in range(5):
videowrite = cv2.VideoWriter(object[i] + '.mp4', cv2.VideoWriter_fourcc(*"mp4v"), 10, size)
for filename in [r'D:\20210712\Test_demo\results\join\{0}.jpg'.format(object[i] + '_' + str(j).zfill(3)) for j
in range(420)]:
videowrite.write(cv2.imread(filename))
videowrite.release()
print('end!')
# -*- coding:utf-8 -*-
import cv2
# 读入美术图像
img = cv2.imread("D:\\20210712\\PFLD-pytorch\\woman04.png")
img = cv2.resize(img, (512, 512), interpolation=cv2.INTER_AREA)
def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
# xy = "%d,%d" % (x, y)
# 人工打标注
cv2.circle(img, (x, y), 1, (255, 0, 0), thickness=-1)
# 将嘴巴关键点写入txt文件中
txt_path = "D:\\20210712\\PFLD-pytorch\\mouth04.txt"
file_handle = open(txt_path, 'a')
file_handle.write(str((x, y)[0]) + ' ' + str((x, y)[1]) + '\n')
# cv2.putText(img, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
# 1.0, (0, 0, 0), thickness=1)
print((x, y))
cv2.imshow("image", img)
file_handle.close()
cv2.namedWindow("image", cv2.WINDOW_NORMAL)
cv2.moveWindow("image", 512, 512)
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)
while (1):
cv2.imshow("image", img)
if cv2.waitKey(0) & 0xFF == 27:
break
cv2.destroyAllWindows()
\ No newline at end of file
'''
* @author [v_daweihao]
* @version [2021-08-03]
* <检测嘴巴是否张开>
'''
import math
from PIL import Image, ImageDraw
import face_recognition
import os
import shutil
import cv2
def get_lip_height(lip):
sum = 0
for i in [2, 3, 4]:
# distance between two near points up and down
distance = math.sqrt((lip[i][0] - lip[12 - i][0]) ** 2 +
(lip[i][1] - lip[12 - i][1]) ** 2)
sum += distance
return sum / 3
def get_mouth_height(top_lip, bottom_lip):
sum = 0
for i in [8, 9, 10]:
# distance between two near points up and down
distance = math.sqrt((top_lip[i][0] - bottom_lip[18 - i][0]) ** 2 +
(top_lip[i][1] - bottom_lip[18 - i][1]) ** 2)
sum += distance
return sum / 3
def check_mouth_open(top_lip, bottom_lip):
top_lip_height = get_lip_height(top_lip)
bottom_lip_height = get_lip_height(bottom_lip)
mouth_height = get_mouth_height(top_lip, bottom_lip)
# if mouth is open more than lip height * ratio, return true.
ratio = 0.5
if mouth_height > min(top_lip_height, bottom_lip_height) * ratio:
return True
else:
return False
if __name__ == "__main__":
# ffhq_path = '/data/data_hao/detect_mouth_open/images1024x1024'
# for image_file in os.listdir(ffhq_path):
# try:
# image = face_recognition.load_image_file(ffhq_path + str('/') + image_file)
# face_landmarks_list = face_recognition.face_landmarks(image)
# pil_image = Image.fromarray(image)
# d = ImageDraw.Draw(pil_image)
#
# top_lip = face_landmarks_list[0]['top_lip']
# bottom_lip = face_landmarks_list[0]['bottom_lip']
# print(top_lip)
# print(bottom_lip)
#
#
#
# top_lip_height = get_lip_height(top_lip)
# bottom_lip_height = get_lip_height(bottom_lip)
# mouth_height = get_mouth_height(top_lip, bottom_lip)
#
# # if mouth is open more than lip height * ratio, return true.
# ratio = 0.5
# if mouth_height > min(top_lip_height, bottom_lip_height) * ratio:
# # print("open")
# shutil.move(ffhq_path + str('/') + image_file, '/data/data_hao/detect_mouth_open/ffhq_open_mouth')
# else:
# pass
# except Exception:
# print('IndexError: list index out of range')
# continue
# /data/data_hao/PFLD-pytorch/03.png
# img = cv2.imread('/data/data_hao/PFLD-pytorch/woman_face/woman04.png')
# img = cv2.resize(img, (512, 512))
# cv2.imwrite('/data/data_hao/PFLD-pytorch/woman_crop04.jpg', img)
# image = face_recognition.load_image_file('/data/data_hao/PFLD-pytorch/0000_006.jpg')
image = face_recognition.load_image_file('/data/data_hao/PFLD-pytorch/woman_face/woman04.png')
face_landmarks_list = face_recognition.face_landmarks(image)
pil_image = Image.fromarray(image)
d = ImageDraw.Draw(pil_image)
print(face_landmarks_list)
top_lip = face_landmarks_list[0]['top_lip']
bottom_lip = face_landmarks_list[0]['bottom_lip']
print(top_lip)
print(bottom_lip)
for tup in top_lip:
bottom_lip.append(tup)
# print(set(bottom_lip)) # 去重
# landmark = list(set(bottom_lip))
# print(landmark)
# 将得到的关键点位置信息按行写进txt文件中,并将文件名以图像名字命名
fw = open('04.txt', 'w')
for line in list(set(bottom_lip)):
for a in line:
a = str(a)
fw.write(a)
fw.write('\t')
fw.write('\n')
fw.close()
# fw.writelines(["%s\n" % item for item in list(set(bottom_lip))])
\ No newline at end of file
#! /usr/bin/env python
'''
* @author [v_daweihao]
* @version [2021-08-03]
* 〈将卡通人脸嘴巴与美术提供的五官中的嘴巴进行置换〉
'''
import numpy as np
import os
import cv2
import dlib
def readPoints(path):
'''
Read points from text file
:param path: 嘴巴关键点txt文件路径
:return: 获取嘴巴关键点坐标列表
'''
# Create an array of points.
points = []
# Read points
with open(path) as file:
for line in file:
x, y = line.split()
points.append((int(x), int(y)))
return points
def applyAffineTransform(src, srcTri, dstTri, size):
'''
Apply affine transform calculated using srcTri and dstTri to src and output an image of size.
:param src:
:param srcTri:
:param dstTri:
:param size:
:return:
'''
# Given a pair of triangles, find the affine transform.
warpMat = cv2.getAffineTransform(np.float32(srcTri), np.float32(dstTri))
# Apply the Affine Transform just found to the src image
dst = cv2.warpAffine(src, warpMat, (size[0], size[1]), None, flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_REFLECT_101)
return dst
# Check if a point is inside a rectangle
def rectContains(rect, point):
if point[0] < rect[0]:
return False
elif point[1] < rect[1]:
return False
elif point[0] > rect[0] + rect[2]:
return False
elif point[1] > rect[1] + rect[3]:
return False
return True
# calculate delanauy triangle
def calculateDelaunayTriangles(rect, points):
'''
根据美术嘴巴的convex hull的点得到
The next step in alignment is to do a Delaunay triangulation of the points on the convex hull.
This allows us to divide the face into smaller parts.
:param rect: 待覆盖卡通人脸的嘴巴区域
:param points: 待覆盖卡通人脸的嘴巴convex hull中的点
:return: a Delaunay triangulation of the points on the convex hull
'''
# create subdiv
subdiv = cv2.Subdiv2D(rect)
# Insert points into subdiv
for p in points:
subdiv.insert(p)
triangleList = subdiv.getTriangleList()
delaunayTri = []
pt = []
for t in triangleList:
pt.append((t[0], t[1]))
pt.append((t[2], t[3]))
pt.append((t[4], t[5]))
pt1 = (t[0], t[1])
pt2 = (t[2], t[3])
pt3 = (t[4], t[5])
if rectContains(rect, pt1) and rectContains(rect, pt2) and rectContains(rect, pt3):
ind = []
# Get face-points (from 68 face detector) by coordinates
for j in range(0, 3):
for k in range(0, len(points)):
if (abs(pt[j][0] - points[k][0]) < 1.0 and abs(pt[j][1] - points[k][1]) < 1.0):
ind.append(k)
# Three points form a triangle. Triangle array corresponds to the file tri.txt in FaceMorph
if len(ind) == 3:
delaunayTri.append((ind[0], ind[1], ind[2]))
pt = []
return delaunayTri
def warpTriangle(img1, img2, t1, t2):
'''
Warps and alpha blends triangular regions from img1 and img2 to img
对美术嘴巴进行仿射变换,覆盖卡通人脸中的嘴巴,生成融合后的卡通人脸
:param img1: 美术提供的卡通人脸图像
:param img2: 待覆盖的卡通人脸图像
:param t1: 美术嘴巴的三角顶点
:param t2: 卡通人脸嘴巴的三角顶点
:return: 融合后的卡通人脸
'''
# Find bounding rectangle for each triangle
r1 = cv2.boundingRect(np.float32([t1]))
r2 = cv2.boundingRect(np.float32([t2]))
# Offset points by left top corner of the respective rectangles
t1Rect = []
t2Rect = []
t2RectInt = []
for i in range(0, 3):
t1Rect.append(((t1[i][0] - r1[0]), (t1[i][1] - r1[1])))
t2Rect.append(((t2[i][0] - r2[0]), (t2[i][1] - r2[1])))
t2RectInt.append(((t2[i][0] - r2[0]), (t2[i][1] - r2[1])))
# Get mask by filling triangle
mask = np.zeros((r2[3], r2[2], 3), dtype=np.float32)
cv2.fillConvexPoly(mask, np.int32(t2RectInt), (1.0, 1.0, 1.0), 16, 0)
# Apply warpImage to small rectangular patches
img1Rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
# img2Rect = np.zeros((r2[3], r2[2]), dtype = img1Rect.dtype)
size = (r2[2], r2[3])
img2Rect = applyAffineTransform(img1Rect, t1Rect, t2Rect, size)
img2Rect = img2Rect * mask
# Copy triangular region of the rectangular patch to the output image
img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] = img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] * (
(1.0, 1.0, 1.0) - mask)
img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] = img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] + img2Rect
def getMouthLandmarks(img_path):
'''
得到卡通人脸的嘴巴轮廓关键点txt文件
:param img_path: 人脸图像的路径
:return: 嘴巴关键点txt文件路径
'''
# image = face_recognition.load_image_file(img_path)
# face_landmarks_list = face_recognition.face_landmarks(image)
# pil_image = Image.fromarray(image)
# d = ImageDraw.Draw(pil_image)
#
# top_lip = face_landmarks_list[0]['top_lip']
# bottom_lip = face_landmarks_list[0]['bottom_lip']
#
# for tup in top_lip:
# bottom_lip.append(tup)
# 嘴巴关键点检测
global mouth_landmark
img = cv2.imread(img_path)
predictor_model = 'shape_predictor_68_face_landmarks.dat'
detector = dlib.get_frontal_face_detector() # dlib人脸检测器
predictor = dlib.shape_predictor(predictor_model)
# cv2读取图像
img = cv2.imread(img_path)
# 取灰度
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 人脸数rects(rectangles)
rects = detector(img_gray, 0)
(path, file) = os.path.split(img_path)
txt_path = path + str('/') + file[:-4] + '.txt'
# print(txt_path)
file_handle = open(txt_path, 'a')
for i in range(len(rects)):
landmarks = np.matrix([[p.x, p.y] for p in predictor(img, rects[i]).parts()])
for idx, point in enumerate(landmarks[49:68], 48):
# 68点的坐标
pos = (point[0, 0], point[0, 1])
print(idx + 1, pos)
pos_info = str(point[0, 0]) + ' ' + str(point[0, 1]) + '\n'
file_handle.write(pos_info)
# 利用cv2.circle给每个特征点画一个圈,共68个
cv2.circle(img, pos, 3, color=(0, 255, 0))
mouth_landmark = landmarks[49:68]
file_handle.close()
# 将得到的关键点位置信息按行写进txt文件中,并将文件名以图像名字命名
# 获取卡通人脸图片的filename
# if not os.path.exists(txt_path):
# with open(txt_path, mode='w', encoding='utf-8') as ff:
# for line in mouth_landmark:
# for a in line:
# a = str(a)
# ff.write(a)
# ff.write('\t')
# ff.write('\n')
cv2.imwrite(file[:-4] + str('_') + "draw.png", img, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])
return txt_path
def startSwap(img1_path, img2_path):
'''
生成置换后带有美术嘴巴的卡通人脸
:param img1_path: 形变对象 .png
:param img2_path: 待覆盖对象 .jpg
:return:
'''
# Read images
# 对美术嘴巴图片进行预处理
ori_img1 = cv2.imread(img1_path)
img1 = cv2.resize(ori_img1, (512, 512), interpolation=cv2.INTER_AREA)
path, file = os.path.split(img1_path)
# print(path) # /data/data_hao/PFLD-pytorch/woman_face
# print(file) # woman05.png
filename = file.split('.png')[0]
img1_crop_path = path + str('/') + filename + '.png'
cv2.imwrite(img1_crop_path, img1, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])
img2 = cv2.imread(img2_path)
img1Warped = np.copy(img2)
# get txt_file of corresponding points
txt_path1 = getMouthLandmarks(img1_crop_path)
# 如果美术人脸得到关键点有误,人工打标注得到嘴巴区域的关键点保存为txt文件
# txt_path2 = '/data/data_hao/PFLD-pytorch/woman_face/woman04.txt'
txt_path2 = getMouthLandmarks(img2_path)
# Read array of corresponding points
points1 = readPoints(txt_path1)
points2 = readPoints(txt_path2)
# Find convex hull
# 寻找嘴巴凸包(将边界点顺序连接成多边形)
hull1 = []
hull2 = []
# In Computer Vision and Math jargon, the boundary of a collection of points or shape is called a “hull”.
# A boundary that does not have any concavities is called a “Convex Hull”.
# The convex hull of a set of points can be calculated using OpenCV’s convexHull function.
hullIndex = cv2.convexHull(np.array(points2), returnPoints=False)
print(len(hullIndex))
for i in range(0, len(hullIndex)):
hull1.append(points1[int(hullIndex[i])])
hull2.append(points2[int(hullIndex[i])])
# Find delanauy traingulation for convex hull points
# 三角剖分,将嘴巴区域进行三角剖分,划分成多个微小区域
sizeImg2 = img2.shape
rect = (0, 0, sizeImg2[1], sizeImg2[0])
# do a Delaunay triangulation of the points on the convex hull
dt = calculateDelaunayTriangles(rect, hull2)
if len(dt) == 0:
quit()
# Apply affine transformation to Delaunay triangles
# The final steps of face alignment to to consider corresponding triangles between the source face
# and the target face, and affine warp the source face triangle onto the target face.
for i in range(0, len(dt)):
t1 = []
t2 = []
# get points for img1, img2 corresponding to the triangles
for j in range(0, 3):
t1.append(hull1[dt[i][j]])
t2.append(hull2[dt[i][j]])
# 仿射变化对齐
warpTriangle(img1, img1Warped, t1, t2)
# How to seamlessly combine the two images?
# Clone seamlessly
# Calculate Mask
hull8U = []
for i in range(0, len(hull2)):
hull8U.append((hull2[i][0], hull2[i][1]))
mask = np.zeros(img2.shape, dtype=img2.dtype)
cv2.fillConvexPoly(mask, np.int32(hull8U), (255, 255, 255))
r = cv2.boundingRect(np.float32([hull2]))
center = ((r[0] + int(r[2] / 2), r[1] + int(r[3] / 2)))
# Clone seamlessly.
output = cv2.seamlessClone(np.uint8(img1Warped), img2, mask, center, cv2.NORMAL_CLONE)
return output
if __name__ == '__main__':
# img1_path表示形变卡通人脸
# img2_path表示待覆盖卡通人脸
img1_path = '/data/data_hao/PFLD-pytorch/woman_face/woman04.png'
img2_path = '/data/data_hao/PFLD-pytorch/0000_007.jpg'
output = startSwap(img1_path, img2_path)
cv2.imwrite('swap_mouth_new.jpg', output, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])
# cv2.imshow("Face Swapped", output)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# # Make sure OpenCV is version 3.0 or above
# (major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')
#
# if int(major_ver) < 3 :
# print >>sys.stderr, 'ERROR: Script needs OpenCV 3.0 or higher'
# sys.exit(1)
# -*- coding: utf-8 -*-
'''
* @author [v_daweihao]
* @version [2021-08-09]
* <image size(1024, 512)-->(512, 512)>
'''
import cv2
import os
from PIL import Image
def split_img(img_dir, save_dir):
"""分离图片
Args:
img_dir:
save_dir:
"""
for img_file in os.listdir(img_dir):
img_path = os.path.join(img_dir, img_file)
img = cv2.imread(img_path)
size = img.shape
new_height = size[0]
new_width = size[1] // 2
split_img = img[0:new_height, 0:new_width]
split_img_path = os.path.join(save_dir, img_file)
cv2.imwrite(split_img_path, split_img)
if __name__ == '__main__':
# img_dir = r'D:\20210809\cartoon_noseg_0807\cartoon_noseg_0727\train'
# save_dir = r'D:\20210809\split_image\train'
# split_img(img_dir, save_dir)
# img_dir = r'D:\20210809\cartoon_noseg_0807\cartoon_noseg_0727\test'
# save_dir = r'D:\20210809\split_image\test'
# split_img(img_dir, save_dir)
#
# img_dir = r'D:\20210809\cartoon_noseg_0807\cartoon_noseg_0727\val'
# save_dir = r'D:\20210809\split_image\val'
# split_img(img_dir, save_dir)
img = cv2.imread(r'D:\20210809\split_image\train\MX2mzRjuQB.jpg')
crop_img = cv2.resize(img, (512, 512), interpolation=cv2.INTER_AREA)
cv2.imwrite('crop_asian.png', crop_img)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册