11import sensor
22import image
33import utime
4+ import math
45
56class face_detection :
67 def __init__ (self , config , comms ):
@@ -9,6 +10,8 @@ def __init__(self, config, comms):
910 self .has_face = False
1011 self .face_cascade = image .HaarCascade ("frontalface" , stages = self .config .get ('FaceStages' ))
1112 self .face_object = [0 , 0 , 1 , 1 ]
13+ self .face_angle = 0
14+ self .correct_angle = False
1215
1316 self .extra_fb = sensor .alloc_extra_fb (sensor .width (), sensor .height (), sensor .GRAYSCALE )
1417
@@ -19,21 +22,31 @@ def detect(self, img):
1922 return
2023
2124 now = utime .ticks_ms ()
25+ self .face_angle = 0
2226 face_objects = img .find_features (self .face_cascade , threshold = self .config .get ('FaceThreshold' ), scale_factor = self .config .get ('FaceScaleFactor' ))
2327
2428 if len (face_objects ) == 0 and self .config .get ('FaceAngles' ):
2529 for angle in self .config .get ('FaceAngles' ):
2630 self .extra_fb .replace (img )
2731 self .extra_fb .rotation_corr (x_rotation = 0.0 , y_rotation = 0.0 , z_rotation = angle )
32+
2833 face_objects = self .extra_fb .find_features (self .face_cascade , threshold = self .config .get ('FaceThreshold' ), scale_factor = self .config .get ('FaceScaleFactor' ))
2934 if face_objects :
35+ self .face_angle = angle
3036 break
3137
3238 if face_objects :
3339 self .face_object = face_objects [0 ]
3440 self .has_face = True
3541 if self .config .get ('TrackEyes' ):
3642 self .face_object = [self .face_object [0 ], self .face_object [1 ] + int (self .face_object [3 ] * 1 / 5 ), self .face_object [2 ], int (self .face_object [3 ] * 2 / 5 )]
43+
44+ if self .correct_angle :
45+ eyes_x = self .face_object [0 ] + int (self .face_object [2 ] * 1 / 5 )
46+ eyes_y = self .face_object [1 ] + int (self .face_object [3 ] * 1 / 5 )
47+ eyes_width = self .face_object [2 ] - int (self .face_object [2 ] * 1 / 5 )
48+ eyes_height = int (self .face_object [3 ] * 2 / 5 )
49+ self .face_object = [eyes_x , eyes_y , eyes_width , eyes_height ]
3750 else :
3851 self .face_object = [0 , 0 , img .width (), img .height ()]
3952 self .has_face = False
@@ -45,7 +58,39 @@ def draw_region(self, img):
4558 if self .face_object [2 ] == img .width ():
4659 return
4760
48- if self .config .get ('PixelFormat' ) == 'RGB565' :
49- img .draw_rectangle (self .face_object , color = (70 , 130 , 180 ))
50- else :
51- img .draw_rectangle (self .face_object )
61+ img .draw_rectangle (self .face_object , color = (70 , 130 , 180 ))
62+
63+ if self .correct_angle :
64+ face_x = self .face_object [0 ]
65+ face_y = self .face_object [1 ]
66+ face_width = self .face_object [2 ]
67+ face_height = self .face_object [3 ]
68+
69+ theta = math .radians (self .face_angle * - 1 )
70+ offset = (0 , 0 )
71+
72+ rect = [
73+ (face_x , face_y ),
74+ (face_x , face_y + face_height ),
75+ (face_x + face_width , face_y + face_height ),
76+ (face_x + face_width , face_y )
77+ ]
78+
79+ rotated_rect = [translate (rotate (xy , theta ), offset ) for xy in rect ]
80+
81+ img .draw_line ((rotated_rect [0 ][0 ], rotated_rect [0 ][1 ], rotated_rect [1 ][0 ], rotated_rect [1 ][1 ]), color = (220 , 220 , 0 ))
82+ img .draw_line ((rotated_rect [1 ][0 ], rotated_rect [1 ][1 ], rotated_rect [2 ][0 ], rotated_rect [2 ][1 ]), color = (220 , 220 , 0 ))
83+ img .draw_line ((rotated_rect [2 ][0 ], rotated_rect [2 ][1 ], rotated_rect [3 ][0 ], rotated_rect [3 ][1 ]), color = (220 , 220 , 0 ))
84+ img .draw_line ((rotated_rect [3 ][0 ], rotated_rect [3 ][1 ], rotated_rect [0 ][0 ], rotated_rect [0 ][1 ]), color = (220 , 220 , 0 ))
85+ img .draw_string (face_x , face_y + face_height - 10 , str (self .face_angle ) + "^" , color = (70 , 130 , 180 ), mono_space = False )
86+
87+ def rotate (xy , theta ):
88+ cos_theta , sin_theta = math .cos (theta ), math .sin (theta )
89+
90+ return (
91+ int (xy [0 ] * cos_theta - xy [1 ] * sin_theta ),
92+ int (xy [0 ] * sin_theta + xy [1 ] * cos_theta )
93+ )
94+
95+ def translate (xy , offset ):
96+ return xy [0 ] + offset [0 ], xy [1 ] + offset [1 ]
0 commit comments