From 1d0f3734b4a0c45c623a72c8f7cbce680ad3ccfa Mon Sep 17 00:00:00 2001 From: Prianka Liz Kariat Date: Tue, 7 Nov 2023 09:46:39 +0530 Subject: [PATCH 1/3] Added iOS MPPPoseLandmarker.mm --- .../tasks/ios/vision/pose_landmarker/BUILD | 14 ++ .../sources/MPPPoseLandmarker.mm | 222 ++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 mediapipe/tasks/ios/vision/pose_landmarker/sources/MPPPoseLandmarker.mm diff --git a/mediapipe/tasks/ios/vision/pose_landmarker/BUILD b/mediapipe/tasks/ios/vision/pose_landmarker/BUILD index a7b612bce..97cb278d9 100644 --- a/mediapipe/tasks/ios/vision/pose_landmarker/BUILD +++ b/mediapipe/tasks/ios/vision/pose_landmarker/BUILD @@ -47,13 +47,27 @@ objc_library( objc_library( name = "MPPPoseLandmarker", + srcs = ["sources/MPPPoseLandmarker.mm"], hdrs = ["sources/MPPPoseLandmarker.h"], + copts = [ + "-ObjC++", + "-std=c++17", + "-x objective-c++", + ], module_name = "MPPPoseLandmarker", deps = [ ":MPPPoseLandmarkerOptions", ":MPPPoseLandmarkerResult", ":MPPPoseLandmarksConnections", + "//mediapipe/tasks/cc/vision/pose_landmarker:pose_landmarker_graph", + "//mediapipe/tasks/ios/common/utils:MPPCommonUtils", + "//mediapipe/tasks/ios/common/utils:NSStringHelpers", "//mediapipe/tasks/ios/components/containers:MPPConnection", + "//mediapipe/tasks/ios/core:MPPTaskInfo", "//mediapipe/tasks/ios/vision/core:MPPImage", + "//mediapipe/tasks/ios/vision/core:MPPVisionPacketCreator", + "//mediapipe/tasks/ios/vision/core:MPPVisionTaskRunner", + "//mediapipe/tasks/ios/vision/pose_landmarker/utils:MPPPoseLandmarkerOptionsHelpers", + "//mediapipe/tasks/ios/vision/pose_landmarker/utils:MPPPoseLandmarkerResultHelpers", ], ) diff --git a/mediapipe/tasks/ios/vision/pose_landmarker/sources/MPPPoseLandmarker.mm b/mediapipe/tasks/ios/vision/pose_landmarker/sources/MPPPoseLandmarker.mm new file mode 100644 index 000000000..815578500 --- /dev/null +++ b/mediapipe/tasks/ios/vision/pose_landmarker/sources/MPPPoseLandmarker.mm @@ -0,0 +1,222 @@ +// Copyright 2023 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "mediapipe/tasks/ios/vision/pose_landmarker/sources/MPPPoseLandmarker.h" + +#import "mediapipe/tasks/ios/common/utils/sources/MPPCommonUtils.h" +#import "mediapipe/tasks/ios/common/utils/sources/NSString+Helpers.h" +#import "mediapipe/tasks/ios/core/sources/MPPTaskInfo.h" +#import "mediapipe/tasks/ios/vision/core/sources/MPPVisionPacketCreator.h" +#import "mediapipe/tasks/ios/vision/core/sources/MPPVisionTaskRunner.h" +#import "mediapipe/tasks/ios/vision/pose_landmarker/sources/MPPPoseLandmarksConnections.h" +#import "mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerOptions+Helpers.h" +#import "mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.h" + +namespace { +using ::mediapipe::NormalizedRect; +using ::mediapipe::Packet; +using ::mediapipe::Timestamp; +using ::mediapipe::tasks::core::PacketMap; +using ::mediapipe::tasks::core::PacketsCallback; +} // namespace + +static NSString *const kImageTag = @"IMAGE"; +static NSString *const kImageInStreamName = @"image_in"; +static NSString *const kNormRectTag = @"NORM_RECT"; +static NSString *const kNormRectInStreamName = @"norm_rect_in"; +static NSString *const kImageOutStreamName = @"image_out"; +static NSString *const kPoseLandmarksTag = @"NORM_LANDMARKS"; +static NSString *const kPoseLandmarksOutStreamName = @"pose_landmarks"; +static NSString *const kWorldLandmarksTag = @"WORLD_LANDMARKS"; +static NSString *const kWorldLandmarksOutStreamName = @"world_landmarks"; +static NSString *const kSegmentationMasksTag = @"SEGMENTATION_MASK"; +static NSString *const kSegmentationMasksOutStreamName = @"segmentation_masks"; +static NSString *const kTaskGraphName = + @"mediapipe.tasks.vision.pose_landmarker.PoseLandmarkerGraph"; +static NSString *const kTaskName = @"poseLandmarker"; + +#define InputPacketMap(imagePacket, normalizedRectPacket) \ + { \ + {kImageInStreamName.cppString, imagePacket}, { \ + kNormRectInStreamName.cppString, normalizedRectPacket \ + } \ + } + +#define PoseLandmarkerResultWithOutputPacketMap(outputPacketMap) \ + ([MPPPoseLandmarkerResult \ + poseLandmarkerResultWithLandmarksPacket:outputPacketMap[kPoseLandmarksOutStreamName \ + .cppString] \ + worldLandmarksPacket:outputPacketMap[kWorldLandmarksOutStreamName \ + .cppString] \ + segmentationMasksPacket:&(outputPacketMap[kSegmentationMasksOutStreamName \ + .cppString])]) + +@interface MPPPoseLandmarker () { + /** iOS Vision Task Runner */ + MPPVisionTaskRunner *_visionTaskRunner; + dispatch_queue_t _callbackQueue; +} +@property(nonatomic, weak) id poseLandmarkerLiveStreamDelegate; +@end + +@implementation MPPPoseLandmarker + +#pragma mark - Public + +- (instancetype)initWithOptions:(MPPPoseLandmarkerOptions *)options error:(NSError **)error { + self = [super init]; + if (self) { + MPPTaskInfo *taskInfo = [[MPPTaskInfo alloc] + initWithTaskGraphName:kTaskGraphName + inputStreams:@[ + [NSString stringWithFormat:@"%@:%@", kImageTag, kImageInStreamName], + [NSString stringWithFormat:@"%@:%@", kNormRectTag, kNormRectInStreamName] + ] + outputStreams:@[ + [NSString + stringWithFormat:@"%@:%@", kPoseLandmarksTag, kPoseLandmarksOutStreamName], + [NSString + stringWithFormat:@"%@:%@", kWorldLandmarksTag, kWorldLandmarksOutStreamName], + [NSString stringWithFormat:@"%@:%@", kSegmentationMasksTag, + kSegmentationMasksOutStreamName], + [NSString stringWithFormat:@"%@:%@", kImageTag, kImageOutStreamName] + ] + taskOptions:options + enableFlowLimiting:options.runningMode == MPPRunningModeLiveStream + error:error]; + + if (!taskInfo) { + return nil; + } + + PacketsCallback packetsCallback = nullptr; + + if (options.poseLandmarkerLiveStreamDelegate) { + _poseLandmarkerLiveStreamDelegate = options.poseLandmarkerLiveStreamDelegate; + + // Create a private serial dispatch queue in which the deleagte method will be called + // asynchronously. This is to ensure that if the client performs a long running operation in + // the delegate method, the queue on which the C++ callbacks is invoked is not blocked and is + // freed up to continue with its operations. + _callbackQueue = dispatch_queue_create( + [MPPVisionTaskRunner uniqueDispatchQueueNameWithSuffix:kTaskName], NULL); + + // Capturing `self` as weak in order to avoid `self` being kept in memory + // and cause a retain cycle, after self is set to `nil`. + MPPPoseLandmarker *__weak weakSelf = self; + packetsCallback = [=](absl::StatusOr liveStreamResult) { + [weakSelf processLiveStreamResult:liveStreamResult]; + }; + } + + _visionTaskRunner = [[MPPVisionTaskRunner alloc] initWithTaskInfo:taskInfo + runningMode:options.runningMode + roiAllowed:NO + packetsCallback:std::move(packetsCallback) + imageInputStreamName:kImageInStreamName + normRectInputStreamName:kNormRectInStreamName + error:error]; + + if (!_visionTaskRunner) { + return nil; + } + } + return self; +} + +- (instancetype)initWithModelPath:(NSString *)modelPath error:(NSError **)error { + MPPPoseLandmarkerOptions *options = [[MPPPoseLandmarkerOptions alloc] init]; + + options.baseOptions.modelAssetPath = modelPath; + + return [self initWithOptions:options error:error]; +} + +- (nullable MPPPoseLandmarkerResult *)detectImage:(MPPImage *)image error:(NSError **)error { + std::optional outputPacketMap = [_visionTaskRunner processImage:image error:error]; + + return [MPPPoseLandmarker poseLandmarkerResultWithOptionalOutputPacketMap:outputPacketMap]; +} + +- (nullable MPPPoseLandmarkerResult *)detectVideoFrame:(MPPImage *)image + timestampInMilliseconds:(NSInteger)timestampInMilliseconds + error:(NSError **)error { + std::optional outputPacketMap = + [_visionTaskRunner processVideoFrame:image + timestampInMilliseconds:timestampInMilliseconds + error:error]; + + return [MPPPoseLandmarker poseLandmarkerResultWithOptionalOutputPacketMap:outputPacketMap]; +} + +- (BOOL)detectAsyncImage:(MPPImage *)image + timestampInMilliseconds:(NSInteger)timestampInMilliseconds + error:(NSError **)error { + return [_visionTaskRunner processLiveStreamImage:image + timestampInMilliseconds:timestampInMilliseconds + error:error]; +} + ++ (NSArray *)poseLandmarks { + return MPPPoseLandmarksConnections; +} + +#pragma mark - Private + +- (void)processLiveStreamResult:(absl::StatusOr)liveStreamResult { + if (![self.poseLandmarkerLiveStreamDelegate + respondsToSelector:@selector(poseLandmarker: + didFinishDetectionWithResult:timestampInMilliseconds:error:)]) { + return; + } + + NSError *callbackError = nil; + if (![MPPCommonUtils checkCppError:liveStreamResult.status() toError:&callbackError]) { + dispatch_async(_callbackQueue, ^{ + [self.poseLandmarkerLiveStreamDelegate poseLandmarker:self + didFinishDetectionWithResult:nil + timestampInMilliseconds:Timestamp::Unset().Value() + error:callbackError]; + }); + return; + } + + PacketMap &outputPacketMap = liveStreamResult.value(); + if (outputPacketMap[kImageOutStreamName.cppString].IsEmpty()) { + return; + } + + MPPPoseLandmarkerResult *result = PoseLandmarkerResultWithOutputPacketMap(outputPacketMap); + + NSInteger timestampInMilliseconds = + outputPacketMap[kImageOutStreamName.cppString].Timestamp().Value() / + kMicroSecondsPerMillisecond; + dispatch_async(_callbackQueue, ^{ + [self.poseLandmarkerLiveStreamDelegate poseLandmarker:self + didFinishDetectionWithResult:result + timestampInMilliseconds:timestampInMilliseconds + error:callbackError]; + }); +} + ++ (nullable MPPPoseLandmarkerResult *)poseLandmarkerResultWithOptionalOutputPacketMap: + (std::optional &)outputPacketMap { + if (!outputPacketMap.has_value()) { + return nil; + } + + return PoseLandmarkerResultWithOutputPacketMap(outputPacketMap.value()); +} + +@end From 91095c2d6affa536b63fa0df88adb3862d4a54fb Mon Sep 17 00:00:00 2001 From: Prianka Liz Kariat Date: Tue, 7 Nov 2023 09:49:42 +0530 Subject: [PATCH 2/3] Added null check for segmentation masks in pose landmarker helper initializer --- .../sources/MPPPoseLandmarkerResult+Helpers.h | 4 ++- .../MPPPoseLandmarkerResult+Helpers.mm | 25 +++++++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.h b/mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.h index 0b20dc32a..83379f676 100644 --- a/mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.h +++ b/mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.h @@ -20,6 +20,8 @@ NS_ASSUME_NONNULL_BEGIN +static const int kMicroSecondsPerMillisecond = 1000; + @interface MPPPoseLandmarkerResult (Helpers) /** @@ -56,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN worldLandmarksProto: (const std::vector<::mediapipe::LandmarkList> &)worldLandmarksProto segmentationMasks:(const std::vector *)segmentationMasks - timestampInMilliSeconds:(NSInteger)timestampInMilliseconds; + timestampInMilliseconds:(NSInteger)timestampInMilliseconds; @end diff --git a/mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.mm b/mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.mm index 6cd67ff9c..c83365c86 100644 --- a/mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.mm +++ b/mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.mm @@ -21,8 +21,6 @@ using LandmarkListProto = ::mediapipe::LandmarkList; using NormalizedLandmarkListProto = ::mediapipe::NormalizedLandmarkList; using ::mediapipe::Image; using ::mediapipe::Packet; - -static const int kMicroSecondsPerMilliSecond = 1000; } // namespace @implementation MPPPoseLandmarkerResult (Helpers) @@ -41,7 +39,7 @@ static const int kMicroSecondsPerMilliSecond = 1000; worldLandmarksProto: (const std::vector &)worldLandmarksProto segmentationMasks:(const std::vector *)segmentationMasks - timestampInMilliSeconds:(NSInteger)timestampInMilliseconds { + timestampInMilliseconds:(NSInteger)timestampInMilliseconds { NSMutableArray *> *multiplePoseLandmarks = [NSMutableArray arrayWithCapacity:(NSUInteger)landmarksProto.size()]; @@ -69,6 +67,12 @@ static const int kMicroSecondsPerMilliSecond = 1000; [multiplePoseWorldLandmarks addObject:worldLandmarks]; } + if (!segmentationMasks) { + return [[MPPPoseLandmarkerResult alloc] initWithLandmarks:multiplePoseLandmarks + worldLandmarks:multiplePoseWorldLandmarks + segmentationMasks:nil + timestampInMilliseconds:timestampInMilliseconds]; + } NSMutableArray *confidenceMasks = [NSMutableArray arrayWithCapacity:(NSUInteger)segmentationMasks->size()]; @@ -83,12 +87,11 @@ static const int kMicroSecondsPerMilliSecond = 1000; shouldCopy:YES]]; } - MPPPoseLandmarkerResult *poseLandmarkerResult = - [[MPPPoseLandmarkerResult alloc] initWithLandmarks:multiplePoseLandmarks - worldLandmarks:multiplePoseWorldLandmarks - segmentationMasks:confidenceMasks - timestampInMilliseconds:timestampInMilliseconds]; - return poseLandmarkerResult; + return [[MPPPoseLandmarkerResult alloc] initWithLandmarks:multiplePoseLandmarks + worldLandmarks:multiplePoseWorldLandmarks + segmentationMasks:confidenceMasks + timestampInMilliseconds:timestampInMilliseconds]; + ; } + (MPPPoseLandmarkerResult *) @@ -96,7 +99,7 @@ static const int kMicroSecondsPerMilliSecond = 1000; worldLandmarksPacket:(const Packet &)worldLandmarksPacket segmentationMasksPacket:(const Packet *)segmentationMasksPacket { NSInteger timestampInMilliseconds = - (NSInteger)(landmarksPacket.Timestamp().Value() / kMicroSecondsPerMilliSecond); + (NSInteger)(landmarksPacket.Timestamp().Value() / kMicroSecondsPerMillisecond); if (landmarksPacket.IsEmpty()) { return [MPPPoseLandmarkerResult @@ -118,7 +121,7 @@ static const int kMicroSecondsPerMilliSecond = 1000; worldLandmarksProto:worldLandmarksPacket .Get>() segmentationMasks:segmentationMasks - timestampInMilliSeconds:timestampInMilliseconds]; + timestampInMilliseconds:timestampInMilliseconds]; } @end From 32571a37d21162353f6d2897484624015c6deeaa Mon Sep 17 00:00:00 2001 From: Prianka Liz Kariat Date: Tue, 7 Nov 2023 09:49:53 +0530 Subject: [PATCH 3/3] Added pose landmarker protobuf utils --- .../test/vision/pose_landmarker/utils/BUILD | 21 +++++++ .../MPPPoseLandmarkerResult+ProtobufHelpers.h | 26 ++++++++ ...MPPPoseLandmarkerResult+ProtobufHelpers.mm | 61 +++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 mediapipe/tasks/ios/test/vision/pose_landmarker/utils/BUILD create mode 100644 mediapipe/tasks/ios/test/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+ProtobufHelpers.h create mode 100644 mediapipe/tasks/ios/test/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+ProtobufHelpers.mm diff --git a/mediapipe/tasks/ios/test/vision/pose_landmarker/utils/BUILD b/mediapipe/tasks/ios/test/vision/pose_landmarker/utils/BUILD new file mode 100644 index 000000000..7c9314367 --- /dev/null +++ b/mediapipe/tasks/ios/test/vision/pose_landmarker/utils/BUILD @@ -0,0 +1,21 @@ +package(default_visibility = ["//mediapipe/tasks:internal"]) + +licenses(["notice"]) + +objc_library( + name = "MPPPoseLandmarkerResultProtobufHelpers", + srcs = ["sources/MPPPoseLandmarkerResult+ProtobufHelpers.mm"], + hdrs = ["sources/MPPPoseLandmarkerResult+ProtobufHelpers.h"], + copts = [ + "-ObjC++", + "-std=c++17", + "-x objective-c++", + ], + deps = [ + "//mediapipe/tasks/cc/components/containers/proto:landmarks_detection_result_cc_proto", + "//mediapipe/tasks/ios/common/utils:NSStringHelpers", + "//mediapipe/tasks/ios/test/vision/utils:parse_proto_utils", + "//mediapipe/tasks/ios/vision/pose_landmarker:MPPPoseLandmarkerResult", + "//mediapipe/tasks/ios/vision/pose_landmarker/utils:MPPPoseLandmarkerResultHelpers", + ], +) diff --git a/mediapipe/tasks/ios/test/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+ProtobufHelpers.h b/mediapipe/tasks/ios/test/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+ProtobufHelpers.h new file mode 100644 index 000000000..3db43c41f --- /dev/null +++ b/mediapipe/tasks/ios/test/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+ProtobufHelpers.h @@ -0,0 +1,26 @@ +// Copyright 2023 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "mediapipe/tasks/ios/vision/pose_landmarker/sources/MPPPoseLandmarkerResult.h" + +NS_ASSUME_NONNULL_BEGIN +@interface MPPPoseLandmarkerResult (ProtobufHelpers) + ++ (MPPPoseLandmarkerResult *)poseLandmarkerResultFromProtobufFileWithName:(NSString *)fileName + shouldRemoveZPosition:(BOOL)removeZPosition; + +@end + +NS_ASSUME_NONNULL_END diff --git a/mediapipe/tasks/ios/test/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+ProtobufHelpers.mm b/mediapipe/tasks/ios/test/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+ProtobufHelpers.mm new file mode 100644 index 000000000..38d855c36 --- /dev/null +++ b/mediapipe/tasks/ios/test/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+ProtobufHelpers.mm @@ -0,0 +1,61 @@ +// Copyright 2023 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "mediapipe/tasks/ios/test/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+ProtobufHelpers.h" + +#import "mediapipe/tasks/ios/common/utils/sources/NSString+Helpers.h" +#import "mediapipe/tasks/ios/vision/pose_landmarker/utils/sources/MPPPoseLandmarkerResult+Helpers.h" + +#include "mediapipe/tasks/cc/components/containers/proto/landmarks_detection_result.pb.h" +#include "mediapipe/tasks/ios/test/vision/utils/sources/parse_proto_utils.h" + +namespace { +using LandmarksDetectionResultProto = + ::mediapipe::tasks::containers::proto::LandmarksDetectionResult; +using ::mediapipe::tasks::ios::test::vision::utils::get_proto_from_pbtxt; +} // anonymous namespace + +@implementation MPPPoseLandmarkerResult (ProtobufHelpers) + ++ (MPPPoseLandmarkerResult *)poseLandmarkerResultFromProtobufFileWithName:(NSString *)fileName + shouldRemoveZPosition:(BOOL)removeZPosition { + LandmarksDetectionResultProto landmarkDetectionResultProto; + + if (!get_proto_from_pbtxt(fileName.cppString, landmarkDetectionResultProto).ok()) { + return nil; + } + + if (removeZPosition) { + // Remove z position of landmarks, because they are not used in correctness testing. For video + // or live stream mode, the z positions varies a lot during tracking from frame to frame. + for (int i = 0; i < landmarkDetectionResultProto.landmarks().landmark().size(); i++) { + auto &landmark = *landmarkDetectionResultProto.mutable_landmarks()->mutable_landmark(i); + landmark.clear_z(); + } + } + + MPPPoseLandmarkerResult *result = [MPPPoseLandmarkerResult + poseLandmarkerResultWithLandmarksProto:{landmarkDetectionResultProto.landmarks()} + worldLandmarksProto:{landmarkDetectionResultProto.world_landmarks()} + segmentationMasks:nullptr + timestampInMilliseconds:0]; + + return [MPPPoseLandmarkerResult + poseLandmarkerResultWithLandmarksProto:{landmarkDetectionResultProto.landmarks()} + worldLandmarksProto:{landmarkDetectionResultProto.world_landmarks()} + segmentationMasks:nullptr + timestampInMilliseconds:0]; +} + +@end