1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
"""
Crop images to prepare for training
"""
import click
# from PIL import Image, ImageOps, ImageFilter, ImageDraw
from app.settings import types
from app.utils import click_utils
from app.settings import app_cfg as cfg
@click.command()
@click.option('-i', '--input', 'opt_dir_in', required=True,
help='Input directory')
@click.option('-o', '--output', 'opt_fp_out', required=True,
help='Output CSV')
@click.option('-e', '--ext', 'opt_ext',
default='jpg', type=click.Choice(['jpg', 'png']),
help='File glob ext')
@click.option('--size', 'opt_size',
type=(int, int), default=(300, 300),
help='Output image size')
@click.option('-t', '--detector-type', 'opt_detector_type',
type=cfg.FaceDetectNetVar,
default=click_utils.get_default(types.FaceDetectNet.DLIB_CNN),
help=click_utils.show_help(types.FaceDetectNet))
@click.option('-g', '--gpu', 'opt_gpu', default=0,
help='GPU index')
@click.option('--conf', 'opt_conf_thresh', default=0.85, type=click.FloatRange(0,1),
help='Confidence minimum threshold')
@click.option('--pyramids', 'opt_pyramids', default=0, type=click.IntRange(0,4),
help='Number pyramids to upscale for DLIB detectors')
@click.option('--slice', 'opt_slice', type=(int, int), default=(None, None),
help='Slice list of files')
@click.option('--display/--no-display', 'opt_display', is_flag=True, default=False,
help='Display detections to debug')
@click.pass_context
def cli(ctx, opt_dir_in, opt_fp_out, opt_ext, opt_size, opt_detector_type,
opt_gpu, opt_conf_thresh, opt_pyramids, opt_slice, opt_display):
"""Extrace face"""
import sys
import os
from os.path import join
from pathlib import Path
from glob import glob
from tqdm import tqdm
import numpy as np
import dlib # must keep a local reference for dlib
import cv2 as cv
import pandas as pd
from app.utils import logger_utils, file_utils, im_utils
from app.processors import face_detector
# -------------------------------------------------
# init here
log = logger_utils.Logger.getLogger()
if opt_detector_type == types.FaceDetectNet.CVDNN:
detector = face_detector.DetectorCVDNN()
elif opt_detector_type == types.FaceDetectNet.DLIB_CNN:
detector = face_detector.DetectorDLIBCNN(opt_gpu)
elif opt_detector_type == types.FaceDetectNet.DLIB_HOG:
detector = face_detector.DetectorDLIBHOG()
elif opt_detector_type == types.FaceDetectNet.HAAR:
log.error('{} not yet implemented'.format(opt_detector_type.name))
return
# -------------------------------------------------
# process here
# get list of files to process
fp_ims = glob(join(opt_dir_in, '*.{}'.format(opt_ext)))
if opt_slice:
fp_ims = fp_ims[opt_slice[0]:opt_slice[1]]
log.debug('processing {:,} files'.format(len(fp_ims)))
data = []
for fp_im in tqdm(fp_ims):
im = cv.imread(fp_im)
bboxes = detector.detect(im, opt_size=opt_size, opt_pyramids=opt_pyramids)
fpp_im = Path(fp_im)
for bbox in bboxes:
roi = {
'fn': fpp_im.stem,
'ext': fpp_im.suffix,
'x': bbox.x,
'y': bbox.y,
'w': bbox.w,
'h': bbox.h}
dim = bbox.to_dim(im.shape[:2][::-1]) # w,h
data.append(roi)
# debug display
if opt_display and len(bboxes):
im_md = im_utils.resize(im, width=opt_size[0])
for bbox in bboxes:
dim = bbox.to_dim(im_md.shape[:2][::-1])
cv.rectangle(im_md, dim.pt_tl, dim.pt_br, (0,255,0), 3)
cv.imshow('', im_md)
while True:
k = cv.waitKey(1) & 0xFF
if k == 27 or k == ord('q'): # ESC
cv.destroyAllWindows()
sys.exit()
elif k != 255:
# any key to continue
break
# save date
df = pd.DataFrame.from_dict(data)
df.to_csv(opt_fp_out)
|