Crisper output and many configuration to cli arguments

This commit is contained in:
Ruben van de Ven 2020-09-23 15:58:36 +02:00
parent 2b1b04779d
commit 3b1f4e40b5
5 changed files with 148 additions and 24 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "visualhaar"]
path = visualhaar
url = git@git.rubenvandeven.com:r/visualhaar.git

View File

@ -5,13 +5,17 @@ import logging
import argparse import argparse
import numpy as np import numpy as np
import time import time
from PIL import ImageFont, ImageDraw, Image
import os
draw_colors = { draw_colors = {
'dnn': (255,0,0), 'hog': (255,0,0),
'haar': (0,255,0), 'haar': (0,255,0),
'hog': (0,0,255), 'dnn': (0,0,255),
} }
font = ImageFont.truetype("/home/ruben/Documents/Projecten/2018/PATH/presentation/lib/font/source-sans-pro/source-sans-pro-regular.ttf", 30)
class Result(): class Result():
def __init__(self, algorithm, image, confidence_threshold = 0.5): def __init__(self, algorithm, image, confidence_threshold = 0.5):
self.algorithm = algorithm self.algorithm = algorithm
@ -28,13 +32,54 @@ class Result():
'confidence': confidence 'confidence': confidence
}) })
return self return self
def draw_detections(self): def draw_detections(self):
color = draw_colors[self.algorithm]
cv2_im_rgb = cv2.cvtColor(self.visualisation,cv2.COLOR_BGR2RGB)
# Pass the image to PIL
pil_im = Image.fromarray(cv2_im_rgb)
draw = ImageDraw.Draw(pil_im, 'RGBA')
for detection in self.detections:
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):
width = 2
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'] - 40 if detection['startY'] - 40 > 10 else detection['startY'] + 10
draw.text((detection['startX'], y), text, font=font, fill=color)
# 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'])
color = list(color)
color.append(int(alpha*255))
color = tuple(color)
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] color = draw_colors[self.algorithm]
for detection in self.detections: for detection in self.detections:
self.draw_detection(detection, color) self.draw_detection(detection, color)
def draw_detection(self, detection, color=(0,0,255)): def draw_detection_cv2(self, detection, color=(0,0,255)):
# First we crop the sub-rect from the image # First we crop the sub-rect from the image
sub_img = self.visualisation[detection['startY']:detection['endY'], detection['startX']:detection['endX']] sub_img = self.visualisation[detection['startY']:detection['endY'], detection['startX']:detection['endX']]
@ -88,11 +133,28 @@ class Result():
def record(device_id, q1,q2, q3, q4): def record(device_id, q1,q2, q3, q4, resolution, rotate):
capture = cv2.VideoCapture(device_id) capture = cv2.VideoCapture(device_id)
is_rotated_90 = rotate in [cv2.ROTATE_90_CLOCKWISE, cv2.ROTATE_90_COUNTERCLOCKWISE]
capture.set(cv2.CAP_PROP_FRAME_WIDTH, resolution[1] if is_rotated_90 else resolution[0])
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, resolution[0] if is_rotated_90 else resolution[1])
while True: while True:
ret, image = capture.read() ret, image = capture.read()
logging.debug('r') if image is None:
logging.critical("Error with camera?")
exit()
if rotate is not None:
image = cv2.rotate(image, rotate)
# print(image.shape[:2], image.shape[1::-1])
if image.shape[1::-1] != resolution:
logging.warning(f"Camera resultion seems wrong: {image.shape[:2]} instead of {resolution}")
try: try:
q1.put_nowait(image) q1.put_nowait(image)
except Full as e: except Full as e:
@ -155,6 +217,10 @@ def process1_hog(in_q, out_q):
from skimage import data, exposure from skimage import data, exposure
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import dlib import dlib
import matplotlib.pyplot as plt
# Get the color map by name:
cm = plt.get_cmap('plasma')
face_detector = dlib.get_frontal_face_detector() face_detector = dlib.get_frontal_face_detector()
@ -187,9 +253,17 @@ def process1_hog(in_q, out_q):
# print(dets, scores, idxs) # print(dets, scores, idxs)
hog_image_rescaled = (hog_image_rescaled.astype('float32') * 255).astype('uint8') hog_image_rescaled = (hog_image_rescaled.astype('float32') * 255).astype('uint8')
hog_image_rescaled = cv2.cvtColor(hog_image_rescaled, cv2.COLOR_GRAY2BGR) # hog_image_rescaled = cv2.cvtColor(hog_image_rescaled, cv2.COLOR_GRAY2BGR)
# blue background:
# hog_image_rescaled[:,:,0] = 200
result = Result('hog', hog_image_rescaled, 0)
# Apply the colormap like a function to any array:
colored_image = (cm(hog_image_rescaled) * 255).astype('uint8')
colored_image = cv2.cvtColor(colored_image, cv2.COLOR_RGB2BGR)
# result = Result('hog', hog_image_rescaled, 0)
result = Result('hog', colored_image, 0)
# Display the results # Display the results
for i, rectangle in enumerate(dets): for i, rectangle in enumerate(dets):
@ -269,10 +343,11 @@ def process2_dnn(in_q, out_q):
out_q.put(result) out_q.put(result)
def process3_haar(in_q, out_q): def process3_haar(in_q, out_q, cascade_file):
from cffi import FFI from cffi import FFI
from PIL import Image from PIL import Image
import cv2 import cv2
import os
logger = logging.getLogger('haar') logger = logging.getLogger('haar')
@ -281,11 +356,12 @@ def process3_haar(in_q, out_q):
int test(int); int test(int);
typedef void* haarclassifier; typedef void* haarclassifier;
haarclassifier classifier_new(); haarclassifier classifier_new(char *filename);
void scan_image(haarclassifier, size_t width,size_t height, char *input, char *buffer, size_t length, bool debug); void scan_image(haarclassifier, size_t width,size_t height, char *input, char *buffer, size_t length, bool debug);
""") """)
C = ffi.dlopen("/home/ruben/Documents/Projecten/2020/rust/testproject/target/debug/libvisual_haarcascades_lib.so") dir_path = os.path.dirname(os.path.realpath(__file__))
C = ffi.dlopen(os.path.join(dir_path,"../visualhaar/target/debug/libvisual_haarcascades_lib.so"))
# print(C.test(9)) # print(C.test(9))
# i = Image.open("Marjo.jpg") # i = Image.open("Marjo.jpg")
@ -293,11 +369,14 @@ def process3_haar(in_q, out_q):
# height = i.size[0] # height = i.size[0]
# use the rust lib to draw the visualisation # use the rust lib to draw the visualisation
haar = C.classifier_new()
filename = cascade_file.encode('ascii')
fn = ffi.new("char[]", filename)
haar = C.classifier_new(fn)
logger.info("Initialised haar classifier") logger.info("Initialised haar classifier")
# opencv for the actual detections # opencv for the actual detections
faceCascade = cv2.CascadeClassifier('./haarcascade_frontalface_alt2.xml') faceCascade = cv2.CascadeClassifier(cascade_file)
while True: while True:
frame = in_q.get() frame = in_q.get()
@ -358,12 +437,16 @@ def process3_haar(in_q, out_q):
# print(img) # print(img)
out_q.put(result) out_q.put(result)
def display(image_res, q1, q2, q3, q4): def display(image_res, q1, q2, q3, q4, fullscreen = False):
prev_image1 = np.zeros((image_res[1],image_res[0],3), np.uint8) prev_image1 = np.zeros((image_res[1],image_res[0],3), np.uint8)
prev_image2 = np.zeros((image_res[1],image_res[0],3), np.uint8) 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) prev_image3 = np.zeros((image_res[1],image_res[0],3), np.uint8)
prev_image4 = np.zeros((image_res[1],image_res[0],3), np.uint8) prev_image4 = np.zeros((image_res[1],image_res[0],3), np.uint8)
if fullscreen:
cv2.namedWindow("output", cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty("output",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
while True: while True:
logging.debug('r') logging.debug('r')
try: try:
@ -403,14 +486,27 @@ def display(image_res, q1, q2, q3, q4):
img_concate_Verti1 = np.concatenate((image1,image2),axis=0) img_concate_Verti1 = np.concatenate((image1,image2),axis=0)
img_concate_Verti2 = np.concatenate((image3,image4),axis=0) img_concate_Verti2 = np.concatenate((image3,image4),axis=0)
grid_img = np.concatenate((img_concate_Verti1,img_concate_Verti2),axis=1) grid_img = np.concatenate((img_concate_Verti1,img_concate_Verti2),axis=1)
cv2.imshow("Output", grid_img) cv2.imshow("output", grid_img)
# Hit 'q' on the keyboard to quit! # Hit 'q' on the keyboard to quit!
if cv2.waitKey(1) & 0xFF == ord('q'): key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break break
if key == ord(' '):
# TODO save frame
pass
def main(camera_id): def main(camera_id, rotate, fullscreen, cascade_file):
image_size = (int(1920/2), int(1080/2)) image_size = (int(1920/2), int(1080/2))
if not os.path.exists(cascade_file):
raise RuntimeError(f"Cannot load OpenCV haar-cascade file '{cascade_file}'")
is_rotated_90 = rotate in [cv2.ROTATE_90_CLOCKWISE, cv2.ROTATE_90_COUNTERCLOCKWISE]
if is_rotated_90:
image_size = (image_size[1], image_size[0])
# TODO should we use queues here at all? # TODO should we use queues here at all?
# https://docs.python.org/3/library/multiprocessing.html#programming-guidelines # https://docs.python.org/3/library/multiprocessing.html#programming-guidelines
# TODO: queue maxsize, or prefrabily some sort of throttled queue (like zmq hight water mark) # TODO: queue maxsize, or prefrabily some sort of throttled queue (like zmq hight water mark)
@ -422,11 +518,11 @@ def main(camera_id):
q_process2 = Queue(maxsize=1) q_process2 = Queue(maxsize=1)
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)) 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 )) 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,)) p5 = Process(target=process3_haar, args=(q_webcam4, q_process3,cascade_file))
p1.start() p1.start()
p2.start() p2.start()

View File

@ -1,10 +1,27 @@
import argparse import argparse
import face_recognition.comparison import face_recognition.comparison
import cv2
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Visualise face recognition algorithms.') parser = argparse.ArgumentParser(description='Visualise face recognition algorithms.')
parser.add_argument('--camera', '-c', type=int, default=0, parser.add_argument('--camera', '-c', type=int, default=0,
help='Numeric id of the camera') help='Numeric id of the camera')
parser.add_argument('--fullscreen', '-f', action='store_true',
help='Display output full screen')
parser.add_argument('--clockwise', action='store_true',
help='Rotate clockwise')
parser.add_argument('--counter-clockwise', action='store_true',
help='Rotate counter clockwise')
parser.add_argument('--cascade', default='haarcascade_frontalface_alt2.xml',
help='Cascade XML file to use (opencv format)')
args = parser.parse_args() args = parser.parse_args()
face_recognition.comparison.main(args.camera)
rotate = None
if args.clockwise:
rotate = cv2.ROTATE_90_CLOCKWISE
if args.counter_clockwise:
rotate = cv2.ROTATE_90_COUNTERCLOCKWISE
face_recognition.comparison.main(args.camera, rotate, args.fullscreen, args.cascade)

View File

@ -8,11 +8,12 @@ ffi.cdef("""
int test(int); int test(int);
typedef void* haarclassifier; typedef void* haarclassifier;
haarclassifier classifier_new(); haarclassifier classifier_new(char *filename);
void scan_image(haarclassifier, size_t width,size_t height, char *input, char *buffer, size_t length, bool debug); void scan_image(haarclassifier, size_t width,size_t height, char *input, char *buffer, size_t length, bool debug);
""") """)
C = ffi.dlopen("/home/ruben/Documents/Projecten/2020/rust/testproject/target/debug/libvisual_haarcascades_lib.so") # C = ffi.dlopen("/home/ruben/Documents/Projecten/2020/rust/testproject/target/debug/libvisual_haarcascades_lib.so")
C = ffi.dlopen("visualhaar/target/debug/libvisual_haarcascades_lib.so")
print(C.test(9)) print(C.test(9))
# i = Image.open("/home/ruben/Documents/Projecten/2020/rust/lena_orig.png") # i = Image.open("/home/ruben/Documents/Projecten/2020/rust/lena_orig.png")
@ -41,7 +42,13 @@ while True:
# buffer2 = ffi.from_buffer("char[]", (i.tobytes("raw","RGB"))) # buffer2 = ffi.from_buffer("char[]", (i.tobytes("raw","RGB")))
buffer2 = ffi.from_buffer("char[]", image.tobytes()) buffer2 = ffi.from_buffer("char[]", image.tobytes())
haar = C.classifier_new()
filename = "/home/ruben/Documents/Projecten/2020/rust/testproject/haarcascade_frontalface_alt2.xml".encode('ascii')
fn = ffi.new("char[]", filename)
# fn = ffi.string(filename)
print("Initialise...")
haar = C.classifier_new(fn)
# i = Image.open("/home/ruben/Documents/Projecten/2020/rust/lena_orig.png") # i = Image.open("/home/ruben/Documents/Projecten/2020/rust/lena_orig.png")
# data = i.tobytes("raw", "RGB") # data = i.tobytes("raw", "RGB")

1
visualhaar Submodule

@ -0,0 +1 @@
Subproject commit 9621bdc934b9a16e883d763e05de9d84d424c639