77// NormalizedLandmarkList won't be defined unless we import this header (following FaceMeshGpuViewController's imports)
88#include " mediapipe/framework/formats/landmark.pb.h"
99#include " mediapipe/framework/formats/rect.pb.h"
10+ #include " mediapipe/framework/formats/detection.pb.h"
1011
1112// #import "mediapipe/objc/MPPLayerRenderer.h"
1213
2021static const char * kNumFacesInputSidePacket = " num_faces" ;
2122static const char * kLandmarksOutputStream = " multi_face_landmarks" ;
2223static const char * kFaceRectsOutputStream = " face_rects_from_landmarks" ;
23- static const char * kFaceDetectionRectsOutputStream = " face_rects_from_detections" ;
24+ static const char * kLandmarkPresenceOutputStream = " landmark_presence" ;
25+ // static const char* kFaceDetectionRectsOutputStream = "face_rects_from_detections";
26+ // static const char* kFaceDetectionsRawDetectionsOutputStream = "face_detections";
2427
2528// Max number of faces to detect/process.
2629static const int kNumFaces = 1 ;
@@ -78,8 +81,14 @@ + (MPPGraph*)loadGraphFromResource:(NSString*)resource {
7881 outputPacketType: MPPPacketTypeRaw];
7982 // The face detections rect output stream
8083 // This is kind of almost direct from blazeface I think, so it's likely out every frame.
84+ // Turns out this doesn't come out at all... what the heck
8185 // [newGraph addFrameOutputStream:kFaceDetectionRectsOutputStream
8286 // outputPacketType:MPPPacketTypeRaw];
87+
88+ // The Presence Detection stream
89+ // This is with much much many many thanks to @homuler here: https://github.com/google/mediapipe/issues/850#issuecomment-683268033
90+ [newGraph addFrameOutputStream: kLandmarkPresenceOutputStream
91+ outputPacketType: MPPPacketTypeRaw];
8392 return newGraph;
8493}
8594
@@ -149,12 +158,12 @@ - (void)mediapipeGraph:(MPPGraph*)graph
149158 didOutputPacket : (const ::mediapipe::Packet&)packet
150159 fromStream : (const std::string&)streamName {
151160 if (streamName == kLandmarksOutputStream ) {
152- if (packet.IsEmpty ()) {
161+ if (packet.IsEmpty ()) { // This condition never gets called because FaceLandmarkFrontGpu does not process when there are no detections
153162 return ;
154163 }
155164 const auto & multi_face_landmarks = packet.Get <std::vector<::mediapipe::NormalizedLandmarkList>>();
156- NSLog (@" [TS:%lld ] Number of face instances with landmarks: %lu " , packet.Timestamp().Value(),
157- multi_face_landmarks.size());
165+ // NSLog(@"[TS:%lld] Number of face instances with landmarks: %lu", packet.Timestamp().Value(),
166+ // multi_face_landmarks.size());
158167 NSMutableArray <NSArray <FaceMeshIOSLibFaceLandmarkPoint *>*>*faceLandmarks = [NSMutableArray new ];
159168
160169 for (int face_index = 0 ; face_index < multi_face_landmarks.size (); ++face_index) {
@@ -176,10 +185,11 @@ - (void)mediapipeGraph:(MPPGraph*)graph
176185 [self .delegate didReceiveFaces: faceLandmarks];
177186 }
178187 }
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: )]) {
188+
189+ else if (streamName == kFaceRectsOutputStream ) {
190+ if (packet.IsEmpty ()) { // This condition never gets called because FaceLandmarkFrontGpu does not process when there are no detections
191+ // NSLog(@"[TS:%lld] No face rects", packet.Timestamp().Value());
192+ if ([self .delegate respondsToSelector: @selector (didReceiveFaceBoxes: )]) {
183193 [self .delegate didReceiveFaceBoxes: @[]];
184194 }
185195 return ;
@@ -197,35 +207,36 @@ - (void)mediapipeGraph:(MPPGraph*)graph
197207 rect.centerX = centerX; rect.centerY = centerY; rect.height = height; rect.width = width; rect.rotation = rotation;
198208 [outRects addObject: rect];
199209 }
200- if ([self .delegate respondsToSelector: @selector (didReceiveFaceDetections : )]) {
201- [self .delegate didReceiveFaceDetections : outRects];
210+ if ([self .delegate respondsToSelector: @selector (didReceiveFaceBoxes : )]) {
211+ [self .delegate didReceiveFaceBoxes : outRects];
202212 }
203213 }
204- else if (streamName == kFaceRectsOutputStream ) {
214+ else if (streamName == kLandmarkPresenceOutputStream ) {
215+ bool is_landmark_present = true ;
205216 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- }
210- return ;
217+ is_landmark_present = false ;
211218 }
212- const auto & face_rects_from_landmarks = packet.Get <std::vector<::mediapipe::NormalizedRect>>();
213- NSMutableArray <FaceMeshIOSLibNormalizedRect *>*outRects = [NSMutableArray new ];
214- for (int face_index = 0 ; face_index < face_rects_from_landmarks.size (); ++face_index) {
215- const auto & face = face_rects_from_landmarks[face_index];
216- float centerX = face.x_center ();
217- float centerY = face.y_center ();
218- float height = face.height ();
219- float width = face.width ();
220- 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];
219+ else {
220+ is_landmark_present = packet.Get <bool >();
224221 }
225- if ([self .delegate respondsToSelector: @selector (didReceiveFaceBoxes: )]) {
226- [self .delegate didReceiveFaceBoxes: outRects];
222+ if (is_landmark_present) {
223+ // NSLog(@"Landmarks present");
224+ // Landmarks are present; no need to do anything (the rest of the callbacks will get called on their own)
225+ }
226+ else {
227+ // NSLog(@"Landmarks not present");
228+ // No landmarks are present, we call our delegate with empty faces to make our protocol consistent with number of frames
229+ if ([self .delegate respondsToSelector: @selector (didReceiveFaceBoxes: )]) {
230+ [self .delegate didReceiveFaceBoxes: @[]];
231+ }
232+ if ([self .delegate respondsToSelector: @selector (didReceiveFaces: )]) {
233+ [self .delegate didReceiveFaces: @[]];
234+ }
227235 }
228236 }
237+ else {
238+ NSLog (@" Unknown %@ packet with stream name %s " , packet.IsEmpty() ? @"EMPTY" : @"NON-EMPTY",streamName.c_str());
239+ }
229240}
230241
231242
@@ -235,14 +246,14 @@ - (void)processVideoFrame:(CVPixelBufferRef)imageBuffer {
235246 const auto ts =
236247 mediapipe::Timestamp (self.timestamp ++ * mediapipe::Timestamp::kTimestampUnitsPerSecond );
237248 NSError * err = nil ;
238- NSLog (@" sending imageBuffer @%@ to %s " , @(ts.DebugString().c_str()), kInputStream);
249+ // NSLog(@"sending imageBuffer @%@ to %s", @(ts.DebugString().c_str()), kInputStream);
239250 auto sent = [self .mediapipeGraph sendPixelBuffer: imageBuffer
240251 intoStream: kInputStream
241252 packetType: MPPPacketTypePixelBuffer
242253 timestamp: ts
243254 allowOverwrite: NO
244255 error: &err];
245- NSLog (@" imageBuffer %s " , sent ? " sent!" : " not sent." );
256+ // NSLog(@"imageBuffer %s", sent ? "sent!" : "not sent.");
246257 if (err) {
247258 NSLog (@" sendPixelBuffer error: %@ " , err);
248259 }
0 commit comments