Skip to content

Commit 207ec15

Browse files
authored
Merge pull request #366 from grycap/dev-srisco
OSCAR2 integration & mask-detector-workflow example
2 parents d486993 + d36cafd commit 207ec15

25 files changed

Lines changed: 1445 additions & 52 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
3+
VIDEO_NAME=`basename "$INPUT_FILE_PATH"`
4+
SUBFOLDER_NAME=`echo "$VIDEO_NAME" | cut -f 1 -d '.'`
5+
OUTPUT_SUBFOLDER="$TMP_OUTPUT_DIR/$SUBFOLDER_NAME"
6+
7+
mkdir "$OUTPUT_SUBFOLDER"
8+
9+
echo "SCRIPT: Analyzing file '$INPUT_FILE_PATH', saving the output images in '$OUTPUT_SUBFOLDER'"
10+
11+
ffmpeg -i "$INPUT_FILE_PATH" -vf fps=12/60 "$OUTPUT_SUBFOLDER/img%d.jpg"
12+
13+
for IMAGE in "$OUTPUT_SUBFOLDER"/*
14+
do
15+
python auto_blur_image.py -i "$IMAGE" -o "$IMAGE"
16+
done
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM python:slim-buster
2+
3+
RUN pip install --no-cache-dir opencv-python numpy tensorflow && \
4+
rm -rf /root/.cache/pip/* && \
5+
rm -rf /tmp/*
6+
7+
RUN apt update && \
8+
apt install -y --no-install-recommends ffmpeg && \
9+
apt-get clean && \
10+
rm -rf /var/lib/apt/lists/*
11+
12+
COPY . /opt/blurry-faces
13+
14+
WORKDIR /opt/blurry-faces/src
15+
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import tensorflow as tf
2+
import numpy as np
3+
import time
4+
5+
class DetectorAPI:
6+
def __init__(self, path_to_ckpt):
7+
self.path_to_ckpt = path_to_ckpt
8+
9+
self.detection_graph = tf.Graph()
10+
with self.detection_graph.as_default():
11+
od_graph_def = tf.compat.v1.GraphDef()
12+
with tf.io.gfile.GFile(self.path_to_ckpt, 'rb') as fid:
13+
serialized_graph = fid.read()
14+
od_graph_def.ParseFromString(serialized_graph)
15+
tf.import_graph_def(od_graph_def, name='')
16+
17+
self.default_graph = self.detection_graph.as_default()
18+
self.sess = tf.compat.v1.Session(graph=self.detection_graph)
19+
20+
# Definite input and output Tensors for detection_graph
21+
self.image_tensor = self.detection_graph.get_tensor_by_name(
22+
'image_tensor:0')
23+
# Each box represents a part of the image where a particular object was detected.
24+
self.detection_boxes = self.detection_graph.get_tensor_by_name(
25+
'detection_boxes:0')
26+
# Each score represent how level of confidence for each of the objects.
27+
# Score is shown on the result image, together with the class label.
28+
self.detection_scores = self.detection_graph.get_tensor_by_name(
29+
'detection_scores:0')
30+
self.detection_classes = self.detection_graph.get_tensor_by_name(
31+
'detection_classes:0')
32+
self.num_detections = self.detection_graph.get_tensor_by_name(
33+
'num_detections:0')
34+
35+
def processFrame(self, image):
36+
# Expand dimensions since the trained_model expects images to have shape: [1, None, None, 3]
37+
image_np_expanded = np.expand_dims(image, axis=0)
38+
# Actual detection.
39+
start_time = time.time()
40+
(boxes, scores, classes,
41+
num) = self.sess.run([
42+
self.detection_boxes, self.detection_scores,
43+
self.detection_classes, self.num_detections
44+
],
45+
feed_dict={self.image_tensor: image_np_expanded})
46+
end_time = time.time()
47+
48+
print("Elapsed Time:", end_time - start_time)
49+
50+
im_height, im_width, _ = image.shape
51+
boxes_list = [None for i in range(boxes.shape[1])]
52+
for i in range(boxes.shape[1]):
53+
boxes_list[i] = (int(boxes[0, i, 1] * im_width),
54+
int(boxes[0, i, 0] * im_height),
55+
int(boxes[0, i, 3] * im_width),
56+
int(boxes[0, i, 2] * im_height))
57+
58+
return boxes_list, scores[0].tolist(), [
59+
int(x) for x in classes[0].tolist()
60+
], int(num[0])
61+
62+
def close(self):
63+
self.sess.close()
64+
self.default_graph.close()
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# author: Asmaa Mirkhan ~ 2019
2+
3+
import os
4+
import argparse
5+
import cv2 as cv
6+
from DetectorAPI import DetectorAPI
7+
8+
def blurBoxes(image, boxes):
9+
"""
10+
Argument:
11+
image -- the image that will be edited as a matrix
12+
boxes -- list of boxes that will be blurred, each box must be int the format (x_top_left, y_top_left, x_bottom_right, y_bottom_right)
13+
14+
Returns:
15+
image -- the blurred image as a matrix
16+
"""
17+
18+
for box in boxes:
19+
# unpack each box
20+
x1, y1, x2, y2 = [d for d in box]
21+
22+
# crop the image due to the current box
23+
sub = image[y1:y2, x1:x2]
24+
25+
# apply GaussianBlur on cropped area
26+
blur = cv.blur(sub, (10, 10))
27+
28+
# paste blurred image on the original image
29+
image[y1:y2, x1:x2] = blur
30+
31+
return image
32+
33+
34+
def main(args):
35+
# assign model path and threshold
36+
model_path = args.model_path
37+
threshold = args.threshold
38+
39+
# create detection object
40+
odapi = DetectorAPI(path_to_ckpt=model_path)
41+
42+
# open image
43+
image = cv.imread(args.input_image)
44+
45+
# real face detection
46+
boxes, scores, classes, num = odapi.processFrame(image)
47+
48+
# filter boxes due to threshold
49+
# boxes are in (x_top_left, y_top_left, x_bottom_right, y_bottom_right) format
50+
boxes = [boxes[i] for i in range(0, num) if scores[i] > threshold]
51+
52+
# apply blurring
53+
image = blurBoxes(image, boxes)
54+
55+
# # show image
56+
# cv.imshow('blurred', image)
57+
58+
# if image will be saved then save it
59+
if args.output_image:
60+
cv.imwrite(args.output_image, image)
61+
print('Image has been saved successfully at', args.output_image,
62+
'path')
63+
else:
64+
cv.imshow('blurred', image)
65+
# when any key has been pressed then close window and stop the program
66+
cv.waitKey(0)
67+
cv.destroyAllWindows()
68+
69+
70+
if __name__ == "__main__":
71+
# creating argument parser
72+
parser = argparse.ArgumentParser(description='Image blurring parameters')
73+
74+
# adding arguments
75+
parser.add_argument('-i',
76+
'--input_image',
77+
help='Path to your image',
78+
type=str,
79+
required=True)
80+
parser.add_argument('-m',
81+
'--model_path',
82+
default='/opt/blurry-faces/face_model/face.pb',
83+
help='Path to .pb model',
84+
type=str)
85+
parser.add_argument('-o',
86+
'--output_image',
87+
help='Output file path',
88+
type=str)
89+
parser.add_argument('-t',
90+
'--threshold',
91+
help='Face detection confidence',
92+
default=0.7,
93+
type=float)
94+
args = parser.parse_args()
95+
print(args)
96+
# if input image path is invalid then stop
97+
assert os.path.isfile(args.input_image), 'Invalid input file'
98+
99+
# if output directory is invalid then stop
100+
if args.output_image:
101+
assert os.path.isdir(os.path.dirname(
102+
args.output_image)), 'No such directory'
103+
104+
main(args)
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# author: Asmaa Mirkhan ~ 2019
2+
3+
import os
4+
import argparse
5+
import cv2 as cv
6+
from DetectorAPI import DetectorAPI
7+
8+
def blurBoxes(image, boxes):
9+
"""
10+
Argument:
11+
image -- the image that will be edited as a matrix
12+
boxes -- list of boxes that will be blurred, each box must be int the format (x_top_left, y_top_left, x_bottom_right, y_bottom_right)
13+
14+
Returns:
15+
image -- the blurred image as a matrix
16+
"""
17+
18+
for box in boxes:
19+
# unpack each box
20+
x1, y1, x2, y2 = [d for d in box]
21+
22+
# crop the image due to the current box
23+
sub = image[y1:y2, x1:x2]
24+
25+
# apply GaussianBlur on cropped area
26+
blur = cv.blur(sub, (25, 25))
27+
28+
# paste blurred image on the original image
29+
image[y1:y2, x1:x2] = blur
30+
31+
return image
32+
33+
34+
def main(args):
35+
# assign model path and threshold
36+
model_path = args.model_path
37+
threshold = args.threshold
38+
39+
# create detection object
40+
odapi = DetectorAPI(path_to_ckpt=model_path)
41+
42+
# open video
43+
capture = cv.VideoCapture(args.input_video)
44+
45+
# video width = capture.get(3)
46+
# video height = capture.get(4)
47+
# video fps = capture.get(5)
48+
49+
if args.output_video:
50+
fourcc = cv.VideoWriter_fourcc(*'mp4v')
51+
output = cv.VideoWriter(args.output_video, fourcc,
52+
20.0, (int(capture.get(3)), int(capture.get(4))))
53+
54+
frame_counter = 0
55+
while True:
56+
# read frame by frame
57+
r, frame = capture.read()
58+
frame_counter += 1
59+
60+
# the end of the video?
61+
if frame is None:
62+
break
63+
64+
key = cv.waitKey(1)
65+
if key & 0xFF == ord('q'):
66+
break
67+
# real face detection
68+
boxes, scores, classes, num = odapi.processFrame(frame)
69+
70+
# filter boxes due to threshold
71+
# boxes are in (x_top_left, y_top_left, x_bottom_right, y_bottom_right) format
72+
boxes = [boxes[i] for i in range(0, num) if scores[i] > threshold]
73+
74+
# apply blurring
75+
frame = blurBoxes(frame, boxes)
76+
77+
# show image
78+
cv.imshow('blurred', frame)
79+
80+
# if image will be saved then save it
81+
if args.output_video:
82+
output.write(frame)
83+
print('Blurred video has been saved successfully at',
84+
args.output_video, 'path')
85+
86+
# when any key has been pressed then close window and stop the program
87+
88+
cv.destroyAllWindows()
89+
90+
91+
if __name__ == "__main__":
92+
# creating argument parser
93+
parser = argparse.ArgumentParser(description='Image blurring parameters')
94+
95+
# adding arguments
96+
parser.add_argument('-i',
97+
'--input_video',
98+
help='Path to your video',
99+
type=str,
100+
required=True)
101+
parser.add_argument('-m',
102+
'--model_path',
103+
help='Path to .pb model',
104+
type=str,
105+
required=True)
106+
parser.add_argument('-o',
107+
'--output_video',
108+
help='Output file path',
109+
type=str)
110+
parser.add_argument('-t',
111+
'--threshold',
112+
help='Face detection confidence',
113+
default=0.7,
114+
type=float)
115+
args = parser.parse_args()
116+
print(args)
117+
# if input image path is invalid then stop
118+
assert os.path.isfile(args.input_video), 'Invalid input file'
119+
120+
# if output directory is invalid then stop
121+
if args.output_video:
122+
assert os.path.isdir(os.path.dirname(
123+
args.output_video)), 'No such directory'
124+
125+
main(args)

0 commit comments

Comments
 (0)