環境要求
找個帶有基本cv配置的虛擬環境安裝上dlib依賴的人臉檢測的基礎環境即可,主要是:
pip install boost dlib opencv-python
缺的按提示安裝。
demo
設置好視頻路徑和圖像保存路徑,裁剪尺寸(默認256)以及裁剪幀數(默認64),可以直接運行:
import os
import random
import cv2
import dlib
from imutils.face_utils import FaceAligner, rect_to_bb
from tqdm import tqdm # 引入tqdm庫# 配置路徑
dataset_path = r'D:\python_project\face-parsing\dataset' # 原始數據集路徑
output_path = r'D:\python_project\face-parsing\dataset\results' # 輸出路徑
crop_size = 256 # 人臉裁剪后的大小# 獲取人臉對齊器
def get_face(fa, image):detector = dlib.get_frontal_face_detector() # 獲取人臉檢測器gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 將圖像轉換為灰度圖thresh = gray.shape[0] // 4 # 設置閾值rects = detector(gray, 2) # 檢測人臉face_aligned = None # 初始化返回的人臉圖像for rect in rects:(x, y, w, h) = rect_to_bb(rect) # 獲取人臉的坐標if w > thresh: # 如果人臉寬度大于閾值,則認為是有效人臉face_aligned = fa.align(image, gray, rect) # 對齊人臉break # 只處理第一張人臉return face_aligned# 處理視頻
def process_video(video_path, save_dir, fa):cap = cv2.VideoCapture(video_path) # 打開視頻文件total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 獲取總幀數if total_frames < 64: # 如果視頻幀數少于64,跳過該視頻print(f"Warning: Video '{video_path}' has less than 64 frames. Skipping.")cap.release() # 釋放視頻文件returnstart_frame = random.randint(0, total_frames - 64) # 隨機選擇起始幀frames = []for i in range(start_frame, start_frame + 64): # 提取連續的64幀cap.set(cv2.CAP_PROP_POS_FRAMES, i) # 設置當前讀取的幀數ret, frame = cap.read() # 讀取該幀if ret:frames.append(frame) # 保存讀取到的幀cap.release() # 釋放視頻文件for i, frame in enumerate(tqdm(frames, desc=f"Processing frames from {os.path.basename(video_path)}")): # 加入進度條face_aligned = get_face(fa, frame) # 對齊每一幀中的人臉if face_aligned is not None:img_name = f"{i + 1:05d}.jpg" # 給每一幀命名save_path = os.path.join(save_dir, img_name) # 保存路徑cv2.imwrite(save_path, face_aligned) # 保存圖像else:print(f"Face not found in frame {i + 1}") # 如果沒有檢測到人臉# 主函數:處理數據集中的所有視頻
def align_dlib():predictor = dlib.shape_predictor(r"../weights/shape_predictor_68_face_landmarks.dat") # 加載預測器fa = FaceAligner(predictor, desiredFaceWidth=crop_size) # 初始化人臉對齊器# 遍歷主目錄(Training、Development、Testing)main_dirs = ['Testing']for main_dir in main_dirs:main_dir_path = os.path.join(dataset_path, main_dir)if not os.path.isdir(main_dir_path):print(f"Skipping non-directory: {main_dir_path}")continue# 遍歷每個子目錄(Northwind、Freeform 等)sub_dirs = os.listdir(main_dir_path)# for sub_dir in sub_dirs:# sub_dir_path = os.path.join(main_dir_path, sub_dir)# if not os.path.isdir(sub_dir_path):# print(f"Skipping non-directory: {sub_dir_path}")# continue# 遍歷視頻文件夾中的每個視頻文件video_files = os.listdir(main_dir_path)for video_file in video_files:video_path = os.path.join(main_dir_path, video_file)if not os.path.isfile(video_path):continue# 獲取視頻名稱(去掉文件擴展名)video_name = os.path.splitext(video_file)[0]# 構建保存路徑: datasets/avec14/Training/Northwind/236_1_Northwind_videosave_path = os.path.join(output_path, main_dir, video_name)os.makedirs(save_path, exist_ok=True) # 創建保存文件夾print(f"Processing video: {video_path}")process_video(video_path, save_path, fa) # 處理該視頻if __name__ == "__main__":align_dlib() # 調用主函數進行處理
debug
eyesCenter在cv2.getRotationMatrix2D中一些版本要求是傳入float型,直接傳整型可能報錯:
Traceback (most recent call last):
File “D:\python_project\face-parsing\utils\face_dect.py”, line 99, in
align_dlib() # 調用主函數進行處理
File “D:\python_project\face-parsing\utils\face_dect.py”, line 95, in align_dlib
process_video(video_path, save_path, fa) # 處理該視頻
File “D:\python_project\face-parsing\utils\face_dect.py”, line 49, in process_video
face_aligned = get_face(fa, frame) # 對齊每一幀中的人臉
File “D:\python_project\face-parsing\utils\face_dect.py”, line 24, in get_face
face_aligned = fa.align(image, gray, rect) # 對齊人臉
File “C:\Users\Fine\anaconda3\envs\torch2\lib\site-packages\imutils\face_utils\facealigner.py”, line 68, in align
M = cv2.getRotationMatrix2D(eyesCenter, float(angle), float(scale))
TypeError: Can’t parse ‘center’. Sequence item with index 0 has a wrong type
將人臉對齊腳本中的eyesCenter類型轉換為float即可:
# eyesCenter = ((leftEyeCenter[0] + rightEyeCenter[0]) // 2,# (leftEyeCenter[1] + rightEyeCenter[1]) // 2)eyesCenter = ((leftEyeCenter[0] + rightEyeCenter[0]) / 2.0,(leftEyeCenter[1] + rightEyeCenter[1]) / 2.0)# grab the rotation matrix for rotating and scaling the faceM = cv2.getRotationMatrix2D(eyesCenter, float(angle), float(scale))
參考:
LinlyZhai-對AVEC2014視頻進行Dlib或MTCNN人臉裁剪