model-code / clean /video /mintime /preprocessing /extract_crops.py
deepsafe's picture
Add stripped inference-only model code mirror
9e14838 verified
Raw History Blame Contribute Delete
5.44 kB
# Following face detection, the json files containing the coordinates framing the faces identified by the MTCNN must be converted into images.
import argparse
import json
import os
from os import cpu_count
from pathlib import Path
from collections import OrderedDict
import pandas as pd
os.environ["MKL_NUM_THREADS"] = "1"
os.environ["NUMEXPR_NUM_THREADS"] = "1"
os.environ["OMP_NUM_THREADS"] = "1"
from functools import partial
from glob import glob
from multiprocessing.pool import Pool
import cv2
cv2.ocl.setUseOpenCL(False)
cv2.setNumThreads(0)
from tqdm import tqdm
def extract_video(video, data_path):
# Composes the path where the coordinates of the detected faces were saved
bboxes_path = data_path + "/boxes_better/" + video.split("video/")[-1].split(".")[0] + ".json"
if not os.path.exists(bboxes_path) or not os.path.exists(video):
print(bboxes_path, "not found\n")
return
# Load the json dictionary and the corresponding video
with open(bboxes_path, "r") as bbox_f:
bboxes_dict = json.load(bbox_f)
capture = cv2.VideoCapture(video)
frames_num = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
fps = int(capture.get(5))
# For each frame, save the detected faces into files
frames = []
for i in range(frames_num):
capture.grab()
success, frame = capture.retrieve()
if not success:
continue
frames.append(frame)
explored_indexes = []
for i in range(0, len(frames), fps):
while str(i) not in bboxes_dict:
if i == frames_num - 1:
i -= 1
if i in explored_indexes:
break
else:
explored_indexes.append(i)
frame = frames[i]
id = os.path.splitext(os.path.basename(video))[0]
crops = []
index = i
limit = i + fps - 1
keys = [int(x) for x in list(bboxes_dict.keys())]
while index < limit:
index += 1
if index in keys and bboxes_dict[str(index)] is not None:
break
if index == limit:
continue
bboxes = bboxes_dict[str(index)]
for bbox in bboxes:
xmin, ymin, xmax, ymax = [int(b * 2) for b in bbox]
w = xmax - xmin
h = ymax - ymin
# Add some padding to catch background too
p_h = h // 3
p_w = w // 3
crop_h = (ymax + p_h) - max(ymin - p_h, 0)
crop_w = (xmax + p_w) - max(xmin - p_w, 0)
# Make the image square
if crop_h > crop_w:
p_h -= int(((crop_h - crop_w)/2))
else:
p_w -= int(((crop_w - crop_h)/2))
# Extract the face from the frame
crop = frame[max(ymin - p_h, 0):ymax + p_h, max(xmin - p_w, 0):xmax + p_w]
# Check if out of bound and correct
h, w = crop.shape[:2]
if h > w:
diff = int((h - w)/2)
if diff > 0:
crop = crop[diff:-diff,:]
else:
crop = crop[1:,:]
elif h < w:
diff = int((w - h)/2)
if diff > 0:
crop = crop[:,diff:-diff]
else:
crop = crop[:,:-1]
# Add the extracted face to the list
crops.append(crop)
# Save the extracted faces into files
tmp = video.split("release")[1]
out_dir = opt.output_path + tmp
os.makedirs(out_dir, exist_ok=True)
for j, crop in enumerate(crops):
try:
cv2.imwrite(os.path.join(out_dir, "{}_{}.png".format(i, j)), crop)
except:
print("Error writing image")
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--list_file', default="../../datasets/ForgeryNet/Training/video_list.txt", type=str,
help='Images List txt file path)')
parser.add_argument('--data_path', default='../../datasets/ForgeryNet/Training', type=str,
help='Videos directory')
parser.add_argument('--output_path', default='../../datasets/ForgeryNet/Training/faces_fix/crops_fix', type=str,
help='Output directory')
parser.add_argument('--gpu_id', default=0, type=int,
help='ID of GPU to be used')
parser.add_argument('--workers', default=40, type=int,
help='Number of data loader workers.')
opt = parser.parse_args()
print(opt)
# Read the dataset
with open(opt.list_file, 'r') as temp_f:
col_count = [ len(l.split(" ")) for l in temp_f.readlines() ]
column_names = [i for i in range(0, max(col_count))]
os.makedirs(opt.output_path, exist_ok=True)
df = pd.read_csv(opt.list_file, sep=' ', names=column_names)
videos_paths = df.values.tolist()
videos_paths = list(dict.fromkeys([os.path.join(opt.data_path, "video", os.path.dirname(row[1].split(" ")[0]), "video.mp4") for row in videos_paths]))
# Start face extraction
with Pool(processes=opt.workers) as p:
with tqdm(total=len(videos_paths)) as pbar:
for v in p.imap_unordered(partial(extract_video, data_path=opt.data_path), videos_paths):
pbar.update()