Download clean/video/dfd_fcg/src/preprocess/fetch_landmark_bbox.py from deepsafe/model-code: direct link, hf CLI and curl.
- Browser
- Download file 5.14 kB
-
https://huggingface.co/deepsafe/model-code/resolve/main/clean/video/dfd_fcg/src/preprocess/fetch_landmark_bbox.py
- Command line
-
hf download hf://deepsafe/model-code/clean/video/dfd_fcg/src/preprocess/fetch_landmark_bbox.py
-
curl -L -o fetch_landmark_bbox.py https://huggingface.co/deepsafe/model-code/resolve/main/clean/video/dfd_fcg/src/preprocess/fetch_landmark_bbox.py
5.14 kB
| import os | |
| import cv2 | |
| import math | |
| import torch | |
| import pickle | |
| import argparse | |
| import numpy as np | |
| from tqdm import tqdm | |
| from glob import glob | |
| import face_alignment | |
| def load_args(args): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--root-dir", type=str, default="") | |
| parser.add_argument("--video-dir", type=str, default="videos") | |
| parser.add_argument("--fdata-dir", type=str, default="frame_data") | |
| parser.add_argument("--glob-exp", type=str, default="*/*") | |
| parser.add_argument("--split-num", type=int, default=1) | |
| parser.add_argument("--part-num", type=int, default=1) | |
| parser.add_argument("--batch", type=int, default=1) | |
| parser.add_argument("--max-res", type=int, default=800) | |
| args = parser.parse_args(args) | |
| assert args.part_num > 0 and args.split_num > 0, "split and part value should be > 0" | |
| args.part_num = args.part_num - 1 | |
| return args | |
| def landmark_extract(fn, org_path, batch_size, max_res): | |
| cap_org = cv2.VideoCapture(org_path) | |
| try: | |
| width = cap_org.get(cv2.CAP_PROP_FRAME_WIDTH) | |
| height = cap_org.get(cv2.CAP_PROP_FRAME_HEIGHT) | |
| frames = [] | |
| # determine the scaling factor to shrink the size of input image(for efficiency). | |
| if (max(height, width) > max_res): | |
| scale = max_res / max(height, width) | |
| else: | |
| scale = 1 | |
| while (1): | |
| ret_org, frame_org = cap_org.read() | |
| if (not ret_org): | |
| break | |
| frame_org = cv2.cvtColor(frame_org, cv2.COLOR_BGR2RGB) | |
| frame_org = cv2.resize(frame_org, None, fx=scale, fy=scale) | |
| frames.append(frame_org) | |
| frame_count = len(frames) | |
| frame_faces = [None for _ in range(frame_count)] | |
| batch_indices = [] | |
| batch_frames = [] | |
| for cnt_frame in range(frame_count): | |
| batch_frames.append(frames[cnt_frame]) | |
| batch_indices.append(cnt_frame) | |
| if (len(batch_frames) == batch_size or (cnt_frame == (frame_count - 1) and len(batch_frames) > 0)): | |
| results = fn(torch.tensor(np.stack(batch_frames).transpose((0, 3, 1, 2)))) | |
| batch_size = len(results[0]) | |
| batch_landmarks = results[0] | |
| batch_bboxes = results[2] | |
| for index, frame_landmarks, frame_bboxes in zip(batch_indices, batch_landmarks, batch_bboxes): | |
| if (len(frame_landmarks) > 0): | |
| frame_landmarks = frame_landmarks.reshape(-1, 68, 2) / scale | |
| frame_landmarks = [lm for lm in frame_landmarks] | |
| frame_bboxes = [bbox[:-1] / scale for bbox in frame_bboxes] | |
| frame_faces[index] = { | |
| "landmarks": frame_landmarks, | |
| "bboxes": frame_bboxes | |
| } | |
| batch_frames.clear() | |
| batch_indices.clear() | |
| return frame_faces | |
| except Exception as e: | |
| raise e | |
| finally: | |
| cap_org.release() | |
| def main(args=None): | |
| # This file extract video landmarks from a given folder. | |
| # In addition, the landmarks are tracked with landmarks from previous frames. | |
| # By doing so, we expect to extract the most consistently appeared faces from a given video. | |
| # Note that under 'pack' save mode, the extracted faces must match the length of the video. | |
| # That's to say, if there exists a single frame without appearing faces in the video, the extract operation fails. | |
| args = load_args(args=args) | |
| model = face_alignment.FaceAlignment( | |
| face_alignment.LandmarksType.TWO_D, | |
| face_detector='sfd', | |
| dtype=torch.float16, # float16 to boost efficiency. | |
| flip_input=False, | |
| device="cuda", | |
| ) | |
| def driver(x): return model.get_landmarks_from_batch(x, return_bboxes=True) | |
| if (not args.root_dir[-1] == "/"): | |
| args.root_dir += "/" | |
| video_files = sorted(glob(os.path.join(args.root_dir, args.video_dir, args.glob_exp))) | |
| _, video_ext = os.path.splitext(video_files[0]) | |
| # splitting | |
| split_size = math.ceil(len(video_files) / args.split_num) | |
| video_files = video_files[args.part_num * split_size:(args.part_num + 1) * split_size] | |
| n_videos = len(video_files) | |
| print("{} videos in {}".format(n_videos, args.root_dir)) | |
| print("path sample:{}".format(video_files[0])) | |
| cont = input(f"Processing Part {args.part_num+1}/{args.split_num}, Confirm?(y/n)") | |
| if (not cont.lower() == "y"): | |
| print("abort.") | |
| return | |
| for i in tqdm(range(n_videos)): | |
| lm_path = video_files[i].replace(args.video_dir, args.fdata_dir).replace(video_ext, '.pickle') | |
| if (os.path.exists(lm_path)): | |
| continue | |
| datas = landmark_extract( | |
| fn=driver, | |
| org_path=video_files[i], | |
| batch_size=args.batch, | |
| max_res=args.max_res | |
| ) | |
| os.makedirs(os.path.split(lm_path)[0], exist_ok=True) | |
| with open(lm_path, "wb") as f: | |
| pickle.dump(datas, f) | |
| if __name__ == '__main__': | |
| main() | |