Compare commits

..

No commits in common. "a7ea09fb5282f4f784c8c6a72ea247b50289047a" and "e7ff1ac0cb5e36b9914714a8b4c0feb4e80976e4" have entirely different histories.

5 changed files with 98 additions and 126 deletions

1
.gitignore vendored
View file

@ -1,3 +1,2 @@
venv/ venv/
*.pyc *.pyc
saves/

View file

@ -5,26 +5,16 @@ import logging
import argparse import argparse
import numpy as np import numpy as np
import time import time
import datetime
from PIL import ImageFont, ImageDraw, Image from PIL import ImageFont, ImageDraw, Image
import os import os
draw_colors = { draw_colors = {
'hog': (198,65,124), 'hog': (255,0,0),
'haar': (255,255,255), 'haar': (0,255,0),
'dnn': (251,212,36), 'dnn': (0,0,255),
} }
titles = { font = ImageFont.truetype("/home/ruben/Documents/Projecten/2018/PATH/presentation/lib/font/source-sans-pro/source-sans-pro-regular.ttf", 30)
'hog' : "Histogram of oriented gradients",
'haar' : "Haar cascades",
'dnn' : "Neural network",
}
fontfile = "SourceSansPro-Regular.ttf"
font = ImageFont.truetype(fontfile, 30)
font_s = ImageFont.truetype(fontfile, 20)
class Result(): class Result():
def __init__(self, algorithm, image, confidence_threshold = 0.5): def __init__(self, algorithm, image, confidence_threshold = 0.5):
@ -43,27 +33,18 @@ class Result():
}) })
return self return self
def draw_detections(self, include_title = False): def draw_detections(self):
color = draw_colors[self.algorithm]
cv2_im_rgb = cv2.cvtColor(self.visualisation,cv2.COLOR_BGR2RGB) cv2_im_rgb = cv2.cvtColor(self.visualisation,cv2.COLOR_BGR2RGB)
# Pass the image to PIL # Pass the image to PIL
pil_im = Image.fromarray(cv2_im_rgb) pil_im = Image.fromarray(cv2_im_rgb)
draw = ImageDraw.Draw(pil_im, 'RGBA') draw = ImageDraw.Draw(pil_im, 'RGBA')
self.draw_detections_on(draw)
if include_title:
draw.text((10,10), titles[self.algorithm], fill=draw_colors[self.algorithm], font=font)
return cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
def draw_detections_on(self, draw: ImageDraw):
'''
Draw on a specified canvas
'''
color = draw_colors[self.algorithm]
for detection in self.detections: for detection in self.detections:
self.draw_detection(draw, detection, color) self.draw_detection(draw, detection, color)
self.visualisation = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
def draw_detection(self, draw: ImageDraw, detection: dict, color: tuple): def draw_detection(self, draw: ImageDraw, detection: dict, color: tuple):
width = 2 width = 2
@ -87,8 +68,51 @@ class Result():
color = tuple(color) color = tuple(color)
draw.rectangle((detection['startX'], detection['startY'], detection['endX'], detection['endY']), outline=color, width=width) draw.rectangle((detection['startX'], detection['startY'], detection['endX'], detection['endY']), outline=color, width=width)
# cv2.rectangle(rect_img, (0, 0),
# (sub_img.shape[1]-int(width/2), sub_img.shape[0]-int(width/2)),
# color, width)
def draw_detections_cv2(self):
color = draw_colors[self.algorithm]
for detection in self.detections:
self.draw_detection(detection, color)
def draw_detection_cv2(self, detection, color=(0,0,255)):
# First we crop the sub-rect from the image
sub_img = self.visualisation[detection['startY']:detection['endY'], detection['startX']:detection['endX']]
rect_img = sub_img.copy()
width = 2
cv2.rectangle(rect_img, (0, 0),
(sub_img.shape[1]-int(width/2), sub_img.shape[0]-int(width/2)),
color, width)
# white_rect = np.ones(sub_img.shape, dtype=np.uint8) * 255
# filter out weak detections by ensuring the `confidence` is
# greater than the minimum confidence
if detection['confidence'] > self.confidence_threshold:
# draw the bounding box of the face along with the associated
# probability
text = "{:.2f}%".format(detection['confidence'] * 100)
y = detection['startY'] - 10 if detection['startY'] - 10 > 10 else detection['startY'] + 10
# cv2.rectangle(image, (startX, startY), (endX, endY),
# color, 2)
cv2.putText(self.visualisation, text, (detection['startX'], y),
cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2, lineType = cv2.LINE_AA)
alpha = 1
else:
# At least 10% opacity
alpha = max(.3, detection['confidence'])
res = cv2.addWeighted(sub_img, 1-alpha, rect_img, alpha, 1.0)
# Putting the image back to its position
self.visualisation[detection['startY']:detection['endY'], detection['startX']:detection['endX']] = res
def resize(self, width, height): def resize(self, width, height):
# TODO resize to new target incl all detections # TODO resize to new target incl all detections
img = self.visualisation img = self.visualisation
@ -107,9 +131,6 @@ class Result():
) )
return result return result
def count_detections(self):
detections = [d for d in self.detections if d['confidence'] > self.confidence_threshold]
return len(detections)
def record(device_id, q1,q2, q3, q4, resolution, rotate): def record(device_id, q1,q2, q3, q4, resolution, rotate):
@ -340,17 +361,7 @@ def process3_haar(in_q, out_q, cascade_file):
""") """)
dir_path = os.path.dirname(os.path.realpath(__file__)) dir_path = os.path.dirname(os.path.realpath(__file__))
C = ffi.dlopen(os.path.join(dir_path,"../visualhaar/target/debug/libvisual_haarcascades_lib.so"))
lib_path = os.path.join(dir_path, "..", "visualhaar", "target", "debug")
so_path = os.path.join(lib_path, "libvisual_haarcascades_lib.so")
dll_path = os.path.join(lib_path, "visual_haarcascades_lib.dll")
if os.path.exists(so_path):
C = ffi.dlopen(so_path)
elif os.path.exists(dll_path):
C = ffi.dlopen(dll_path)
else:
raise RuntimeException("Visual haarcascades library is not found")
# print(C.test(9)) # print(C.test(9))
# i = Image.open("Marjo.jpg") # i = Image.open("Marjo.jpg")
@ -426,33 +437,11 @@ def process3_haar(in_q, out_q, cascade_file):
# print(img) # print(img)
out_q.put(result) out_q.put(result)
def draw_stats(image, results): def display(image_res, q1, q2, q3, q4, fullscreen = False):
pil_im = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) prev_image1 = np.zeros((image_res[1],image_res[0],3), np.uint8)
draw = ImageDraw.Draw(pil_im, 'RGBA') prev_image2 = np.zeros((image_res[1],image_res[0],3), np.uint8)
prev_image3 = np.zeros((image_res[1],image_res[0],3), np.uint8)
for i, result in enumerate(results): prev_image4 = np.zeros((image_res[1],image_res[0],3), np.uint8)
if result is None:
continue
c = result.count_detections()
txt = "face" if c == 1 else "faces"
txt = f"{result.algorithm.ljust(5)} {c} {txt}"
draw.text((10, pil_im.size[1] - i*25 - 50), txt, fill=draw_colors[result.algorithm], font=font_s, stroke_width=1, stroke_fill=(0,0,0))
return cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
def display(image_res, q1, q2, q3, q4, fullscreen, output_dir):
logger = logging.getLogger('display')
empty_image = np.zeros((image_res[1],image_res[0],3), np.uint8)
results = [None, None, None]
result_queues = [q2, q3, q4]
images = [empty_image, empty_image, empty_image, empty_image]
override_image = None
override_until = None
if fullscreen: if fullscreen:
cv2.namedWindow("output", cv2.WND_PROP_FULLSCREEN) cv2.namedWindow("output", cv2.WND_PROP_FULLSCREEN)
@ -461,68 +450,57 @@ def display(image_res, q1, q2, q3, q4, fullscreen, output_dir):
while True: while True:
logging.debug('r') logging.debug('r')
try: try:
image = q1.get_nowait() image1 = q1.get_nowait()
images[0] = cv2.resize(image, (image_res[0], image_res[1])) image1 = cv2.resize(image1, (image_res[0], image_res[1]))
prev_image1 = image1
except Empty as e: except Empty as e:
pass image1 = prev_image1
try:
result2 = q2.get_nowait()
result2 = result2.resize(image_res[0], image_res[1])
result2.draw_detections()
image2 = result2.visualisation
# image2 = cv2.resize(image2, (image_res[0], image_res[1]))
prev_image2 = image2
except Empty as e:
image2 = prev_image2
try:
result3 = q3.get_nowait()
result3 = result3.resize(image_res[0], image_res[1])
result3.draw_detections()
image3 = result3.visualisation
# image3 = cv2.resize(image3, (image_res[0], image_res[1]))
prev_image3 = image3
except Empty as e:
image3 = prev_image3
try:
result4 = q4.get_nowait()
result4 = result4.resize(image_res[0], image_res[1])
result4.draw_detections()
image4 = result4.visualisation
# image4 = cv2.resize(image4, (image_res[0], image_res[1]))
prev_image4 = image4
except Empty as e:
image4 = prev_image4
for idx, queue in enumerate(result_queues): img_concate_Verti1 = np.concatenate((image1,image2),axis=0)
try: img_concate_Verti2 = np.concatenate((image3,image4),axis=0)
result = queue.get_nowait() grid_img = np.concatenate((img_concate_Verti1,img_concate_Verti2),axis=1)
results[idx] = result.resize(image_res[0], image_res[1]) cv2.imshow("output", grid_img)
images[idx+1] = results[idx].draw_detections(include_title=True)
except Empty as e:
pass
finally:
pass
if override_image is not None and override_until > time.time():
cv2.imshow("output", override_image)
else:
override_image = None
images[0] = draw_stats(images[0], results)
img_concate_Verti1 = np.concatenate((images[0],images[1]),axis=0)
img_concate_Verti2 = np.concatenate((images[2],images[3]),axis=0)
grid_img = np.concatenate((img_concate_Verti1,img_concate_Verti2),axis=1)
cv2.imshow("output", grid_img)
# Hit 'q' on the keyboard to quit! # Hit 'q' on the keyboard to quit!
key = cv2.waitKey(1) & 0xFF key = cv2.waitKey(1) & 0xFF
if key == ord('q'): if key == ord('q'):
break break
if key == ord(' '): if key == ord(' '):
# TODO wait for frame to be processed. Eg. if I move and make a pic, it should use the last frame... # TODO save frame
output_res = (image_res[0] *2, image_res[1] * 2) pass
pil_im = Image.fromarray(cv2.cvtColor(images[0], cv2.COLOR_BGR2RGB))
pil_im = pil_im.resize(output_res)
draw = ImageDraw.Draw(pil_im, 'RGBA')
for result in results: def main(camera_id, rotate, fullscreen, cascade_file):
if result is None:
continue
result.resize(output_res[0], output_res[1]).draw_detections_on(draw)
override_image = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
override_until = time.time() + 5
logger.info("Show frame until %f", override_until)
# save images:
name = datetime.datetime.now().isoformat(timespec='seconds')
cv2.imwrite(os.path.join(output_dir, f'{name}.png'),override_image)
for result in results:
cv2.imwrite(os.path.join(output_dir, f'{name}-{result.algorithm}.png'),result.visualisation)
def main(camera_id, rotate, fullscreen, cascade_file, output_dir):
image_size = (int(1920/2), int(1080/2)) image_size = (int(1920/2), int(1080/2))
if not os.path.exists(cascade_file): if not os.path.exists(cascade_file):
raise RuntimeError(f"Cannot load OpenCV haar-cascade file '{cascade_file}'") raise RuntimeError(f"Cannot load OpenCV haar-cascade file '{cascade_file}'")
if not os.path.isdir(output_dir):
raise RuntimeError(f"Non-existent directory to store files '{output_dir}'")
is_rotated_90 = rotate in [cv2.ROTATE_90_CLOCKWISE, cv2.ROTATE_90_COUNTERCLOCKWISE] is_rotated_90 = rotate in [cv2.ROTATE_90_CLOCKWISE, cv2.ROTATE_90_COUNTERCLOCKWISE]
@ -541,7 +519,7 @@ def main(camera_id, rotate, fullscreen, cascade_file, output_dir):
q_process3 = Queue(maxsize=1) q_process3 = Queue(maxsize=1)
p1 = Process(target=record, args=(camera_id, q_webcam1, q_webcam2,q_webcam3,q_webcam4, image_size, rotate)) p1 = Process(target=record, args=(camera_id, q_webcam1, q_webcam2,q_webcam3,q_webcam4, image_size, rotate))
p2 = Process(target=display, args=(image_size, q_webcam1, q_process1, q_process2, q_process3, fullscreen, output_dir )) p2 = Process(target=display, args=(image_size, q_webcam1, q_process1, q_process2, q_process3, fullscreen ))
p3 = Process(target=process1_hog, args=(q_webcam2, q_process1,)) p3 = Process(target=process1_hog, args=(q_webcam2, q_process1,))
p4 = Process(target=process2_dnn, args=(q_webcam3, q_process2,)) p4 = Process(target=process2_dnn, args=(q_webcam3, q_process2,))
p5 = Process(target=process3_haar, args=(q_webcam4, q_process3,cascade_file)) p5 = Process(target=process3_haar, args=(q_webcam4, q_process3,cascade_file))

View file

@ -15,8 +15,6 @@ if __name__ == '__main__':
help='Rotate counter clockwise') help='Rotate counter clockwise')
parser.add_argument('--cascade', default='haarcascade_frontalface_alt2.xml', parser.add_argument('--cascade', default='haarcascade_frontalface_alt2.xml',
help='Cascade XML file to use (opencv format)') help='Cascade XML file to use (opencv format)')
parser.add_argument('--output', default='saves',
help='Directory to store images (after pressing spacebar)')
args = parser.parse_args() args = parser.parse_args()
@ -26,4 +24,4 @@ if __name__ == '__main__':
if args.counter_clockwise: if args.counter_clockwise:
rotate = cv2.ROTATE_90_COUNTERCLOCKWISE rotate = cv2.ROTATE_90_COUNTERCLOCKWISE
face_recognition.comparison.main(args.camera, rotate, args.fullscreen, args.cascade, args.output) face_recognition.comparison.main(args.camera, rotate, args.fullscreen, args.cascade)

View file

@ -2,6 +2,3 @@ scipy
numpy numpy
dlib dlib
Pillow Pillow
opencv-python
cffi
scikit-image

@ -1 +1 @@
Subproject commit 928da82d24de1ae2cef268c140f9992b0614806b Subproject commit 7de5440484842c147944ae123fa689333846dde7