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]