Files
2024-11-12 16:25:52 +08:00

241 lines
9.8 KiB
Python

import os
import torch.nn.functional as F
os.environ["KMP_DUPLICATE_LIB_OK"] = "true"
current_dir = os.path.dirname(os.path.abspath(__file__))
import cv2
import numpy as np
import kaldi_native_fbank as knf
from scipy.io import wavfile
import torch
import os
from talkingface.mediapipe_utils import detect_face_mesh
from train.data.dataset_faceReenactment3 import crop_,get_image,adjust_verts,get_standard_image
device = "cuda" if torch.cuda.is_available() else "cpu"
FaceModel = None
Audio2FeatureModel = None
PcaModel = None
def generate_bg_mask(out_size):
bg_mask = cv2.imread(current_dir + "/../obj_utils/bg_mask.png")
bg_mask[np.where(bg_mask < 128)] = 0
bg_mask = cv2.resize(bg_mask, (out_size, out_size))
bg_mask = (bg_mask > 0).astype(int)
bg_mask = np.concatenate([bg_mask[:, :, 0:1], bg_mask[:, :, 0:1], bg_mask[:, :, 0:1], bg_mask[:, :, 0:1]], axis=2)
return bg_mask
def rotate(image, angle, trans, center=None, scale=1.0):
# grab the dimensions of the image
(h, w) = image.shape[:2]
# if the center is None, initialize it as the center of
# the image
if center is None:
# center = (w // 2, h // 2)
center = (w // 2, 1.3*h)
# perform the rotation
M = cv2.getRotationMatrix2D(center, angle, scale)
M[:, 2] += trans
rotated = cv2.warpAffine(image, M, (w, h))
# return the rotated image
return rotated
from math import cos,sin,radians
def eularAngle2Matrix(tmp): #tmp为xyz的旋转角,角度值
tmp = [radians(i) for i in tmp]
matX = np.array([[1.0, 0, 0],
[0.0, cos(tmp[0]), -sin(tmp[0])],
[0.0, sin(tmp[0]), cos(tmp[0])]])
matY = np.array([[cos(tmp[1]), 0, sin(tmp[1])],
[0.0, 1, 0],
[-sin(tmp[1]), 0, cos(tmp[1])]])
matZ = np.array([[cos(tmp[2]), -sin(tmp[2]), 0],
[sin(tmp[2]), cos(tmp[2]), 0],
[0, 0, 1]])
matRotate = np.matmul(matZ, matY)
matRotate = np.matmul(matRotate, matX)
return matRotate
def face_interface(tensor_source_img, tensor_source_prompt, tensor_drving_img,
tensor_driving_img_face, tensor_drving_prompt, tensor_bg_mask, model_size):
global FaceModel
if FaceModel is None:
from models.FreeFace import FreeFace as FreeFaceModel
FaceModel = FreeFaceModel(8, 8, model_size, is_train=False).to(device) #
# current_dir = os.path.dirname(os.path.abspath(__file__))
inference_model_path = os.path.join(os.environ['minimates_models_dir'] , "FreeFace/epoch_40.pth")
state_dict = torch.load(inference_model_path)['state_dict']['net_g']
FaceModel.load_state_dict(state_dict)
FaceModel.eval()
in0 = F.interpolate(tensor_source_img, size=(model_size, model_size), mode='nearest')
in1 = F.interpolate(tensor_source_prompt, size=(model_size, model_size), mode='nearest')
in2 = F.interpolate(tensor_drving_img, size=(model_size, model_size), mode='nearest')
in3 = F.interpolate(tensor_driving_img_face, size=(model_size, model_size), mode='nearest')
in4 = F.interpolate(tensor_drving_prompt, size=(model_size, model_size), mode='nearest')
in5 = F.interpolate(tensor_bg_mask, size=(model_size, model_size), mode='nearest')
fake_out = FaceModel(in0, in1, in2, in3, in4, in5)
return fake_out
def face_process(img_path, out_size):
img_primer_rgba = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
assert img_primer_rgba.shape[2] == 4
source_pts = detect_face_mesh([img_primer_rgba[:, :, :3]])[0]
source_pts[:, 2] = source_pts[:, 2] - np.max(source_pts[:, 2])
img_primer_rgba = cv2.cvtColor(img_primer_rgba, cv2.COLOR_BGRA2RGBA)
(h, w) = img_primer_rgba.shape[:2]
source_crop_rect = crop_(source_pts[np.newaxis, :, :], w, h)
# source_img = get_image(img_primer_rgba, source_crop_coords, input_type='img', resize=out_size)
# source_crop_pts = get_image(source_pts, source_crop_coords, input_type='mediapipe', resize=out_size)
source_img, source_crop_pts = get_standard_image(img_primer_rgba, source_pts, source_crop_rect, resize=out_size)
source_crop_pts = adjust_verts(source_crop_pts)
source_crop_pts_vt = source_crop_pts.copy()
source_crop_pts_vt = source_crop_pts_vt[:,:2]/ out_size
return img_primer_rgba, source_img, source_crop_pts, source_crop_pts_vt,source_crop_rect
def rgb_face_process(img_primer_bgr, out_size):
source_pts = detect_face_mesh([img_primer_bgr[:, :, :3]])[0]
source_pts[:, 2] = source_pts[:, 2] - np.max(source_pts[:, 2])
img_primer_rgb = cv2.cvtColor(img_primer_bgr, cv2.COLOR_BGR2RGB)
(h, w) = img_primer_rgb.shape[:2]
source_crop_coords = crop_(source_pts[np.newaxis, :, :], w, h)
source_img, source_crop_pts = get_standard_image(img_primer_rgb, source_pts, source_crop_coords, resize=out_size)
source_crop_pts = adjust_verts(source_crop_pts)
return source_img, source_crop_pts
# def rgb_face_rotation_process(img_primer_bgr, out_size):
# source_pts = detect_face_mesh([img_primer_bgr[:, :, :3]])[0]
# source_pts[:, 2] = source_pts[:, 2] - np.max(source_pts[:, 2])
# img_primer_rgb = cv2.cvtColor(img_primer_bgr, cv2.COLOR_BGR2RGB)
# (h, w) = img_primer_rgb.shape[:2]
# source_crop_coords = crop_(source_pts[np.newaxis, :, :], w, h)
# source_img, source_crop_pts = get_standard_image(img_primer_rgb, source_pts, source_crop_coords, resize=out_size)
# source_crop_pts = adjust_verts(source_crop_pts)
#
# mat_list, _, face_pts_mean_personal_primer = calc_face_mat(pts_driven, face_pts_mean)
# return source_img, source_crop_pts
# 读取音频文件
def load_audio(file_path):
import librosa
import numpy as np
# 使用 librosa 读取音频文件
# sr=None 表示不改变原始采样率,mono=True 表示转换为单声道
y, sr = librosa.load(file_path, sr=None, mono=True)
# 将采样率转换为 16kHz
y_16k = librosa.resample(y, orig_sr=sr, target_sr=16000)
# 确保数据类型为 float32
y_16k = y_16k.astype(np.float32)
return y_16k
def audio_interface(audio_path):
global Audio2FeatureModel,PcaModel
if Audio2FeatureModel is None:
# current_dir = os.path.dirname(os.path.abspath(__file__))
ckpt_path = os.path.join(os.environ['minimates_models_dir'] , "lstm/lstm_model_epoch_590.pth")
# ckpt_path = r"F:\C\AI\CV\DH_few_shot\DH029_wav2lip_mediapipe\checkpoint\lstm\lstm_model_epoch_590.pth"
from talkingface.models.audio2bs_lstm import Audio2Feature
Audio2FeatureModel = Audio2Feature() # 调用模型Model
Audio2FeatureModel.load_state_dict(torch.load(ckpt_path))
Audio2FeatureModel = Audio2FeatureModel.to(device)
Audio2FeatureModel.eval()
# rate, wav = wavfile.read(wavpath, mmap=False)
#
# augmented_samples = wav
# augmented_samples2 = augmented_samples.astype(np.float32, order='C') / 32768.0
augmented_samples2 = load_audio(audio_path)
opts = knf.FbankOptions()
opts.frame_opts.dither = 0
opts.frame_opts.frame_length_ms = 50
opts.frame_opts.frame_shift_ms = 20
opts.mel_opts.num_bins = 80
opts.frame_opts.snip_edges = False
opts.mel_opts.debug_mel = False
fbank = knf.OnlineFbank(opts)
fbank.accept_waveform(16000, augmented_samples2.tolist())
seq_len = fbank.num_frames_ready // 2
A2Lsamples = np.zeros([2 * seq_len, 80])
for i in range(2 * seq_len):
# print(i)
f2 = fbank.get_frame(i)
A2Lsamples[i] = f2
orig_mel = A2Lsamples
input = torch.from_numpy(orig_mel).unsqueeze(0).float().to(device)
h0 = torch.zeros(2, 1, 192).to(device)
c0 = torch.zeros(2, 1, 192).to(device)
bs_array, hn, cn = Audio2FeatureModel(input, h0, c0)
# print(bs_array.shape)
bs_array = bs_array[0, 4:].detach().cpu().float().numpy()
if PcaModel is None:
ckpt_path = os.path.join(os.environ['minimates_models_dir'], "pca_mediapipe.pkl")
import pickle
with open(ckpt_path, "rb") as f:
PcaModel = pickle.load(f)
frame_num = len(bs_array)
output = np.zeros([frame_num, 478, 3])
for frame_index in range(frame_num):
# pts = np.dot(bs_array[frame_index, :6], PcaModel.components_[:6]) + PcaModel.mean_
pts = np.dot(bs_array[frame_index, :6], PcaModel.components_[:6]) * 0.7
# print(frame_index, pts.shape)
pts = pts.reshape(-1, 3)
pts[:, 0] *= 0.7
output[frame_index] = pts
# point_size = 1
# point_color = (0, 0, 255) # BGR
# thickness = 4 # 0 、4、8
#
# img = np.zeros([1000, 1000, 3])
# cv2.line(img, (0, 780), (1000, 780), point_color, 1)
# for coor in pts:
# # coor = (coor +1 )/2.
# cv2.circle(img, (int(coor[0]), int(coor[1])), point_size, point_color, thickness)
# cv2.imshow("a", img)
# cv2.waitKey(40)
return output
import math
def rotation_matrix_to_euler_angles(R):
# 检查矩阵是否为3x3
assert R.shape == (3, 3), "Rotation matrix must be 3x3"
U, S, Vt = np.linalg.svd(R)
# 2. 构造正交矩阵 W
W = U @ Vt
# 3. 调整行列式
det_W = np.linalg.det(W)
if det_W < 0:
# 交换最后一列
W[:, -1] *= -1
# print(det_W, S)
#
# print(R, U @ Vt*np.mean(S))
R = W
# 计算欧拉角
sy = math.sqrt(R[2, 1] ** 2 + R[2, 2] ** 2)
singular = sy < 1e-6 # 当sy接近0时,可能会出现除零错误
if not singular:
x = np.arctan2(R[2, 1], R[2, 2])
y = np.arctan2(-R[2, 0], sy)
z = np.arctan2(R[1, 0], R[0, 0])
else:
x = np.arctan2(-R[1, 2], R[1, 1])
y = np.arctan2(-R[2, 0], sy)
z = 0
# 将弧度转换为角度
x = math.degrees(x)
y = math.degrees(y)
z = math.degrees(z)
# print([x, y, z])
# exit()
return [x, y, z]