Compare commits
12 Commits
Author | SHA1 | Date |
---|---|---|
Ruben van de Ven | 4c519e46a6 | |
Ruben van de Ven | 75db761507 | |
Ruben van de Ven | e9c48317f8 | |
Ruben van de Ven | df5d72ca83 | |
Ruben van de Ven | 12ce9e1751 | |
Ruben van de Ven | b3b407a99e | |
Ruben van de Ven | b3a0e4035b | |
Ruben van de Ven | cf88f3a8ee | |
Ruben van de Ven | 9d1b523c56 | |
Ruben van de Ven | 2af58fc170 | |
Ruben van de Ven | 357d481b97 | |
Ruben van de Ven | 50e05c631e |
|
@ -17,8 +17,9 @@
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "mirror.py",
|
"program": "mirror.py",
|
||||||
"args": [
|
"args": [
|
||||||
// "--fullscreen",
|
"--windowed",
|
||||||
"--camera", "2",
|
"--output", "/tmp/face_saves",
|
||||||
|
"--camera", "0",
|
||||||
],
|
],
|
||||||
"console": "integratedTerminal"
|
"console": "integratedTerminal"
|
||||||
}
|
}
|
||||||
|
|
48
README.md
48
README.md
|
@ -11,21 +11,55 @@ A `mirror` which shows which faces are detected through three different facial d
|
||||||
|
|
||||||
The installation in Windows can be done, though it is quite elaborate:
|
The installation in Windows can be done, though it is quite elaborate:
|
||||||
|
|
||||||
* Install rustup-init
|
* Install python3.8
|
||||||
* Install VS C++
|
* Install VS C++ build tools
|
||||||
* Install python3
|
|
||||||
* Install Cmake (needed for python dlib)
|
* Install Cmake (needed for python dlib)
|
||||||
+ make sure to add it to path
|
+ make sure to add it to path
|
||||||
* Install git
|
* Install git
|
||||||
+ including ssh deploy key
|
+ including ssh deploy key
|
||||||
* `git clone https://git.rubenvandeven.com/r/face_detector`
|
* `git clone https://git.rubenvandeven.com/r/face_recognition`
|
||||||
* `cd face_recognition`
|
* `cd face_recognition`
|
||||||
* `git submodules init`
|
|
||||||
* `git submodules update`
|
|
||||||
* `pip install virtualenv`
|
* `pip install virtualenv`
|
||||||
* `virtualenv.exe venv`
|
* `virtualenv.exe venv`
|
||||||
|
+ Might be that you need to run: `C:\Users\DP Medialab\AppData\Roaming\Python\Python39\Scripts\virtualenv.exe` (see pip output)
|
||||||
* `.\venv\Scripts\activate`
|
* `.\venv\Scripts\activate`
|
||||||
|
+ Might be that you need to first run `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
|
||||||
* `cd .\dnn\face_detector`
|
* `cd .\dnn\face_detector`
|
||||||
* `python.exe .\download_weights.py`
|
* `python.exe .\download_weights.py`
|
||||||
|
* `cd ..\..`
|
||||||
|
* `pip.exe install -r requirements.txt`
|
||||||
* `cd .\visualhaar`
|
* `cd .\visualhaar`
|
||||||
* `cargo build --lib --release`
|
* Either one of:
|
||||||
|
+ Compile rust library
|
||||||
|
* Install rustup-init
|
||||||
|
* `git submodules init`
|
||||||
|
* `git submodules update`
|
||||||
|
* `cargo build --lib --release`
|
||||||
|
+ Download dll from https://git.rubenvandeven.com/r/visualhaar/releases
|
||||||
|
+ Fetch `SourceSansPro-Regular.ttf` from the internet
|
||||||
|
+ Make the installer:
|
||||||
|
* Either one of:
|
||||||
|
* `& 'C:\Users\DP Medialab\AppData\Roaming\Python\Python38\Scripts\pyinstaller.exe' .\mirror.py --add-binary '.\visualhaar\target\release\visual_haarcascades_lib.dll;.' --add-data '.\haarcascade_frontalface_alt2.xml;.' --add-data '.\SourceSansPro-Regular.ttf;.' --add-data 'dnn;dnn'`
|
||||||
|
* `& '.\venv\Scripts\pyinstaller.exe' .\mirror.py --add-binary '.\visualhaar\target\release\visual_haarcascades_lib.dll;.' --add-data '.\haarcascade_frontalface_alt2.xml;.' --add-data '.\SourceSansPro-Regular.ttf;.' --add-data 'dnn;dnn' --hidden-import 'scipy.spatial.transform._rotation_groups' --hidden-import 'skimage.filters.rank.core_cy_3d'`
|
||||||
|
* `Compress-Archive -LiteralPath .\dist\mirror -DestinationPath .\dist\mirror.zip`
|
||||||
|
+ We could also [use wine for cross compilation](https://www.andreafortuna.org/2017/12/27/how-to-cross-compile-a-python-script-into-a-windows-executable-on-linux/) from Linux
|
||||||
|
- make sure wine is set to pose as Windows 10 (`winecfg`)
|
||||||
|
- `wine ~/Downloads/python-3.9.0-amd64.exe` (or whichever version you use)
|
||||||
|
- Install for all users
|
||||||
|
-
|
||||||
|
|
||||||
|
### On windows in VirtualBox
|
||||||
|
|
||||||
|
See [this](https://askubuntu.com/questions/4875/how-can-i-use-my-webcam-with-ubuntu-running-in-virtualbox/1237808#1237808) on getting the webcam working in the VM:
|
||||||
|
|
||||||
|
1. Install extension pack: `sudo apt install virtualbox-ext-pack`
|
||||||
|
2. `VBoxManage list webcams`
|
||||||
|
3. `VBoxManage controlvm "WIn10" webcam attach .3`
|
||||||
|
|
||||||
|
|
||||||
|
## Instructor help
|
||||||
|
|
||||||
|
If screen stays black: is the camera on?
|
||||||
|
|
||||||
|
|
||||||
|
Enable camera through keyboard (MSI laptops: fn+F6). Then go to Settings/Instellingen -> Privacy instellingen voor camera -> Grant apps access to camera.
|
||||||
|
|
|
@ -9,11 +9,12 @@ import math
|
||||||
import datetime
|
import datetime
|
||||||
from PIL import ImageFont, ImageDraw, Image
|
from PIL import ImageFont, ImageDraw, Image
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
draw_colors = {
|
draw_colors = {
|
||||||
'hog': (255,255,255), #(198,65,124),
|
'hog': (198,65,124),
|
||||||
'haar': (255,255,255),
|
'haar': (255,255,255),
|
||||||
'dnn': (255,255,255) #(251,212,36),
|
'dnn': (251,212,36),
|
||||||
}
|
}
|
||||||
|
|
||||||
titles = {
|
titles = {
|
||||||
|
@ -22,7 +23,10 @@ titles = {
|
||||||
'dnn' : "Neural network",
|
'dnn' : "Neural network",
|
||||||
}
|
}
|
||||||
|
|
||||||
fontfile = "SourceSansPro-Regular.ttf"
|
|
||||||
|
project_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)),'..')
|
||||||
|
|
||||||
|
fontfile = os.path.join(project_dir, "SourceSansPro-Regular.ttf")
|
||||||
|
|
||||||
font = ImageFont.truetype(fontfile, 30)
|
font = ImageFont.truetype(fontfile, 30)
|
||||||
font_s = ImageFont.truetype(fontfile, 20)
|
font_s = ImageFont.truetype(fontfile, 20)
|
||||||
|
@ -45,42 +49,50 @@ class Result():
|
||||||
})
|
})
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def draw_detections(self, include_title = False):
|
def draw_detections(self, include_title = False, coloured=False):
|
||||||
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)
|
self.draw_detections_on(draw, coloured)
|
||||||
|
|
||||||
if include_title:
|
if include_title:
|
||||||
draw.text((10,10), titles[self.algorithm], fill=draw_colors[self.algorithm], font=font)
|
color = draw_colors[self.algorithm] if coloured else (255,255,255)
|
||||||
|
draw.text((10,10), titles[self.algorithm], fill=color, font=font, stroke_width=1, stroke_fill=(0,0,0,100))
|
||||||
|
|
||||||
return cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
return cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
||||||
|
|
||||||
def draw_detections_on(self, draw: ImageDraw):
|
def draw_detections_on(self, draw: ImageDraw, coloured=False, onlyIfConfident=False):
|
||||||
'''
|
'''
|
||||||
Draw on a specified canvas
|
Draw on a specified canvas
|
||||||
'''
|
'''
|
||||||
color = draw_colors[self.algorithm]
|
color = draw_colors[self.algorithm] if coloured else (255,255,255)
|
||||||
for detection in self.detections:
|
for detection in self.detections:
|
||||||
self.draw_detection(draw, detection, color)
|
self.draw_detection(draw, detection, color, onlyIfConfident)
|
||||||
|
|
||||||
def draw_detection(self, draw: ImageDraw, detection: dict, color: tuple):
|
def draw_detection(self, draw: ImageDraw, detection: dict, color: tuple, onlyIfConfident: bool = False):
|
||||||
width = 2
|
|
||||||
|
|
||||||
if detection['confidence'] > self.confidence_threshold:
|
if detection['confidence'] > self.confidence_threshold:
|
||||||
|
width = 8
|
||||||
# draw the bounding box of the face along with the associated
|
# draw the bounding box of the face along with the associated
|
||||||
# probability
|
# probability
|
||||||
text = "{:.2f}%".format(detection['confidence'] * 100)
|
text = "{:.0f}%".format(detection['confidence'] * 100)
|
||||||
y = detection['startY'] - 40 if detection['startY'] - 40 > 10 else detection['startY'] + 10
|
y = detection['startY'] - 40 if detection['startY'] - 40 > 10 else detection['startY'] + 10
|
||||||
|
|
||||||
draw.text((detection['startX'], y), text, font=font, fill=color)
|
draw.text((detection['startX'], y), text, font=font, fill=color, stroke_fill=(0,0,0,100), stroke_width=1)
|
||||||
# cv2.putText(self.visualisation, text, (detection['startX'], y),
|
# cv2.putText(self.visualisation, text, (detection['startX'], y),
|
||||||
# cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2, lineType = cv2.LINE_AA)
|
# cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2, lineType = cv2.LINE_AA)
|
||||||
|
|
||||||
alpha = 1
|
alpha = 1
|
||||||
|
draw.rectangle((detection['startX']-1, detection['startY']-1, detection['endX']+1, detection['endY']+1), outline=(0,0,0,100), width=1)
|
||||||
|
draw.rectangle((detection['startX']+width, detection['startY']+width, detection['endX']-width, detection['endY']-width), outline=(0,0,0,100), width=1)
|
||||||
|
elif onlyIfConfident:
|
||||||
|
# Only draw if above threshold, so this should be ignored.
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
|
width = int(detection['confidence'] * 10 * 8)
|
||||||
# At least 10% opacity
|
# At least 10% opacity
|
||||||
alpha = max(.2, detection['confidence'])
|
alpha = max(.2, detection['confidence'])
|
||||||
|
|
||||||
|
@ -90,23 +102,35 @@ class Result():
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
def resize(self, width, height, flip=False):
|
||||||
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
|
||||||
factor_x = width / self.visualisation.shape[1]
|
factor_x = width / self.visualisation.shape[1]
|
||||||
factor_y = height / self.visualisation.shape[0]
|
factor_y = height / self.visualisation.shape[0]
|
||||||
inter = cv2.INTER_NEAREST if self.algorithm in ['dnn', 'haar'] else cv2.INTER_CUBIC
|
inter = cv2.INTER_NEAREST if self.algorithm in ['dnn', 'haar'] else cv2.INTER_CUBIC
|
||||||
img = cv2.resize(img, (width, height), interpolation=inter)
|
img = cv2.resize(img, (width, height), interpolation=inter)
|
||||||
|
|
||||||
|
if flip:
|
||||||
|
img = cv2.flip(img, 1)
|
||||||
|
|
||||||
result = Result(self.algorithm, img, self.confidence_threshold)
|
result = Result(self.algorithm, img, self.confidence_threshold)
|
||||||
for d in self.detections:
|
for d in self.detections:
|
||||||
result.add_detection(
|
if flip:
|
||||||
int(d['startX'] * factor_x),
|
result.add_detection(
|
||||||
int(d['startY'] * factor_y),
|
int(width - d['endX'] * factor_x),
|
||||||
int(d['endX'] * factor_x),
|
int(d['startY'] * factor_y),
|
||||||
int(d['endY'] * factor_y),
|
int(width - d['startX'] * factor_x),
|
||||||
d['confidence']
|
int(d['endY'] * factor_y),
|
||||||
)
|
d['confidence']
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
result.add_detection(
|
||||||
|
int(d['startX'] * factor_x),
|
||||||
|
int(d['startY'] * factor_y),
|
||||||
|
int(d['endX'] * factor_x),
|
||||||
|
int(d['endY'] * factor_y),
|
||||||
|
d['confidence']
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def count_detections(self):
|
def count_detections(self):
|
||||||
|
@ -128,7 +152,7 @@ def record(device_id, q1,q2, q3, q4, resolution, rotate):
|
||||||
ret, image = capture.read()
|
ret, image = capture.read()
|
||||||
if image is None:
|
if image is None:
|
||||||
logging.critical("Error with camera?")
|
logging.critical("Error with camera?")
|
||||||
exit()
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
if rotate is not None:
|
if rotate is not None:
|
||||||
|
@ -199,9 +223,9 @@ def draw_detection(image, startX, startY, endX, endY, confidence, color=(0,0,255
|
||||||
|
|
||||||
|
|
||||||
def process1_hog(in_q, out_q):
|
def process1_hog(in_q, out_q):
|
||||||
from skimage.feature import hog as hog_orig
|
# from skimage.feature import hog as hog_orig
|
||||||
from .hog import hog # use modified version for viz
|
from .hog import hog # use modified version for viz
|
||||||
from skimage import data, exposure
|
from skimage import exposure
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import dlib
|
import dlib
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
@ -212,7 +236,7 @@ def process1_hog(in_q, out_q):
|
||||||
face_detector = dlib.get_frontal_face_detector()
|
face_detector = dlib.get_frontal_face_detector()
|
||||||
|
|
||||||
visualisation_factor = 1
|
visualisation_factor = 1
|
||||||
detection_factor = .4
|
detection_factor = .3
|
||||||
|
|
||||||
|
|
||||||
process_this_frame = True
|
process_this_frame = True
|
||||||
|
@ -222,7 +246,7 @@ def process1_hog(in_q, out_q):
|
||||||
frame = in_q.get()
|
frame = in_q.get()
|
||||||
|
|
||||||
frame = cv2.cvtColor(src=frame, code=cv2.COLOR_BGR2GRAY)
|
frame = cv2.cvtColor(src=frame, code=cv2.COLOR_BGR2GRAY)
|
||||||
viz_frame = cv2.resize(frame, (0, 0), fx=visualisation_factor, fy=visualisation_factor)
|
# viz_frame = cv2.resize(frame, (0, 0), fx=visualisation_factor, fy=visualisation_factor)
|
||||||
det_frame = cv2.resize(frame, (0, 0), fx=detection_factor, fy=detection_factor)
|
det_frame = cv2.resize(frame, (0, 0), fx=detection_factor, fy=detection_factor)
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
@ -330,7 +354,7 @@ def process2_dnn(in_q, out_q):
|
||||||
|
|
||||||
out_q.put(result)
|
out_q.put(result)
|
||||||
|
|
||||||
def process3_haar(in_q, out_q, cascade_file):
|
def process3_haar(in_q, out_q, cascade_file, library_filename = None):
|
||||||
from cffi import FFI
|
from cffi import FFI
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import cv2
|
import cv2
|
||||||
|
@ -347,19 +371,27 @@ def process3_haar(in_q, out_q, cascade_file):
|
||||||
void scan_image(haarclassifier, size_t width,size_t height, char *input, char *buffer, size_t length, size_t min_face_factor, bool debug);
|
void scan_image(haarclassifier, size_t width,size_t height, char *input, char *buffer, size_t length, size_t min_face_factor, bool debug);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
|
if library_filename is not None:
|
||||||
lib_path = os.path.join(dir_path, "..", "visualhaar", "target", "release")
|
C = ffi.dlopen(library_filename)
|
||||||
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:
|
else:
|
||||||
raise RuntimeException("Visual haarcascades library is not found")
|
|
||||||
|
|
||||||
|
lib_path = os.path.join(project_dir, "visualhaar", "target", "release")
|
||||||
|
possible_paths = [
|
||||||
|
os.path.join(lib_path, "libvisual_haarcascades_lib.so"),
|
||||||
|
os.path.join(lib_path, "visual_haarcascades_lib.dll"),
|
||||||
|
os.path.join(project_dir, "visual_haarcascades_lib.dll"),
|
||||||
|
]
|
||||||
|
|
||||||
|
existing_paths = [p for p in possible_paths if os.path.exists(p)]
|
||||||
|
|
||||||
|
if not len(existing_paths):
|
||||||
|
raise RuntimeError("Visual haarcascades library is not found")
|
||||||
|
|
||||||
|
logger.debug(f"Using library: {existing_paths[0]}")
|
||||||
|
C = ffi.dlopen(existing_paths[0])
|
||||||
|
|
||||||
# print(C.test(9))
|
# print(C.test(9))
|
||||||
# i = Image.open("Marjo.jpg")
|
# i = Image.open("Marjo.jpg")
|
||||||
# width = i.size[0]
|
# width = i.size[0]
|
||||||
|
@ -406,7 +438,7 @@ def process3_haar(in_q, out_q, cascade_file):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
C.scan_image(haar, width, height, buffer2, buffer, buffer_len, 5, False)
|
C.scan_image(haar, width, height, buffer2, buffer, buffer_len, 5, False)
|
||||||
logger.info(f"Visualised scan into buffer: {buffer}")
|
logger.info(f"Visualised scan into buffer: {buffer}")
|
||||||
print(f"duration: {time.time() - start}s")
|
# print(f"duration: {time.time() - start}s")
|
||||||
|
|
||||||
img = Image.frombuffer(pixel_format, (width, height), ffi.buffer(buffer),
|
img = Image.frombuffer(pixel_format, (width, height), ffi.buffer(buffer),
|
||||||
"raw", pixel_format, 0, 1)
|
"raw", pixel_format, 0, 1)
|
||||||
|
@ -434,10 +466,13 @@ 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, padding):
|
def draw_stats(image, results, padding, coloured=False, drawDetections=False):
|
||||||
pil_im = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
pil_im = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
||||||
draw = ImageDraw.Draw(pil_im, 'RGBA')
|
draw = ImageDraw.Draw(pil_im, 'RGBA')
|
||||||
|
draw_stats_on_canvas(draw, results, padding, coloured, drawDetections)
|
||||||
|
return cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
||||||
|
|
||||||
|
def draw_stats_on_canvas(draw, results, padding, coloured=False, drawDetections=False):
|
||||||
for i, result in enumerate(results):
|
for i, result in enumerate(results):
|
||||||
if result is None:
|
if result is None:
|
||||||
continue
|
continue
|
||||||
|
@ -446,9 +481,11 @@ def draw_stats(image, results, padding):
|
||||||
txt = "face" if c == 1 else "faces"
|
txt = "face" if c == 1 else "faces"
|
||||||
txt = f"{result.algorithm.ljust(5)} {c} {txt}"
|
txt = f"{result.algorithm.ljust(5)} {c} {txt}"
|
||||||
height = padding + 25
|
height = padding + 25
|
||||||
draw.text((padding, pil_im.size[1] - i*height - height), txt, fill=draw_colors[result.algorithm], font=font_s, stroke_width=1, stroke_fill=(0,0,0))
|
colour = draw_colors[result.algorithm] if coloured else (255,255,255)
|
||||||
|
draw.text((padding, draw.im.size[1] - (i+1)*height - padding), txt, fill=colour, font=font, stroke_width=2, stroke_fill=(0,0,0))
|
||||||
|
|
||||||
return cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
if drawDetections:
|
||||||
|
result.draw_detections_on(draw, coloured, onlyIfConfident=True)
|
||||||
|
|
||||||
|
|
||||||
def display(image_res, q1, q2, q3, q4, fullscreen, output_dir):
|
def display(image_res, q1, q2, q3, q4, fullscreen, output_dir):
|
||||||
|
@ -535,7 +572,9 @@ def display(image_res, q1, q2, q3, q4, fullscreen, output_dir):
|
||||||
grid_img.shape[1] - padding - preview_width:grid_img.shape[1] - padding] = cv2.resize(image, (preview_width, preview_height), cv2.INTER_CUBIC)
|
grid_img.shape[1] - padding - preview_width:grid_img.shape[1] - padding] = cv2.resize(image, (preview_width, preview_height), cv2.INTER_CUBIC)
|
||||||
|
|
||||||
# statistics
|
# statistics
|
||||||
grid_img = draw_stats(grid_img, results, padding)
|
# for the plain webcam image (no viz), draw all detected faces.
|
||||||
|
drawDetections = (selectPreview.imageIdx == 0)
|
||||||
|
grid_img = draw_stats(grid_img, results, padding, coloured=True, drawDetections=drawDetections)
|
||||||
pil_im = Image.fromarray(cv2.cvtColor(grid_img, cv2.COLOR_BGR2RGB))
|
pil_im = Image.fromarray(cv2.cvtColor(grid_img, cv2.COLOR_BGR2RGB))
|
||||||
draw = ImageDraw.Draw(pil_im, 'RGBA')
|
draw = ImageDraw.Draw(pil_im, 'RGBA')
|
||||||
|
|
||||||
|
@ -543,7 +582,7 @@ def display(image_res, q1, q2, q3, q4, fullscreen, output_dir):
|
||||||
if countdown_until:
|
if countdown_until:
|
||||||
duration = math.ceil(countdown_until - time.time())
|
duration = math.ceil(countdown_until - time.time())
|
||||||
w, h = draw.textsize(f"{duration}", font=countdown_font)
|
w, h = draw.textsize(f"{duration}", font=countdown_font)
|
||||||
draw.text(((grid_img.shape[1]-w)/2,(grid_img.shape[0]-h)/2), f"{duration}", fill="white", stroke="black", font=countdown_font)
|
draw.text(((grid_img.shape[1]-w)/2,(grid_img.shape[0]-h)/2), f"{duration}", fill="white", stroke="black", font=countdown_font, stroke_width=1, stroke_fill=(0,0,0,100))
|
||||||
|
|
||||||
grid_img = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
grid_img = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
||||||
|
|
||||||
|
@ -554,41 +593,63 @@ def display(image_res, q1, q2, q3, q4, fullscreen, output_dir):
|
||||||
|
|
||||||
# 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') or key == 27: # key 27: escape
|
||||||
break
|
break
|
||||||
if key == ord(' ') and not override_image:
|
|
||||||
|
# TODO: the truth value of an array with ore than one element is ambiguous, use a.any or a.all() (OF DUS override_image is None)
|
||||||
|
if key == ord(' ') and override_image is None:
|
||||||
countdown_until = time.time() + 3 # seconds of countdown
|
countdown_until = time.time() + 3 # seconds of countdown
|
||||||
|
|
||||||
|
# SNAP! SAVE FRAMES
|
||||||
if countdown_until is not None and time.time() > countdown_until:
|
if countdown_until is not None and time.time() > countdown_until:
|
||||||
countdown_until = None
|
countdown_until = None
|
||||||
# TODO wait for frame to be processed. Eg. if I move and make a pic, it should use the last frame...
|
# TODO wait for frame to be processed. Eg. if I move and make a pic, it should use the last frame...
|
||||||
# SNAP!
|
|
||||||
# output_res = (image_res[0] *2, image_res[1] * 2)
|
# output_res = (image_res[0] *2, image_res[1] * 2)
|
||||||
output_res = image_res # no scaling needed anyore
|
output_res = image_res # no scaling needed anyore
|
||||||
pil_im = Image.fromarray(cv2.cvtColor(images[0], cv2.COLOR_BGR2RGB))
|
pil_im = Image.fromarray(cv2.cvtColor(cv2.flip(images[0],1), cv2.COLOR_BGR2RGB))
|
||||||
pil_im = pil_im.resize(output_res)
|
pil_im = pil_im.resize(output_res)
|
||||||
|
|
||||||
|
# base name for all images
|
||||||
|
name = datetime.datetime.now().isoformat(timespec='seconds').replace(':','-')
|
||||||
|
|
||||||
|
# filename of clean frame
|
||||||
|
filename = os.path.join(output_dir, f'{name}-frame.jpg')
|
||||||
|
pil_im.save(filename)
|
||||||
|
|
||||||
|
# now draw all results to the main image
|
||||||
draw = ImageDraw.Draw(pil_im, 'RGBA')
|
draw = ImageDraw.Draw(pil_im, 'RGBA')
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
if result is None:
|
if result is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
result.resize(output_res[0], output_res[1]).draw_detections_on(draw)
|
result.resize(output_res[0], output_res[1], flip=True).draw_detections_on(draw, coloured=True)
|
||||||
|
|
||||||
|
draw_stats_on_canvas(draw, results, padding, coloured=True)
|
||||||
|
|
||||||
override_image = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
override_image = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
||||||
override_until = time.time() + 5
|
override_until = time.time() + 5
|
||||||
logger.info("Show frame until %f", override_until)
|
logger.info("Show frame until %f", override_until)
|
||||||
|
|
||||||
# save images:
|
# save images:
|
||||||
name = datetime.datetime.now().isoformat(timespec='seconds')
|
filename = os.path.join(output_dir, f'{name}-all.png')
|
||||||
cv2.imwrite(os.path.join(output_dir, f'{name}.png'),override_image)
|
print(f"Save to {filename}")
|
||||||
|
r=cv2.imwrite(filename, override_image)
|
||||||
|
if not r:
|
||||||
|
raise RuntimeError(f"Could not save image {filename}")
|
||||||
|
|
||||||
|
# finally, store each visualisation with the results
|
||||||
for result in results:
|
for result in results:
|
||||||
cv2.imwrite(os.path.join(output_dir, f'{name}-{result.algorithm}.png'),result.visualisation)
|
result_img =result.draw_detections(include_title = True)
|
||||||
|
filename = os.path.join(output_dir, f'{name}-{result.algorithm}.png')
|
||||||
|
r = cv2.imwrite(filename, result_img)
|
||||||
|
if not r:
|
||||||
|
raise RuntimeError(f"Could not save image {filename}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main(camera_id, rotate, fullscreen, cascade_file, output_dir):
|
def main(camera_id, rotate, fullscreen, cascade_file, output_dir, visualhaar_lib = None):
|
||||||
image_size = (1920, 1080) #(int(1920/2), int(1080/2))
|
image_size = (1920, 1080) #(int(1920/2), int(1080/2))
|
||||||
|
|
||||||
if not os.path.exists(cascade_file):
|
if not os.path.exists(cascade_file):
|
||||||
|
@ -616,7 +677,7 @@ def main(camera_id, rotate, fullscreen, cascade_file, output_dir):
|
||||||
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, output_dir ))
|
||||||
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, visualhaar_lib))
|
||||||
|
|
||||||
p1.start()
|
p1.start()
|
||||||
p2.start()
|
p2.start()
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
from PIL import ImageFont, ImageDraw, Image
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
text_to_show = "The quick brown fox jumps over the lazy dog"
|
||||||
|
|
||||||
|
# Load image in OpenCV
|
||||||
|
image = cv2.imread("Me.jpg")
|
||||||
|
|
||||||
|
# Convert the image to RGB (OpenCV uses BGR)
|
||||||
|
cv2_im_rgb = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
|
||||||
|
|
||||||
|
# Pass the image to PIL
|
||||||
|
pil_im = Image.fromarray(cv2_im_rgb)
|
||||||
|
|
||||||
|
draw = ImageDraw.Draw(pil_im)
|
||||||
|
|
||||||
|
# Draw the text
|
||||||
|
draw.text((10, 700), text_to_show, font=font)
|
||||||
|
|
||||||
|
# Get back the image to OpenCV
|
||||||
|
cv2_im_processed = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
||||||
|
|
||||||
|
cv2.imshow('Fonts', cv2_im_processed)
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
|
cv2.destroyAllWindows()
|
||||||
|
|
||||||
|
def get_font(filename, size):
|
||||||
|
return ImageFont.truetype(filename, size)
|
||||||
|
|
||||||
|
def draw_text(img, ):
|
23
mirror.py
23
mirror.py
|
@ -1,22 +1,27 @@
|
||||||
import argparse
|
import argparse
|
||||||
import face_recognition.comparison
|
import face_recognition.comparison
|
||||||
import cv2
|
import cv2
|
||||||
|
from multiprocessing import freeze_support
|
||||||
|
import os
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser(description='Visualise face recognition algorithms.')
|
freeze_support() # support pyinstaller on Windows
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Visualise face recognition algorithms.', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
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',
|
parser.add_argument('--windowed', '-w', action='store_true',
|
||||||
help='Display output full screen')
|
help='Display output windowed instead of fullscreen')
|
||||||
parser.add_argument('--clockwise', action='store_true',
|
parser.add_argument('--clockwise', action='store_true',
|
||||||
help='Rotate clockwise')
|
help='Rotate clockwise')
|
||||||
parser.add_argument('--counter-clockwise', action='store_true',
|
parser.add_argument('--counter-clockwise', action='store_true',
|
||||||
help='Rotate counter clockwise')
|
help='Rotate counter clockwise')
|
||||||
parser.add_argument('--cascade', default='haarcascade_frontalface_alt2.xml',
|
parser.add_argument('--cascade', default=os.path.join(os.path.dirname(os.path.realpath(__file__)),'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',
|
parser.add_argument('--output', metavar="DIRECTORY", default=os.path.expanduser("~/Desktop/faces"),
|
||||||
help='Directory to store images (after pressing spacebar)')
|
help='Directory to store images (after pressing spacebar)')
|
||||||
|
parser.add_argument('--visualhaar-lib', metavar="LIBRARY", default=None,
|
||||||
|
help='path/filename for visualhaar library (.so on linux, .dll on windows)\nSee: https://git.rubenvandeven.com/r/visualhaar/releases')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
@ -26,4 +31,8 @@ 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)
|
if not os.path.exists(args.output):
|
||||||
|
print("Making directory:", args.output)
|
||||||
|
os.mkdir(args.output)
|
||||||
|
|
||||||
|
face_recognition.comparison.main(args.camera, rotate, not args.windowed, args.cascade, args.output, args.visualhaar_lib)
|
||||||
|
|
|
@ -1,7 +1,25 @@
|
||||||
scipy
|
altgraph==0.17
|
||||||
numpy
|
cffi==1.14.4
|
||||||
dlib
|
cycler==0.10.0
|
||||||
Pillow
|
decorator==4.4.2
|
||||||
opencv-python
|
dlib==19.21.1
|
||||||
cffi
|
future==0.18.2
|
||||||
scikit-image
|
imageio==2.9.0
|
||||||
|
kiwisolver==1.3.1
|
||||||
|
matplotlib==3.3.3
|
||||||
|
networkx==2.5
|
||||||
|
numpy==1.19.3
|
||||||
|
opencv-python==4.5.1.48
|
||||||
|
pefile==2019.4.18
|
||||||
|
Pillow==8.1.0
|
||||||
|
pycparser==2.20
|
||||||
|
pyinstaller==4.1
|
||||||
|
pyinstaller-hooks-contrib==2020.11
|
||||||
|
pyparsing==2.4.7
|
||||||
|
python-dateutil==2.8.1
|
||||||
|
PyWavelets==1.1.1
|
||||||
|
pywin32-ctypes==0.2.0
|
||||||
|
scikit-image==0.18.1
|
||||||
|
scipy==1.6.0
|
||||||
|
six==1.15.0
|
||||||
|
tifffile==2020.12.8
|
|
@ -1 +1 @@
|
||||||
Subproject commit ac1aea1d68f346be194e64a3275629a177327f2e
|
Subproject commit 1319e644b1f59debe46be866d18209d2a6089e1b
|
Loading…
Reference in New Issue