@@ -7,6 +7,7 @@ const Image = zignal.Image;
7
7
const SimilarityTransform = zignal .SimilarityTransform (f32 );
8
8
const Rectangle = zignal .Rectangle (f32 );
9
9
const Rgba = zignal .Rgba ;
10
+ const Hsv = zignal .Hsv ;
10
11
const drawRectangle = zignal .drawRectangle ;
11
12
12
13
pub const std_options : std.Options = .{
@@ -36,7 +37,7 @@ pub fn extractAlignedFace(
36
37
blurring : i32 ,
37
38
out : * Image (T ),
38
39
) ! void {
39
- // This are the normalized coordinates of the aligned landmarks
40
+ // These are the normalized coordinates of the aligned landmarks
40
41
// taken from dlib.
41
42
var from_points : [5 ]Point2d = .{
42
43
.{ .x = 0.8595674595992 , .y = 0.2134981538014 },
@@ -46,6 +47,7 @@ pub fn extractAlignedFace(
46
47
.{ .x = 0.4901123135679 , .y = 0.6277975316475 },
47
48
};
48
49
50
+ // These are the detected points from MediaPipe.
49
51
const to_points : [5 ]Point2d = .{
50
52
landmarks [alignment [0 ]].scale (image .cols , image .rows ),
51
53
landmarks [alignment [1 ]].scale (image .cols , image .rows ),
@@ -61,30 +63,43 @@ pub fn extractAlignedFace(
61
63
p .x = (padding + p .x ) / (2 * padding + 1 ) * side ;
62
64
p .y = (padding + p .y ) / (2 * padding + 1 ) * side ;
63
65
}
66
+
67
+ // Find the transforms that maps the points between the canonical landmarks
68
+ // and the detected landmarks.
64
69
const transform = SimilarityTransform .find (& from_points , & to_points );
65
70
var p = transform .project (.{ .x = 1 , .y = 0 });
66
71
p .x -= transform .bias .at (0 , 0 );
67
72
p .y -= transform .bias .at (1 , 0 );
68
73
const angle = std .math .atan2 (p .y , p .x );
69
74
const scale = p .norm ();
70
75
const center = transform .project (.{ .x = side / 2 , .y = side / 2 });
76
+
77
+ // Align the face: rotate the image so that the face is aligned.
71
78
var rotated : Image (Rgba ) = undefined ;
72
79
try image .rotateFrom (allocator , center , angle , & rotated );
73
80
defer rotated .deinit (allocator );
74
81
82
+ // Get the rectangle around the face.
75
83
const rect = Rectangle .initCenter (center .x , center .y , side * scale , side * scale );
76
- drawRectangle (Rgba , image , rect , 1 , .{ .r = 0 , .g = 0 , .b = 0 , .a = 255 });
84
+ // Draw a rectangle around the detected face. Note that the color can be any Zignal
85
+ // supported color, and the appropriate conversion will be performed. In this case,
86
+ // the image is in Rgba format, and the color is in Hsv. Zignal will handle that.
87
+ drawRectangle (Rgba , image , rect , 1 , Hsv { .h = 0 , .s = 100 , .v = 100 });
88
+
89
+ // Crop out the detected face.
77
90
var chip : Image (Rgba ) = undefined ;
78
91
try rotated .crop (allocator , rect , & chip );
79
92
defer chip .deinit (allocator );
80
93
94
+ // Resize it to the desired size.
81
95
var resized = try Image (Rgba ).initAlloc (allocator , out .rows , out .cols );
82
96
defer resized .deinit (allocator );
83
97
chip .resize (& resized );
84
98
for (out .data , resized .data ) | * c , b | {
85
99
c .* = b ;
86
100
}
87
101
102
+ // Perform blurring or sharpening to the aligned face.
88
103
if (blurring > 0 ) {
89
104
try out .boxBlur (allocator , out , @intCast (blurring ));
90
105
} else if (blurring < 0 ) {
0 commit comments