Skip to content

Commit 08d7cad

Browse files
committed
it seems the detections do not come through even for BlazeFace if there are no detections
1 parent 60cc906 commit 08d7cad

3 files changed

Lines changed: 82 additions & 8 deletions

File tree

mediapipe/examples/ios/facemeshioslib/FaceMeshIOSLib.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,30 @@
99
@property (nonatomic) float z;
1010
@end
1111

12+
@interface FaceMeshIOSLibNormalizedRect : NSObject
13+
@property (nonatomic) float centerX;
14+
@property (nonatomic) float centerY;
15+
@property (nonatomic) float height;
16+
@property (nonatomic) float width;
17+
@property (nonatomic) float rotation;
18+
@end
19+
1220
@protocol FaceMeshIOSLibDelegate <NSObject>
1321
@optional
14-
/** Array of faces, with faces represented by arrays of face landmarks */
22+
/** Array of faces, with faces represented by arrays of face landmarks
23+
* This does not always get called. If there are no faces detected by the Face Detector (Short Range) model,
24+
* then this does not get called
25+
*/
1526
- (void)didReceiveFaces:(NSArray <NSArray<FaceMeshIOSLibFaceLandmarkPoint *>*>*)faces;
27+
/** Array of faces, with faces represented by arrays of face landmarks
28+
* This does not always get called. If there are no faces detected by the Face Detector (Short Range) model,
29+
* then this does not get called
30+
*/
31+
- (void)didReceiveFaceBoxes:(NSArray <FaceMeshIOSLibNormalizedRect *>*)faces;
32+
/** Array of faces, with faces represented by arrays of face landmarks
33+
* This is the result called by the Face Detection (Short Range) model (a.k.a. BlazeFace)
34+
*/
35+
- (void)didReceiveFaceDetections:(NSArray <FaceMeshIOSLibNormalizedRect *>*)faces;
1636
@end
1737

1838
@interface FaceMeshIOSLib : NSObject

mediapipe/examples/ios/facemeshioslib/FaceMeshIOSLib.mm

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
static const char* kNumFacesInputSidePacket = "num_faces";
2121
static const char* kLandmarksOutputStream = "multi_face_landmarks";
2222
static const char* kFaceRectsOutputStream = "face_rects_from_landmarks";
23+
static const char* kFaceDetectionRectsOutputStream = "face_rects_from_detections";
2324

2425
// Max number of faces to detect/process.
2526
static const int kNumFaces = 1;
@@ -68,8 +69,17 @@ + (MPPGraph*)loadGraphFromResource:(NSString*)resource {
6869
// Set graph configurations
6970
[newGraph setSidePacket:(mediapipe::MakePacket<int>(kNumFaces))
7071
named:kNumFacesInputSidePacket];
72+
// The landmarks output stream.
73+
// !! This output does *not* give out any output when there are no faces detected by the face detector!
7174
[newGraph addFrameOutputStream:kLandmarksOutputStream
7275
outputPacketType:MPPPacketTypeRaw];
76+
77+
[newGraph addFrameOutputStream:kFaceRectsOutputStream
78+
outputPacketType:MPPPacketTypeRaw];
79+
// The face detections rect output stream
80+
// This is kind of almost direct from blazeface I think, so it's likely out every frame.
81+
// [newGraph addFrameOutputStream:kFaceDetectionRectsOutputStream
82+
// outputPacketType:MPPPacketTypeRaw];
7383
return newGraph;
7484
}
7585

@@ -140,10 +150,6 @@ - (void)mediapipeGraph:(MPPGraph*)graph
140150
fromStream:(const std::string&)streamName {
141151
if (streamName == kLandmarksOutputStream) {
142152
if (packet.IsEmpty()) {
143-
NSLog(@"[TS:%lld] No face landmarks", packet.Timestamp().Value());
144-
if([self.delegate respondsToSelector:@selector(didReceiveFaces:)]) {
145-
[self.delegate didReceiveFaces:@[]];
146-
}
147153
return;
148154
}
149155
const auto& multi_face_landmarks = packet.Get<std::vector<::mediapipe::NormalizedLandmarkList>>();
@@ -170,20 +176,55 @@ - (void)mediapipeGraph:(MPPGraph*)graph
170176
[self.delegate didReceiveFaces:faceLandmarks];
171177
}
172178
}
179+
else if (streamName == kFaceDetectionRectsOutputStream) {
180+
if (packet.IsEmpty()) {
181+
NSLog(@"[TS:%lld] No face detections", packet.Timestamp().Value());
182+
if([self.delegate respondsToSelector:@selector(didReceiveFaces:)]) {
183+
[self.delegate didReceiveFaceBoxes:@[]];
184+
}
185+
return;
186+
}
187+
const auto& face_rects_from_landmarks = packet.Get<std::vector<::mediapipe::NormalizedRect>>();
188+
NSMutableArray <FaceMeshIOSLibNormalizedRect *>*outRects = [NSMutableArray new];
189+
for (int face_index = 0; face_index < face_rects_from_landmarks.size(); ++face_index) {
190+
const auto& face = face_rects_from_landmarks[face_index];
191+
float centerX = face.x_center();
192+
float centerY = face.y_center();
193+
float height = face.height();
194+
float width = face.width();
195+
float rotation = face.rotation();
196+
FaceMeshIOSLibNormalizedRect *rect = [FaceMeshIOSLibNormalizedRect new];
197+
rect.centerX = centerX; rect.centerY = centerY; rect.height = height; rect.width = width; rect.rotation = rotation;
198+
[outRects addObject:rect];
199+
}
200+
if([self.delegate respondsToSelector:@selector(didReceiveFaceDetections:)]) {
201+
[self.delegate didReceiveFaceDetections:outRects];
202+
}
203+
}
173204
else if (streamName == kFaceRectsOutputStream) {
174205
if (packet.IsEmpty()) {
206+
NSLog(@"[TS:%lld] No face rects", packet.Timestamp().Value());
207+
if([self.delegate respondsToSelector:@selector(didReceiveFaces:)]) {
208+
[self.delegate didReceiveFaceBoxes:@[]];
209+
}
175210
return;
176211
}
177212
const auto& face_rects_from_landmarks = packet.Get<std::vector<::mediapipe::NormalizedRect>>();
213+
NSMutableArray <FaceMeshIOSLibNormalizedRect *>*outRects = [NSMutableArray new];
178214
for (int face_index = 0; face_index < face_rects_from_landmarks.size(); ++face_index) {
179215
const auto& face = face_rects_from_landmarks[face_index];
180216
float centerX = face.x_center();
181217
float centerY = face.y_center();
182218
float height = face.height();
183219
float width = face.width();
184220
float rotation = face.rotation();
221+
FaceMeshIOSLibNormalizedRect *rect = [FaceMeshIOSLibNormalizedRect new];
222+
rect.centerX = centerX; rect.centerY = centerY; rect.height = height; rect.width = width; rect.rotation = rotation;
223+
[outRects addObject:rect];
224+
}
225+
if([self.delegate respondsToSelector:@selector(didReceiveFaceBoxes:)]) {
226+
[self.delegate didReceiveFaceBoxes:outRects];
185227
}
186-
// TODO: MAYBE MAKE A DELEGATE METHOD HERE.
187228
}
188229
}
189230

@@ -212,3 +253,6 @@ - (void)processVideoFrame:(CVPixelBufferRef)imageBuffer {
212253

213254
@implementation FaceMeshIOSLibFaceLandmarkPoint
214255
@end
256+
257+
@implementation FaceMeshIOSLibNormalizedRect
258+
@end

mediapipe/graphs/face_mesh/pure_face_mesh_mobile.pbtxt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ output_stream: "multi_face_landmarks"
2121
# For typings see "mediapipe/framework/formats/rect.pb.h"
2222
output_stream: "face_rects_from_landmarks"
2323

24+
# The detections from the box model
25+
# see detection.proto
26+
# Regions of interest calculated based on face detections.
27+
# (std::vector<NormalizedRect>)
28+
output_stream: "face_rects_from_detections"
29+
2430
# There's also face_rects_from_detections, but that likely isn't as accurate (it's from BlazeFace)
2531

2632

@@ -35,8 +41,12 @@ node {
3541
input_side_packet: "NUM_FACES:num_faces"
3642
output_stream: "LANDMARKS:multi_face_landmarks"
3743
output_stream: "ROIS_FROM_LANDMARKS:face_rects_from_landmarks"
38-
# output_stream: "DETECTIONS:face_detections"
39-
# output_stream: "ROIS_FROM_DETECTIONS:face_rects_from_detections"
44+
# face_detections is the stream that comes out from face_detection_short_range_common
45+
# output_stream: "DETECTIONS:face_detections"
46+
47+
# we need to output this too because otherwise the graph outputs nothing
48+
# for frames without faces, and that makes it pretty hard to use
49+
output_stream: "ROIS_FROM_DETECTIONS:face_rects_from_detections"
4050
}
4151

4252
# nope not rendering.

0 commit comments

Comments
 (0)