Compare commits

...
295 Commits
Author SHA1 Message Date
talksik 10214fa67c adding in personal config 2023-10-05 11:46:33 -07:00
Copybara-Service d686b42b85 Merge pull request #4852 from kinaryml:c-text-embedder-api
PiperOrigin-RevId: 571065228
2023-10-05 10:43:30 -07:00
Kinar ebfd7284c9 Fixed some issues with documentation 2023-10-05 04:25:18 -07:00
Kinar 92e13d43e4 Resolved some issues 2023-10-05 03:54:54 -07:00
MediaPipe TeamandCopybara-Service edc4db287c No public description
PiperOrigin-RevId: 570904787
2023-10-04 22:18:50 -07:00
MediaPipe TeamandCopybara-Service 7ab3d70aa4 Add stream API presence utils.
PiperOrigin-RevId: 570901832
2023-10-04 21:59:05 -07:00
Nevena KotlajaandCopybara-Service 2dd20822be No public description
PiperOrigin-RevId: 570789405
2023-10-04 13:33:51 -07:00
Sebastian SchmidtandCopybara-Service 1d8bd9c3ee No public description
PiperOrigin-RevId: 570765754
2023-10-04 12:14:31 -07:00
Daniel ChengandCopybara-Service d2baba6dbb Internal change
PiperOrigin-RevId: 570745425
2023-10-04 11:09:36 -07:00
MediaPipe TeamandCopybara-Service 3b99f8d9dd Introduce SetJointsVisibilityCalculator
PiperOrigin-RevId: 570745171
2023-10-04 11:04:40 -07:00
MediaPipe TeamandCopybara-Service c81624d7b2 Introduce CombineJointsCalculator
PiperOrigin-RevId: 570739088
2023-10-04 10:45:11 -07:00
Daniel ChengandCopybara-Service 7f1c17065a Prefix status macro implementation with MP_.
This makes it less likely for the implementation to conflict with other
ASSIGN_OR_RETURN() and RETURN_IF_ERROR() implementations.

PiperOrigin-RevId: 570726994
2023-10-04 10:04:59 -07:00
MediaPipe TeamandCopybara-Service 9bb042cc86 GlSurfaceViewRenderer: Capture graph output texture
Captures the original graph output texture, not what has been copied to the screen. This will be important for zooming to prevent top/bottom letterboxes, and it preserves the original quality, so that high resolution images can be used.

PiperOrigin-RevId: 570604422
2023-10-04 00:07:13 -07:00
MediaPipe TeamandCopybara-Service da8fcb6bb2 Smooth pose landmarks
PiperOrigin-RevId: 570441366
2023-10-03 11:12:46 -07:00
Sebastian SchmidtandCopybara-Service a72839ef99 See memory of freed result to nullptr
PiperOrigin-RevId: 570410751
2023-10-03 09:33:48 -07:00
MediaPipe TeamandCopybara-Service d0183b2c70 Fixes typos in the file mediapipe/python/pybind/image.cc and mediapipe/python/pybind
/image_frame.cc.

PiperOrigin-RevId: 570388388
2023-10-03 08:01:25 -07:00
Kinar 753ba916a1 Fixed some typos 2023-10-03 01:51:18 -07:00
Kinar 3564fc0d9b Added files for the TextEmbedder C API and tests 2023-10-03 01:48:07 -07:00
MediaPipe TeamandCopybara-Service 5366aa9d0a Internal update
PiperOrigin-RevId: 570204415
2023-10-02 15:55:31 -07:00
Sebastian SchmidtandCopybara-Service a00759007d Add error handling to C API
PiperOrigin-RevId: 570094642
2023-10-02 09:49:09 -07:00
Sebastian SchmidtandCopybara-Service c7402efe5e Add End to End test for Text Classifier C API
PiperOrigin-RevId: 569658768
2023-09-29 20:53:54 -07:00
Sebastian SchmidtandCopybara-Service 96fa10b906 Add unit tests for C layer for the input types of Text Classifier
PiperOrigin-RevId: 569553038
2023-09-29 12:08:00 -07:00
Sebastian SchmidtandCopybara-Service 6915a79e28 Add tests for C API containers
PiperOrigin-RevId: 569526282
2023-09-29 10:27:15 -07:00
Sebastian SchmidtandCopybara-Service d4561fb5c2 Do not use full filename when FileLocator decides which asset to load
Fixes https://github.com/google/mediapipe/issues/4819

PiperOrigin-RevId: 569506907
2023-09-29 09:11:01 -07:00
MediaPipe TeamandCopybara-Service 09a51bcdeb Internal change
PiperOrigin-RevId: 569310433
2023-09-28 15:44:37 -07:00
Sebastian SchmidtandCopybara-Service 5ca1be6f21 Populate the classification result output param instead of a copy
PiperOrigin-RevId: 569293617
2023-09-28 14:38:02 -07:00
MediaPipe TeamandCopybara-Service f78f24f576 segmentation smoothing stream utility function.
PiperOrigin-RevId: 569283980
2023-09-28 14:03:24 -07:00
Sebastian SchmidtandCopybara-Service 636cf99a3e Fix memory access issue in C layer
PiperOrigin-RevId: 569279959
2023-09-28 13:50:28 -07:00
MediaPipe TeamandCopybara-Service e169849041 No public description
PiperOrigin-RevId: 569274219
2023-09-28 13:31:00 -07:00
Sebastian SchmidtandCopybara-Service 33d6143a1a Don't convert nullptr to std::string in C layer
PiperOrigin-RevId: 569232756
2023-09-28 11:04:44 -07:00
MediaPipe TeamandCopybara-Service a577dc3043 smoothing stream utility function.
PiperOrigin-RevId: 569074973
2023-09-27 23:19:37 -07:00
MediaPipe TeamandCopybara-Service 9edb4cd753 Introduce LandmarksTransformationCalculator
PiperOrigin-RevId: 569050686
2023-09-27 21:12:19 -07:00
MediaPipe TeamandCopybara-Service 66a279418c tensor_to_joints stream utility function.
PiperOrigin-RevId: 569043195
2023-09-27 20:34:20 -07:00
MediaPipe TeamandCopybara-Service 0ae9ff6b98 Introduce TensorToJointsCalculator
PiperOrigin-RevId: 569040914
2023-09-27 20:27:24 -07:00
MediaPipe TeamandCopybara-Service da02052c70 landmarks_to_tensor stream utility function.
PiperOrigin-RevId: 569003241
2023-09-27 17:13:46 -07:00
MediaPipe TeamandCopybara-Service 8837b49026 get_vector_item stream utility function.
PiperOrigin-RevId: 568998504
2023-09-27 16:55:43 -07:00
MediaPipe TeamandCopybara-Service 2ecccaf076 concatenate stream utility function.
PiperOrigin-RevId: 568997695
2023-09-27 16:50:48 -07:00
MediaPipe TeamandCopybara-Service 983fda5d4e No public description
PiperOrigin-RevId: 568953918
2023-09-27 14:04:33 -07:00
MediaPipe TeamandCopybara-Service 8f8c66430f Update PackMediaSequenceCalculator to support index feature inputs on the CLIP_MEDIA_ input tag.
For Detection protos representing index features, the `label` field might be empty.

With this change, only the `Detection::score` field is required, and `Detection.label` and `Detection.label_id` are both optional but at least one of them should be set.

PiperOrigin-RevId: 568944596
2023-09-27 13:33:55 -07:00
MediaPipe TeamandCopybara-Service 698b154ff4 Only recreate immutable texture when necessary for Android TensorsToSegmentationCalculator.
PiperOrigin-RevId: 568937611
2023-09-27 13:09:29 -07:00
MediaPipe TeamandCopybara-Service 787371cfba No public description
PiperOrigin-RevId: 568927297
2023-09-27 12:27:57 -07:00
Sebastian SchmidtandCopybara-Service 61ce228576 Add cc_binary target for C Libraries
PiperOrigin-RevId: 568902427
2023-09-27 11:04:41 -07:00
Sebastian SchmidtandCopybara-Service b01ad84c6f Add export declaration to FaceDetector.detect()
PiperOrigin-RevId: 568872459
2023-09-27 09:28:53 -07:00
Sebastian SchmidtandCopybara-Service 3134625508 No public description
PiperOrigin-RevId: 568660415
2023-09-26 15:14:16 -07:00
Copybara-Service 0417817886 Merge pull request #4829 from priankakariatyml:ios-vision-api-name-changes
PiperOrigin-RevId: 568622587
2023-09-26 12:51:31 -07:00
MediaPipe TeamandCopybara-Service 199b42278b Fixes multiple typos in the tasks internal files.
PiperOrigin-RevId: 568585517
2023-09-26 10:45:07 -07:00
Sebastian SchmidtandCopybara-Service e5e75eac5e No public description
PiperOrigin-RevId: 568581409
2023-09-26 10:34:47 -07:00
MediaPipe TeamandCopybara-Service 573fdad173 Add export_model_with_tokenizer to Text Classifier API.
PiperOrigin-RevId: 567744604
2023-09-22 16:32:38 -07:00
Chris McClanahanandCopybara-Service 9d85141227 No public description
PiperOrigin-RevId: 567726262
2023-09-22 15:07:11 -07:00
Prianka Liz Kariat 2d4e5a75b3 Updated iOS Object Detector Objective C API names 2023-09-23 00:08:43 +05:30
Prianka Liz Kariat 435bee71e8 Updated iOS hand landmarker Objective C API names 2023-09-23 00:08:07 +05:30
Prianka Liz Kariat 9d42744f8a Updated iOS Face Landmarker Objective C API names 2023-09-23 00:07:49 +05:30
Prianka Liz Kariat d7c57e4eda Updated iOS Face Detector Objective C API names 2023-09-23 00:07:20 +05:30
MediaPipe TeamandCopybara-Service 34cedb980b No public description
PiperOrigin-RevId: 567562548
2023-09-22 02:24:25 -07:00
MediaPipe TeamandCopybara-Service 743118a04a Fixes multiple typos in the tasks internal files.
PiperOrigin-RevId: 567506050
2023-09-21 21:24:45 -07:00
MediaPipe TeamandCopybara-Service 859d90b68b No public description
PiperOrigin-RevId: 567439132
2023-09-21 15:40:19 -07:00
MediaPipe TeamandCopybara-Service abf0ee892a Internal Changes
PiperOrigin-RevId: 567374962
2023-09-21 11:55:02 -07:00
MediaPipe TeamandCopybara-Service 82d83f2dd8 Update glog to latest commit
PiperOrigin-RevId: 567337708
2023-09-21 10:10:04 -07:00
Copybara-Service 19c9d328cb Merge pull request #4815 from priankakariatyml:ios-image-segmenter-basic-tests
PiperOrigin-RevId: 567102079
2023-09-20 15:46:14 -07:00
MediaPipe TeamandCopybara-Service 223641a73c Fix depth condition bug when only depth condition is configured.
PiperOrigin-RevId: 567080598
2023-09-20 14:29:18 -07:00
MediaPipe TeamandCopybara-Service 41a012721f Fix bug missing SHOW_RESULT in image generator
PiperOrigin-RevId: 566810243
2023-09-19 18:37:35 -07:00
MediaPipe TeamandCopybara-Service 867d5dc5a7 No public description
PiperOrigin-RevId: 566794388
2023-09-19 17:27:55 -07:00
MediaPipe TeamandCopybara-Service bbf40cba87 split stream utility function.
PiperOrigin-RevId: 566722901
2023-09-19 13:21:39 -07:00
Copybara-Service 58bb2d1b92 Merge pull request #4811 from shmishra99:patch-1
PiperOrigin-RevId: 566676755
2023-09-19 10:43:12 -07:00
Sebastian SchmidtandCopybara-Service 12600e03e9 Do not convert milliseconds to microseconds twice
Fixes https://github.com/google/mediapipe/issues/4809

PiperOrigin-RevId: 566644379
2023-09-19 08:47:31 -07:00
Prianka Liz Kariat f1a5c8d549 Fixed formatting in MPPImageSegmenter.mm 2023-09-19 20:10:23 +05:30
Prianka Liz Kariat d9d4016334 Uncommented live stream test in iOS image segmenter tests 2023-09-19 20:06:25 +05:30
Prianka Liz Kariat bac60548dc Added selfie segmentation and running mode tests to image segmenter 2023-09-19 20:00:41 +05:30
Prianka Liz Kariat 08a5d55ac1 Updated interface of iOS image segmenter 2023-09-19 19:59:33 +05:30
Prianka Liz Kariat 6e80941215 Fixed premature deallocation of C++ masks in iOS Image Segmenter 2023-09-19 19:59:07 +05:30
MediaPipe TeamandCopybara-Service 0ed199186b Fix glScalerCalculator not clearing background in FIT mode
In FIT mode, the image is scaled in an aspect ratio preserving way. That means, the calculator does not render a full-screen quad. The letterbox areas are not drawn. This can cause artifacts, e.g. when MediaPipe reuses the GPU buffer from some other operation. This CL always clears the render target in FIT mode.

PiperOrigin-RevId: 566562715
2023-09-19 02:19:22 -07:00
Shivam MishraandGitHub fd062a2c3f Remove 'awaiting' labels when user issue/PR updated.
Remove the label "stat:awaiting response", when issue/PR unstale.
2023-09-19 11:28:20 +05:30
MediaPipe TeamandCopybara-Service 94cda40a83 No public description
PiperOrigin-RevId: 566435327
2023-09-18 15:50:10 -07:00
MediaPipe TeamandCopybara-Service 36f78f6e4a threshold stream utility function.
PiperOrigin-RevId: 566417914
2023-09-18 14:44:28 -07:00
MediaPipe TeamandCopybara-Service 58a7790081 detections_to_rects stream utility function.
PiperOrigin-RevId: 566358715
2023-09-18 11:17:27 -07:00
MediaPipe TeamandCopybara-Service f4477f1739 A minor typo fix in model maker image classifier hyperparameters python docstring.
PiperOrigin-RevId: 566355937
2023-09-18 11:07:58 -07:00
Copybara-Service d5fa4a157e Merge pull request #4802 from priankakariatyml:ios-image-segmenter-basic-tests
PiperOrigin-RevId: 565797057
2023-09-15 15:45:54 -07:00
Copybara-Service 838c89a3ff Merge pull request #4801 from priankakariatyml:ios-face-stylizer
PiperOrigin-RevId: 565784200
2023-09-15 14:49:50 -07:00
Sebastian SchmidtandCopybara-Service 94477b1342 No public description
PiperOrigin-RevId: 565755048
2023-09-15 12:55:00 -07:00
Sebastian SchmidtandCopybara-Service a933e324b5 Add export declaration for FaceDetector
Fixes https://github.com/google/mediapipe/issues/4799

PiperOrigin-RevId: 565706741
2023-09-15 10:06:06 -07:00
Sebastian SchmidtandCopybara-Service 30590fe8d3 Add helper to create Connection array
PiperOrigin-RevId: 565706612
2023-09-15 10:00:28 -07:00
Prianka Liz Kariat 0f511d52d6 Fixed typo in iOS MPPImageSegmenterResult helpers 2023-09-15 14:24:15 +05:30
Prianka Liz Kariat b3be1418da Updated multiply function in iOS Image Segmenter tests to use C++ vectors 2023-09-15 14:21:33 +05:30
Prianka Liz Kariat fad7f9cdb4 Added iOS image segmenter basic Objective C tests 2023-09-15 14:18:54 +05:30
Prianka Liz Kariat d3f7368b27 Added iOS MPPMask test utils 2023-09-15 14:18:23 +05:30
Prianka Liz Kariat 81ec5801ea Added new initializers for iOS MPPImage in test utils 2023-09-15 14:18:10 +05:30
Prianka Liz Kariat e0b059da58 Added iOS MPPFileInfo for tests 2023-09-15 14:16:50 +05:30
Prianka Liz Kariat 21d000490c Added iOS face stylizer header 2023-09-15 14:06:11 +05:30
Prianka Liz Kariat bb93b775f4 Added iOS face stylizer options 2023-09-15 14:05:59 +05:30
Prianka Liz Kariat a259300bfe Added iOS face stylizer result 2023-09-15 14:05:38 +05:30
Sebastian SchmidtandCopybara-Service 4a8a811373 No public description
PiperOrigin-RevId: 565516592
2023-09-14 17:00:02 -07:00
MediaPipe TeamandCopybara-Service 81964608ba Fixes typo in MediaPipe namespace
PiperOrigin-RevId: 565478366
2023-09-14 14:32:35 -07:00
Daniel ChengandCopybara-Service 65e7cd5236 Fix win32 build break in mediapipe.
buffer_aligned_size_ is not used in tflite_support, but is used
in mediapipe.

PiperOrigin-RevId: 565477047
2023-09-14 14:27:05 -07:00
MediaPipe TeamandCopybara-Service f2b11bf250 No public description
PiperOrigin-RevId: 565446429
2023-09-14 12:41:12 -07:00
Sebastian SchmidtandCopybara-Service 85b19383b9 Fixes iOS hand landmarker connections
PiperOrigin-RevId: 565442497
2023-09-14 12:24:25 -07:00
MediaPipe TeamandCopybara-Service 124a4de08d Clean up TensorConverterCalculator flipping behavior
Returns an error if
- gpu_origin is specified for a CPU image, and
- gpu_origin and flip_vertically are both specified.
Adds a test for an IMAGE_GPU input to validate flipping.

PiperOrigin-RevId: 565311456
2023-09-14 02:56:02 -07:00
Daniel ChengandCopybara-Service 21646008d5 Don't define field in ExternalFileHandler that's not used on Windows.
This fixes:
```
error: private field 'buffer_aligned_size_' is not used [-Werror,-Wunused-private-field]
   87 |   int64 buffer_aligned_size_{};
      |         ^
```
in the downstream Chrome build.
PiperOrigin-RevId: 565221813
2023-09-13 18:42:32 -07:00
MediaPipe TeamandCopybara-Service 7333329470 No public description
PiperOrigin-RevId: 565215664
2023-09-13 18:11:03 -07:00
MediaPipe TeamandCopybara-Service e1d1877e07 Modifying tensor_to_vector_float_calculator to take in D_BFLOAT16 values
PiperOrigin-RevId: 565189254
2023-09-13 16:10:35 -07:00
MediaPipe TeamandCopybara-Service 6dc1239aa9 No public description
PiperOrigin-RevId: 565167086
2023-09-13 14:48:48 -07:00
Sebastian SchmidtandCopybara-Service 50bd79a317 Add exports to ImageSegmenterResult and InteractiveSegmenterResult
PiperOrigin-RevId: 565138661
2023-09-13 13:11:25 -07:00
Sebastian SchmidtandCopybara-Service 7b091dbe53 Fix missing exports for FilesetResolver and static constants
PiperOrigin-RevId: 565113006
2023-09-13 11:40:36 -07:00
MediaPipe TeamandCopybara-Service d6ee884200 No public description
PiperOrigin-RevId: 565087299
2023-09-13 10:23:00 -07:00
MediaPipe TeamandCopybara-Service 8c9cd8a2fb fixes the non-unicode path of file_helpers on windows
Macros can't start with ##, this fixes it.

PiperOrigin-RevId: 565066376
2023-09-13 09:04:33 -07:00
MediaPipe TeamandCopybara-Service 90e18eab91 Internal change.
PiperOrigin-RevId: 565062314
2023-09-13 08:49:16 -07:00
MediaPipe TeamandCopybara-Service 38f421acf0 This will fix multiple typos in the tasks internal files.
PiperOrigin-RevId: 565055843
2023-09-13 08:22:19 -07:00
Sebastian SchmidtandCopybara-Service a5a3e9d36b No public description
PiperOrigin-RevId: 564894013
2023-09-12 18:41:10 -07:00
MediaPipe TeamandCopybara-Service df211d211e Internal update.
PiperOrigin-RevId: 564883563
2023-09-12 17:40:28 -07:00
MediaPipe TeamandCopybara-Service 1d8dda3337 Remove uncoditional texture params reset to make float textures handled correctly.
PiperOrigin-RevId: 564869245
2023-09-12 16:40:13 -07:00
MediaPipe TeamandCopybara-Service 5b08a09446 Fixes two issues with file handling on windows:
. If UNICODE is set, then win32 functions taking file paths use wide
  (utf-16) strings. For example, FindFirstFile really calls to
  FindFirstFileW, which takes a wchar_t*. This adds support for
  the unicode path.
. SetContents() changes from "w" to "wb". This is necessary as
  windows will do some amount of encoding without "b", which results
  in much different values being written.

PiperOrigin-RevId: 564842317
2023-09-12 15:00:05 -07:00
MediaPipe TeamandCopybara-Service dbcdb44f7c Move loading tasks-vision-jni to individual vision task class
PiperOrigin-RevId: 564840343
2023-09-12 14:52:58 -07:00
MediaPipe TeamandCopybara-Service 4ba1dadf92 Add option for nearest neighbor interpolation.
PiperOrigin-RevId: 564786213
2023-09-12 11:41:58 -07:00
MediaPipe TeamandCopybara-Service 5daed78844 No public description
PiperOrigin-RevId: 564775970
2023-09-12 11:10:11 -07:00
MediaPipe TeamandCopybara-Service dd692c2395 Internal update
PiperOrigin-RevId: 564740487
2023-09-12 09:17:13 -07:00
MediaPipe TeamandCopybara-Service 26a67f4424 No public description
PiperOrigin-RevId: 564651554
2023-09-12 02:15:53 -07:00
Sebastian SchmidtandCopybara-Service 12502b6f96 Add Handedness to JS, C++ and Android API
PiperOrigin-RevId: 564559718
2023-09-11 18:27:05 -07:00
MediaPipe TeamandCopybara-Service 02bd0d95e7 Splitting GraphRunner into public API declared interfaces and private TS impls
PiperOrigin-RevId: 564551973
2023-09-11 17:48:21 -07:00
Sebastian SchmidtandCopybara-Service 0fec532ebe Add API exports for MPMask and MPImage
PiperOrigin-RevId: 564527405
2023-09-11 16:03:07 -07:00
Sebastian SchmidtandCopybara-Service 56c26dba84 Update WASM files for 10.5 release
PiperOrigin-RevId: 564511761
2023-09-11 15:07:51 -07:00
MediaPipe TeamandCopybara-Service 7a04d60134 Set the default running model to Image for face stylizer.
PiperOrigin-RevId: 564511316
2023-09-11 15:03:07 -07:00
Sebastian SchmidtandCopybara-Service 81481df304 No public description
PiperOrigin-RevId: 564461274
2023-09-11 12:09:11 -07:00
Sebastian SchmidtandCopybara-Service 315982df0f Ensure that C header don't import C++ types
PiperOrigin-RevId: 564435119
2023-09-11 10:47:27 -07:00
Sebastian SchmidtandCopybara-Service e206f9acdb No public description
PiperOrigin-RevId: 564429453
2023-09-11 10:36:06 -07:00
Copybara-Service cdf199cf96 Merge pull request #4775 from priankakariatyml:ios-doc-updates-part2
PiperOrigin-RevId: 564429285
2023-09-11 10:31:13 -07:00
Chris McClanahanandCopybara-Service e51b923bda internal fix
PiperOrigin-RevId: 564404269
2023-09-11 09:11:49 -07:00
MediaPipe TeamandCopybara-Service 7f245bc84b Internal Change
PiperOrigin-RevId: 564316003
2023-09-11 02:39:40 -07:00
MediaPipe TeamandCopybara-Service b2494fe3c1 This will fix multiple typos in the tasks internal files.
PiperOrigin-RevId: 564264998
2023-09-10 21:56:57 -07:00
MediaPipe TeamandCopybara-Service d1b04a9309 Set enableFlowLimiting to false since only Image model is supported for face stylizer.
PiperOrigin-RevId: 563939653
2023-09-08 22:46:15 -07:00
Sebastian SchmidtandCopybara-Service 7accc79018 Internal
PiperOrigin-RevId: 563907673
2023-09-08 19:16:14 -07:00
Copybara-Service 1514304ab3 Merge pull request #4767 from priankakariatyml:ios-vision-task-refactoring-impl3
PiperOrigin-RevId: 563859728
2023-09-08 15:00:36 -07:00
Sebastian SchmidtandCopybara-Service 6df05b7d2a Internal
PiperOrigin-RevId: 563843599
2023-09-08 13:55:19 -07:00
Copybara-Service b89ca28fe1 Merge pull request #4751 from kuaashish:master
PiperOrigin-RevId: 563840414
2023-09-08 13:44:20 -07:00
Prianka Liz Kariat 9d31827de8 Moved iOS MPPHandLandmark enum to MPPHandLandmarker.h 2023-09-08 20:06:47 +05:30
Prianka Liz Kariat 75daf4e756 Updated iOS hand landmarker documentation to use swift names 2023-09-08 19:16:15 +05:30
Prianka Liz Kariat 18f16f6bb5 Updated iOS gesture recognizer documentation to use Swift names 2023-09-08 19:15:56 +05:30
Prianka Liz Kariat 900e637b6a Fixed typos in iOS documentation 2023-09-08 19:15:32 +05:30
MediaPipe TeamandCopybara-Service 886a118232 landmarks_to_detection stream utility function.
PiperOrigin-RevId: 563633314
2023-09-07 21:40:45 -07:00
MediaPipe TeamandCopybara-Service 7549677408 Internal update
PiperOrigin-RevId: 563553758
2023-09-07 14:58:39 -07:00
MediaPipe TeamandCopybara-Service 80b762a281 No public description
PiperOrigin-RevId: 563543098
2023-09-07 14:19:08 -07:00
Sebastian SchmidtandCopybara-Service 6c38483b37 Add externs to js_library targets
PiperOrigin-RevId: 563500180
2023-09-07 11:52:30 -07:00
vrabaudandCopybara-Service 55536c4382 No public description
PiperOrigin-RevId: 563333271
2023-09-07 00:00:38 -07:00
MediaPipe TeamandCopybara-Service 5f4a6e313e Format improvement.
PiperOrigin-RevId: 563321343
2023-09-06 23:02:05 -07:00
MediaPipe TeamandCopybara-Service 3ce457006f Remove video and streaming mode for face stylizer.
PiperOrigin-RevId: 563312344
2023-09-06 22:20:43 -07:00
MediaPipe TeamandCopybara-Service a9da6d325c Move stream API landmarks_projection to third_party.
PiperOrigin-RevId: 563246209
2023-09-06 16:21:09 -07:00
MediaPipe TeamandCopybara-Service 7252f6f2e7 Remove video and stream model in face stylizer.
PiperOrigin-RevId: 563233996
2023-09-06 15:33:58 -07:00
MediaPipe TeamandCopybara-Service b40b3973fb Add notes/warnings for calculators which use dedicated GL contexts.
PiperOrigin-RevId: 563167765
2023-09-06 11:40:21 -07:00
MediaPipe TeamandCopybara-Service e58ec2d039 No public description
PiperOrigin-RevId: 563163901
2023-09-06 11:30:53 -07:00
MediaPipe TeamandCopybara-Service 967007f250 No public description
PiperOrigin-RevId: 563145860
2023-09-06 10:35:52 -07:00
Prianka Liz Kariat 1ffa999abb Replaced the old iOS vision task runner with the refactored task runner 2023-09-06 18:55:03 +05:30
MediaPipe TeamandCopybara-Service e39119ae53 Add missing cache writing implementation in InferenceCalculatorAdvancedGL
Add missing implementation for absl::Status SaveGpuCachesBasedOnBehavior(tflite::gpu::TFLiteGPURunner* gpu_runner) const for non android/chromeos.

PiperOrigin-RevId: 562973338
2023-09-05 20:51:36 -07:00
MediaPipe TeamandCopybara-Service bf32d1acb2 No public description
PiperOrigin-RevId: 562915674
2023-09-05 15:52:21 -07:00
MediaPipe TeamandCopybara-Service 4e52e96973 No public description
PiperOrigin-RevId: 562865700
2023-09-05 13:03:27 -07:00
Sebastian SchmidtandCopybara-Service 2aefa2308b Internal
PiperOrigin-RevId: 562834129
2023-09-05 11:10:55 -07:00
Copybara-Service a87613aa6c Merge pull request #4750 from priankakariatyml:ios-vision-task-runner-refactor-impl-part2
PiperOrigin-RevId: 562823970
2023-09-05 10:39:19 -07:00
Fergus HendersonandCopybara-Service a19da25565 Some spelling and grammar fixes in the comments.
PiperOrigin-RevId: 562802023
2023-09-05 09:28:50 -07:00
MediaPipe TeamandCopybara-Service be0cde8c2e No public description
PiperOrigin-RevId: 562724334
2023-09-05 03:39:37 -07:00
MediaPipe TeamandCopybara-Service 223544ca4b No public description
PiperOrigin-RevId: 562711473
2023-09-05 02:35:24 -07:00
Ayush GuptaandGitHub 4f5069b402 Merge pull request #4751 from kuaashish/master
Updated Issue Templates
2023-09-04 12:15:58 +05:30
MediaPipe TeamandCopybara-Service cac462c486 Add allow_custom_ops to model_util.convert_to_tflite and enable custom ops for face stylizer.
PiperOrigin-RevId: 562212965
2023-09-02 09:56:40 -07:00
MediaPipe TeamandCopybara-Service 2b5e281c27 internal update
PiperOrigin-RevId: 562090520
2023-09-01 17:52:50 -07:00
MediaPipe TeamandCopybara-Service d6119957a4 No public description
PiperOrigin-RevId: 562075110
2023-09-01 16:31:33 -07:00
MediaPipe TeamandCopybara-Service ab70d92752 No public description
PiperOrigin-RevId: 562071599
2023-09-01 16:14:06 -07:00
MediaPipe TeamandCopybara-Service 23057ac146 Update PackMediaSequenceCalculator to support setting clip/media/string, clip/media/confidence and clip/label/index.
The input stream is provided as drishti::Detection.

PiperOrigin-RevId: 562070790
2023-09-01 16:08:52 -07:00
Copybara-Service e7d071ab39 Merge pull request #4745 from priankakariatyml:ios-image-segmenter-impl
PiperOrigin-RevId: 562020873
2023-09-01 12:34:30 -07:00
MediaPipe TeamandCopybara-Service 6c43d37e5a Provide API/options to show intermediate results and generating progress for Java Image Generator.
PiperOrigin-RevId: 562014712
2023-09-01 12:32:26 -07:00
MediaPipe TeamandCopybara-Service ceb8cd3c78 internal update.
PiperOrigin-RevId: 561995330
2023-09-01 10:57:40 -07:00
MediaPipe TeamandCopybara-Service 823493ee82 Internal update.
PiperOrigin-RevId: 561995055
2023-09-01 10:53:00 -07:00
MediaPipe TeamandCopybara-Service 007824594b Rollback of "Enable defining and using internal executors in subgraphs."
PiperOrigin-RevId: 561921927
2023-09-01 04:57:34 -07:00
Prianka Liz Kariat 40da111ba7 Updated iOS object detector to use refactored vision task runner 2023-09-01 14:07:42 +05:30
Prianka Liz Kariat 188321ace4 Updated iOS hand landmarker to use refactored vision task runner 2023-09-01 14:07:25 +05:30
Prianka Liz Kariat 020ca5eb77 Updated iOS gesture recognizer to use refactored vision task runner 2023-09-01 14:07:07 +05:30
Prianka Liz Kariat fe9c7a47e9 Updated iOS face landmarker to use refactored vision task runner 2023-09-01 14:06:50 +05:30
kuaashishandGitHub b60355dee9 Update 18-solution-legacy-issue-template.yaml 2023-09-01 14:06:47 +05:30
kuaashishandGitHub f371f8f4ea Update 16-bug-issue-template.yaml 2023-09-01 14:04:24 +05:30
kuaashishandGitHub 8642a22985 Update 15-build-install-issue-template.yaml 2023-09-01 14:03:49 +05:30
kuaashishandGitHub d8a9f3ac8e Update 14-feature-request-issue-template.yaml 2023-09-01 14:03:07 +05:30
kuaashishandGitHub 1378fb63a7 Update 12-studio-issue-template.yaml 2023-09-01 14:01:20 +05:30
kuaashishandGitHub 0e8f5c168a Update 11-model-maker-issue-template.yaml 2023-09-01 14:00:48 +05:30
kuaashishandGitHub e060824cd7 Merge branch 'google:master' into master 2023-09-01 13:59:13 +05:30
MediaPipe TeamandCopybara-Service de0c7f2a30 Make cache writes optional in InferenceCalculatorAdvancedGL
Previously, caches were always written, and an error would cause the graph to close abruptly. This prevented services with read-only access to the cache from using the calculator.

The new behavior allows services to choose whether or not to write caches.

PiperOrigin-RevId: 561866791
2023-08-31 23:31:27 -07:00
MediaPipe TeamandCopybara-Service dea6ccba25 Remove unnecessary includes in threadpool_std_thread_impl.cc.
The windows.h was causing conflicts with LOG. Also the the posix headers weren't needed because the code doesn't use OS specific code anymore.

PiperOrigin-RevId: 561848229
2023-08-31 21:52:22 -07:00
Sebastian SchmidtandCopybara-Service 9bb852c33d Add libimagegenerator_gpu.so
PiperOrigin-RevId: 561800710
2023-08-31 17:10:00 -07:00
Copybara-Service 827c2983bd Merge pull request #4743 from priankakariatyml:ios-vision-task-runner-refactor-impl
PiperOrigin-RevId: 561796747
2023-08-31 16:53:14 -07:00
MediaPipe TeamandCopybara-Service 81732944c4 No public description
PiperOrigin-RevId: 561775271
2023-08-31 15:22:43 -07:00
MediaPipe TeamandCopybara-Service afcb9c4216 No public description
PiperOrigin-RevId: 561773992
2023-08-31 15:17:51 -07:00
MediaPipe TeamandCopybara-Service 62e682363c Remove reference pointer to prevent using a constant reference in the looped iteration variable
PiperOrigin-RevId: 561758116
2023-08-31 14:17:51 -07:00
MediaPipe TeamandCopybara-Service 7c2d654d67 Convert CHECK macro to ABSL_CHECK.
Chrome can't use Absl's CHECK because of collisions with its own version.

PiperOrigin-RevId: 561740965
2023-08-31 13:20:29 -07:00
Prianka Liz Kariat d16cb72438 Fixed method call in MPPImageSegmenter.mm 2023-08-31 18:04:09 +05:30
Prianka Liz Kariat 9f01540191 Changed order of methods in MPPImageSegmenter.mm 2023-08-31 18:02:34 +05:30
Prianka Liz Kariat ba685567dd Updated iOS image classifier to use refactored vision task runner 2023-08-31 17:56:36 +05:30
Prianka Liz Kariat e7a0ed84e6 Updated iOS face detector to use refactored vision task runner 2023-08-31 17:37:15 +05:30
Prianka Liz Kariat ec87f068c1 Renamed option in MPPImageSegmenterOptions 2023-08-31 17:31:54 +05:30
Prianka Liz Kariat bac3efdf6a Fixed typo in MPPImageSegmenter.h 2023-08-31 17:31:17 +05:30
Prianka Liz Kariat 5a1564e04c Updated image segmenter bazel target to add MPPImageSegmenter.mm 2023-08-31 14:22:17 +05:30
Prianka Liz Kariat 0863d8def5 Added iOS image segmenter implementation file 2023-08-31 14:04:34 +05:30
Prianka Liz Kariat f74f7b8657 Fixed typo 2023-08-31 14:04:17 +05:30
Prianka Liz Kariat 47e7ec47a2 Changed delegate method to optional 2023-08-31 14:04:09 +05:30
kuaashishandGitHub 15c8e4b087 Update 00-task-issue-template.yaml 2023-08-31 11:02:09 +05:30
kuaashishandGitHub fdc1207a40 Update 00-task-issue-template.yaml 2023-08-31 11:00:45 +05:30
kuaashishandGitHub 74ebb89dec Update 00-task-issue-template.yaml 2023-08-31 10:51:16 +05:30
kuaashishandGitHub f88db254da Update 00-task-issue-template.yaml 2023-08-31 10:50:44 +05:30
Copybara-Service 30802b80cd Merge pull request #4735 from priankakariatyml:ios-doc-updates
PiperOrigin-RevId: 561469442
2023-08-30 15:39:20 -07:00
MediaPipe TeamandCopybara-Service 612162d765 Check if the image contains valid face that can be aligned for stylization. If not, throw an exception for invalid input image. This is applied to both input stylized face and raw face.
PiperOrigin-RevId: 561439600
2023-08-30 13:54:11 -07:00
MediaPipe TeamandCopybara-Service c92570f844 Use ABSL_LOG in MediaPipe.
This is needed in Chrome builds to avoid collisions with its own LOG.

PiperOrigin-RevId: 561436864
2023-08-30 13:43:49 -07:00
Jiuqiang TangandCopybara-Service f60da2120d Internal changes
PiperOrigin-RevId: 561398473
2023-08-30 11:26:57 -07:00
MediaPipe TeamandCopybara-Service 5434b840f6 Improving throttling logs by providing a node info corresponding to a throttling stream.
PiperOrigin-RevId: 561396272
2023-08-30 11:21:31 -07:00
MediaPipe TeamandCopybara-Service 45b0271ded No public description
PiperOrigin-RevId: 561379537
2023-08-30 10:27:02 -07:00
Prianka Liz Kariat 3e90e8d464 Fixed directory creation issues in build_ios_framework.sh 2023-08-30 16:28:17 +05:30
Prianka Liz Kariat 763bc8c71c Fixed typos 2023-08-30 16:27:52 +05:30
Prianka Liz Kariat 298578e10e Added gesture recognizer and hand landmarker to iOS vision framework 2023-08-30 14:51:05 +05:30
MediaPipe TeamandCopybara-Service 6c2638592e Internal update.
PiperOrigin-RevId: 561184322
2023-08-29 17:34:35 -07:00
MediaPipe TeamandCopybara-Service e18e749e3e Internal update
PiperOrigin-RevId: 561148365
2023-08-29 15:04:33 -07:00
MediaPipe TeamandCopybara-Service 01fbbd9f67 No public description
PiperOrigin-RevId: 561067189
2023-08-29 10:18:06 -07:00
MediaPipe TeamandCopybara-Service f56b8a13a3 Add a custom op resolver for fused batch norm.
PiperOrigin-RevId: 560795170
2023-08-28 13:04:10 -07:00
MediaPipe TeamandCopybara-Service 442940cd55 No public description
PiperOrigin-RevId: 560743684
2023-08-28 10:08:49 -07:00
MediaPipe TeamandCopybara-Service 1aa5e0d46f No public description
PiperOrigin-RevId: 560689326
2023-08-28 06:21:09 -07:00
MediaPipe TeamandCopybara-Service b22dcf9ce6 No public description
PiperOrigin-RevId: 560652313
2023-08-28 02:50:07 -07:00
Sebastian SchmidtandCopybara-Service d0bf0dd021 Update TF to solve OneDNN build
PiperOrigin-RevId: 560241320
2023-08-25 18:05:50 -07:00
MediaPipe TeamandCopybara-Service d6dce193fc Internal update
PiperOrigin-RevId: 560147650
2023-08-25 11:22:58 -07:00
Copybara-Service 5d2d8f9ab2 Merge pull request #4721 from priankakariatyml:ios-doc-updates
PiperOrigin-RevId: 560133185
2023-08-25 10:37:51 -07:00
Prianka Liz Kariat 3f0ec5969b Updated iOS docs to use swift names in place of objective c names 2023-08-25 18:06:50 +05:30
MediaPipe TeamandCopybara-Service 6e6978cdbf New image test utilities and memory management fixes.
PiperOrigin-RevId: 559926378
2023-08-24 18:02:55 -07:00
MediaPipe TeamandCopybara-Service dd09c8d3f7 Update port includes with IWYU to fix clang warnings in code where corresponding ports are used.
PiperOrigin-RevId: 559920115
2023-08-24 17:33:34 -07:00
Zu KimandCopybara-Service c56f45bce5 Change the image label input from Classification to Detection.
PiperOrigin-RevId: 559828139
2023-08-24 12:08:25 -07:00
Richard LevasseurandCopybara-Service f2e9a553d6 No public description
PiperOrigin-RevId: 559787614
2023-08-24 10:06:00 -07:00
Sebastian SchmidtandCopybara-Service 4fb52bb7ef Add 'types' to package.json
Fixes gttps://github.com/google/mediapipe/issues/4659

PiperOrigin-RevId: 559785635
2023-08-24 09:58:44 -07:00
MediaPipe TeamandCopybara-Service 4b1b6ae7fb Move stream API rect_transformation to third_party.
PiperOrigin-RevId: 559652775
2023-08-23 23:11:47 -07:00
MediaPipe TeamandCopybara-Service b2446c6ca8 No public description
PiperOrigin-RevId: 559566037
2023-08-23 15:50:34 -07:00
Sebastian SchmidtandCopybara-Service f3d069175c Add C++ converters for C Text Classifier API
PiperOrigin-RevId: 559519880
2023-08-23 13:08:40 -07:00
MediaPipe TeamandCopybara-Service f645c59746 Move stream API image_size to third_party.
PiperOrigin-RevId: 559475476
2023-08-23 10:45:18 -07:00
Nevena KotlajaandCopybara-Service 8689f4f595 No public description
PiperOrigin-RevId: 559466191
2023-08-23 10:21:28 -07:00
MediaPipe TeamandCopybara-Service 2ebdb01d43 ImageGenerator Java API
PiperOrigin-RevId: 559310074
2023-08-22 21:42:16 -07:00
MediaPipe TeamandCopybara-Service 90781669cb No public description
PiperOrigin-RevId: 559275983
2023-08-22 18:04:11 -07:00
Sebastian SchmidtandCopybara-Service 1dfdeb6ebb No public description
PiperOrigin-RevId: 559239912
2023-08-22 15:25:03 -07:00
MediaPipe TeamandCopybara-Service 3443fe4c8e No public description
PiperOrigin-RevId: 559211117
2023-08-22 13:43:27 -07:00
MediaPipe TeamandCopybara-Service 8c4b971c14 Add an API in model_task_graph to create or use cached model resources.
PiperOrigin-RevId: 559174528
2023-08-22 11:34:54 -07:00
MediaPipe TeamandCopybara-Service bcb83302bf Add pose landmarks constants
PiperOrigin-RevId: 559153433
2023-08-22 10:32:10 -07:00
MediaPipe TeamandCopybara-Service 7517b56476 No public description
PiperOrigin-RevId: 559133490
2023-08-22 09:26:33 -07:00
MediaPipe TeamandCopybara-Service edb0a64d0e Move stream API loopback to third_party.
PiperOrigin-RevId: 559037020
2023-08-22 01:44:24 -07:00
MediaPipe TeamandCopybara-Service 9bc8b3bb4f Update the header information for EnsureMinimumDefaultExecutorStackSize.
PiperOrigin-RevId: 558981535
2023-08-21 21:26:32 -07:00
MediaPipe TeamandCopybara-Service 7ba4edc372 Internal Change
PiperOrigin-RevId: 558937644
2023-08-21 16:55:44 -07:00
MediaPipe TeamandCopybara-Service 7f8150776a Add an API to run inference with face stylizer TF model.
PiperOrigin-RevId: 558926645
2023-08-21 16:08:58 -07:00
MediaPipe TeamandCopybara-Service bbf168ddda Add a new from_image API to create face stylizer dataset from a single image. Also deprecate the from_folder API since we only support one-shot use case now.
PiperOrigin-RevId: 558912896
2023-08-21 15:14:36 -07:00
MediaPipe TeamandCopybara-Service ae9e945e0c Change SegmentationOptions.builder() to be public
PiperOrigin-RevId: 558864872
2023-08-21 12:18:17 -07:00
MediaPipe TeamandCopybara-Service 737c103940 Add output size as parameters in Java ImageSegmenter
PiperOrigin-RevId: 558834692
2023-08-21 10:45:08 -07:00
MediaPipe TeamandCopybara-Service cd9d32e797 update pose rendering
PiperOrigin-RevId: 558424354
2023-08-19 10:40:26 -07:00
MediaPipe TeamandCopybara-Service a44c810921 Update PackMediaSequenceCalculator to support adding clip/media/id to the MediaSequence.
As the media ID is usually a video ID which is provided to the graph as a side packet, in this graph it expects it to be provided as as a input side packet instead of an input stream.

PiperOrigin-RevId: 558266967
2023-08-18 15:48:40 -07:00
MediaPipe TeamandCopybara-Service fda0d19337 Adds option to use tensor_ahwb in Android vendor processes
PiperOrigin-RevId: 558086646
2023-08-18 02:31:58 -07:00
Chris McClanahanandCopybara-Service a04a3a1c81 internal fix
PiperOrigin-RevId: 557934477
2023-08-17 14:20:58 -07:00
Copybara-Service 6866d338e0 Merge pull request #4645 from priankakariatyml:ios-vision-task-runner-refactoring
PiperOrigin-RevId: 557894034
2023-08-17 12:02:07 -07:00
MediaPipe TeamandCopybara-Service b213256cbd Change supported_ops to a Tuple instead of List to match the API definition.
PiperOrigin-RevId: 557890361
2023-08-17 11:48:56 -07:00
Sebastian SchmidtandCopybara-Service 990bfd2e3e Don't access "document" in WebWorker
Fixes https://github.com/google/mediapipe/issues/4694

PiperOrigin-RevId: 557885230
2023-08-17 11:32:55 -07:00
Prianka Liz Kariat 22dc08be0e Removed convenience initializer from refactored MPPVisionTaskRunner 2023-08-17 14:15:14 +05:30
MediaPipe TeamandCopybara-Service ed0c8d8d8b Swap left and right hand labels.
PiperOrigin-RevId: 557625660
2023-08-16 15:51:19 -07:00
MediaPipe TeamandCopybara-Service 13bb65db96 Internal Changes
PiperOrigin-RevId: 557563669
2023-08-16 12:16:16 -07:00
MediaPipe TeamandCopybara-Service 9e45e2b6e9 Setting training for the encoder and decoder when converting to TFLite.
Also add selected TF ops to TFLite converter.

PiperOrigin-RevId: 557520277
2023-08-16 10:02:29 -07:00
MediaPipe TeamandCopybara-Service ee217ceb67 Fix MediaPipe build in Chromium.
When building Chromium with Clang on Windows, it needs the template specializations to be declared as well.

PiperOrigin-RevId: 557508703
2023-08-16 09:23:15 -07:00
Sebastian SchmidtandCopybara-Service 251ffc21c8 No public description
PiperOrigin-RevId: 557501469
2023-08-16 08:58:14 -07:00
MediaPipe TeamandCopybara-Service ff17846c6a No public description
PiperOrigin-RevId: 557490568
2023-08-16 08:16:30 -07:00
MediaPipe TeamandCopybara-Service ff3f0433d3 Fix image_util shortcut import line
PiperOrigin-RevId: 557311617
2023-08-15 18:19:13 -07:00
MediaPipe TeamandCopybara-Service 1c98270ef0 Import image_util for using it in mediapipe face stylizer open sourcing.
PiperOrigin-RevId: 557254489
2023-08-15 14:41:57 -07:00
MediaPipe TeamandCopybara-Service cda0ba04ed Dry-Run mode for static registration to make it easier to find all required static registrations
PiperOrigin-RevId: 557185347
2023-08-15 11:03:18 -07:00
MediaPipe TeamandCopybara-Service c1d7e6023a Expose tool calculators in headers to enable dynamic registration by superusers.
PiperOrigin-RevId: 557174440
2023-08-15 10:32:45 -07:00
MediaPipe TeamandCopybara-Service a392561b31 Internal change
PiperOrigin-RevId: 557015628
2023-08-14 22:16:20 -07:00
MediaPipe TeamandCopybara-Service 0da296536b Expose stream handlers in headers to allow dynamic registration for superusers
PiperOrigin-RevId: 556988288
2023-08-14 20:01:50 -07:00
MediaPipe TeamandCopybara-Service b6f5414b3d Support more GPU formats in tensor converter calculator.
PiperOrigin-RevId: 556987807
2023-08-14 19:57:05 -07:00
MediaPipe TeamandCopybara-Service a183212a13 Header for callback_packet_calculator to allow dynamic registration for superusers
PiperOrigin-RevId: 556977122
2023-08-14 18:50:11 -07:00
MediaPipe TeamandCopybara-Service 9c5bdd2eb9 Clarify deprecated GraphStatus usage in Close documentation
PiperOrigin-RevId: 556963967
2023-08-14 17:53:32 -07:00
MediaPipe TeamandCopybara-Service dd940707ca Provide a way to disable static registration using MEDIAPIPE_DISABLE_STATIC_REGISTRATION
PiperOrigin-RevId: 556963956
2023-08-14 17:48:25 -07:00
MediaPipe TeamandCopybara-Service 6605fdb16f add end loop calculator for image size
PiperOrigin-RevId: 556955370
2023-08-14 17:09:02 -07:00
MediaPipe TeamandCopybara-Service a8bee6baf3 Updates the runners to support wasm-style binary assets files, and allows their URLs to be explicitly specified as part of the WasmFileset.
PiperOrigin-RevId: 556903356
2023-08-14 13:59:53 -07:00
MediaPipe TeamandCopybara-Service c8ad606e7c Refactor text_classifier preprocessor to move away from using classifier_data_lib
PiperOrigin-RevId: 556859900
2023-08-14 11:41:09 -07:00
MediaPipe TeamandCopybara-Service 3ac3b03ed5 Migrate packet messages auto registration to rely on MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE
PiperOrigin-RevId: 556063007
2023-08-11 13:14:29 -07:00
Yuqi LiandCopybara-Service c448d54aa7 add metadata writer into face stylizer.
PiperOrigin-RevId: 555596257
2023-08-10 12:09:27 -07:00
MediaPipe TeamandCopybara-Service 91f15d8e4a Enable run inference with a TFLite model containing multiple subgraphs. It uses the subgraph 0 as the default primary subgraph for inference. It will also log a warning in the case that there are more than one subgraph in the model.
PiperOrigin-RevId: 555579131
2023-08-10 11:30:32 -07:00
MediaPipe TeamandCopybara-Service a9c7e22ca4 apply affine transform before drawing, in order to keep constant line width regardless of face cropping.
PiperOrigin-RevId: 555173659
2023-08-09 08:42:57 -07:00
MediaPipe TeamandCopybara-Service 00e0314040 Remove unsafe cast.
PiperOrigin-RevId: 555007705
2023-08-08 18:50:11 -07:00
MediaPipe TeamandCopybara-Service f9a0244c5b No public description
PiperOrigin-RevId: 555005770
2023-08-08 18:38:34 -07:00
MediaPipe TeamandCopybara-Service e558a71597 Include calculator_context.h and calculator_contract.h from calculator_framework.h
PiperOrigin-RevId: 554931086
2023-08-08 13:54:59 -07:00
MediaPipe TeamandCopybara-Service 39b31e51a9 No public description
PiperOrigin-RevId: 554673463
2023-08-07 20:15:34 -07:00
MediaPipe TeamandCopybara-Service 032ed973b6 Add setGpuBufferVerticalFlip to GraphRunner TS API
PiperOrigin-RevId: 554667869
2023-08-07 19:44:21 -07:00
MediaPipe TeamandCopybara-Service c1c51c2fe7 Internal
PiperOrigin-RevId: 554595324
2023-08-07 14:36:42 -07:00
Zu KimandCopybara-Service 22054cd468 Set confidence score of the bounding box label.
PiperOrigin-RevId: 554508925
2023-08-07 10:01:59 -07:00
MediaPipe TeamandCopybara-Service e10bcd1bfd No public description
PiperOrigin-RevId: 554084475
2023-08-05 08:36:24 -07:00
Zu KimandCopybara-Service 460346ed13 Add a support for label annotations (image/label/string and image/label/confidence). Also fixed some clang tidy issues.
PiperOrigin-RevId: 553900667
2023-08-04 13:43:44 -07:00
MediaPipe TeamandCopybara-Service 11508f2291 Internal Change
PiperOrigin-RevId: 553652444
2023-08-03 18:49:35 -07:00
MediaPipe TeamandCopybara-Service 360959e325 Replace some size EXPECTs by ASSERTs
PiperOrigin-RevId: 553555650
2023-08-03 12:27:52 -07:00
MediaPipe TeamandCopybara-Service a0b91e4062 Add a GpuOrigin parameter to TensorConverterCalculator
The parameter superseeds flip_vertically. GpuOrigin works more generally than flip_vertically because CONVENTIONAL works on both iOS (no flip) and Android (yes flip). If not set, the calculator falls back to flip_vertically for backwards compatibility.

Note that web demos actually use TOP_LEFT image orientation, so they shouldn't be flipped, but they still are by CONVENTIONAL. That's being discussed right now.

PiperOrigin-RevId: 553400525
2023-08-03 01:40:13 -07:00
MediaPipe TeamandCopybara-Service 9325af0af3 vlog default executor and its config usage
PiperOrigin-RevId: 553298440
2023-08-02 17:01:05 -07:00
MediaPipe TeamandCopybara-Service e56636b6d1 internal change
PiperOrigin-RevId: 553250547
2023-08-02 14:06:16 -07:00
MediaPipe TeamandCopybara-Service 366a3290cf Change to add the w_avg latent code to style encoding before layer swapping. This is a bug in the previous code. Also set training=True for encoder since this affect the encoding performance.
PiperOrigin-RevId: 553234376
2023-08-02 13:11:22 -07:00
MediaPipe TeamandCopybara-Service 6e54d8c204 Log stack traces for combined CalculatorGraph statuses
PiperOrigin-RevId: 553111356
2023-08-02 05:10:52 -07:00
MediaPipe TeamandCopybara-Service 557ed0b1ea Add tensorflow-addons to model_maker requirements.txt
PiperOrigin-RevId: 552610011
2023-07-31 15:36:25 -07:00
MediaPipe TeamandCopybara-Service 6f916a001c Fix crash in SavePngTestOutput
Do not call SavePngTestOutput in CompareAndSaveImageOutput in case diff_img is null. This can happen if for instance the expected and the actual image have non-matching format or size. Currently, this crashes.
Support single channel golden images.

PiperOrigin-RevId: 552519834
2023-07-31 10:20:06 -07:00
Prianka Liz Kariat d2a86341bd Added refactored iOS vision task runner sources 2023-07-26 20:02:00 +05:30
910 changed files with 31270 additions and 9647 deletions
@@ -40,18 +40,16 @@ body:
label: Programming Language and version (e.g. C++, Python, Java) label: Programming Language and version (e.g. C++, Python, Java)
validations: validations:
required: true required: true
- type: textarea - type: input
id: current_model id: current_model
attributes: attributes:
label: Describe the actual behavior label: Describe the actual behavior
render: shell
validations: validations:
required: true required: true
- type: textarea - type: input
id: expected_model id: expected_model
attributes: attributes:
label: Describe the expected behaviour label: Describe the expected behaviour
render: shell
validations: validations:
required: true required: true
- type: textarea - type: textarea
@@ -41,18 +41,16 @@ body:
label: Task name (e.g. Image classification, Gesture recognition etc.) label: Task name (e.g. Image classification, Gesture recognition etc.)
validations: validations:
required: true required: true
- type: textarea - type: input
id: current_model id: current_model
attributes: attributes:
label: Describe the actual behavior label: Describe the actual behavior
render: shell
validations: validations:
required: true required: true
- type: textarea - type: input
id: expected_model id: expected_model
attributes: attributes:
label: Describe the expected behaviour label: Describe the expected behaviour
render: shell
validations: validations:
required: true required: true
- type: textarea - type: textarea
@@ -31,18 +31,16 @@ body:
label: URL that shows the problem label: URL that shows the problem
validations: validations:
required: false required: false
- type: textarea - type: input
id: current_model id: current_model
attributes: attributes:
label: Describe the actual behavior label: Describe the actual behavior
render: shell
validations: validations:
required: false required: false
- type: textarea - type: input
id: expected_model id: expected_model
attributes: attributes:
label: Describe the expected behaviour label: Describe the expected behaviour
render: shell
validations: validations:
required: false required: false
- type: textarea - type: textarea
@@ -28,37 +28,33 @@ body:
- 'No' - 'No'
validations: validations:
required: false required: false
- type: textarea - type: input
id: behaviour id: behaviour
attributes: attributes:
label: Describe the feature and the current behaviour/state label: Describe the feature and the current behaviour/state
render: shell
validations: validations:
required: true required: true
- type: textarea - type: input
id: api_change id: api_change
attributes: attributes:
label: Will this change the current API? How? label: Will this change the current API? How?
render: shell
validations: validations:
required: false required: false
- type: textarea - type: input
id: benifit id: benifit
attributes: attributes:
label: Who will benefit with this feature? label: Who will benefit with this feature?
validations: validations:
required: false required: false
- type: textarea - type: input
id: use_case id: use_case
attributes: attributes:
label: Please specify the use cases for this feature label: Please specify the use cases for this feature
render: shell
validations: validations:
required: true required: true
- type: textarea - type: input
id: info_other id: info_other
attributes: attributes:
label: Any Other info label: Any Other info
render: shell
validations: validations:
required: false required: false
@@ -87,14 +87,13 @@ body:
placeholder: placeholder:
validations: validations:
required: false required: false
- type: textarea - type: input
id: what-happened id: what-happened
attributes: attributes:
label: Describe the problem label: Describe the problem
description: Provide the exact sequence of commands / steps that you executed before running into the [problem](https://google.github.io/mediapipe/getting_started/getting_started.html) description: Provide the exact sequence of commands / steps that you executed before running into the [problem](https://google.github.io/mediapipe/getting_started/getting_started.html)
placeholder: Tell us what you see! placeholder: Tell us what you see!
value: "A bug happened!" value: "A bug happened!"
render: shell
validations: validations:
required: true required: true
- type: textarea - type: textarea
@@ -80,18 +80,16 @@ body:
label: Xcode & Tulsi version (if issue is related to building for iOS) label: Xcode & Tulsi version (if issue is related to building for iOS)
validations: validations:
required: false required: false
- type: textarea - type: input
id: current_model id: current_model
attributes: attributes:
label: Describe the actual behavior label: Describe the actual behavior
render: shell
validations: validations:
required: true required: true
- type: textarea - type: input
id: expected_model id: expected_model
attributes: attributes:
label: Describe the expected behaviour label: Describe the expected behaviour
render: shell
validations: validations:
required: true required: true
- type: textarea - type: textarea
@@ -48,18 +48,16 @@ body:
placeholder: e.g. C++, Python, Java placeholder: e.g. C++, Python, Java
validations: validations:
required: false required: false
- type: textarea - type: input
id: current_model id: current_model
attributes: attributes:
label: Describe the actual behavior label: Describe the actual behavior
render: shell
validations: validations:
required: false required: false
- type: textarea - type: input
id: expected_model id: expected_model
attributes: attributes:
label: Describe the expected behaviour label: Describe the expected behaviour
render: shell
validations: validations:
required: false required: false
- type: textarea - type: textarea
+3 -1
View File
@@ -39,7 +39,9 @@ jobs:
# Limit the No. of API calls in one run default value is 30. # Limit the No. of API calls in one run default value is 30.
operations-per-run: 500 operations-per-run: 500
# Prevent to remove stale label when PRs or issues are updated. # Prevent to remove stale label when PRs or issues are updated.
remove-stale-when-updated: false remove-stale-when-updated: true
# List of labels to remove when issues/PRs unstale.
labels-to-remove-when-unstale: 'stat:awaiting response'
# comment on issue if not active for more then 7 days. # comment on issue if not active for more then 7 days.
stale-issue-message: 'This issue has been marked stale because it has no recent activity since 7 days. It will be closed if no further activity occurs. Thank you.' stale-issue-message: 'This issue has been marked stale because it has no recent activity since 7 days. It will be closed if no further activity occurs. Thank you.'
# comment on PR if not active for more then 14 days. # comment on PR if not active for more then 14 days.
+32 -15
View File
@@ -73,12 +73,9 @@ http_archive(
http_archive( http_archive(
name = "zlib", name = "zlib",
build_file = "@//third_party:zlib.BUILD", build_file = "@//third_party:zlib.BUILD",
sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1", sha256 = "b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30",
strip_prefix = "zlib-1.2.11", strip_prefix = "zlib-1.2.13",
urls = [ url = "http://zlib.net/fossils/zlib-1.2.13.tar.gz",
"http://mirror.bazel.build/zlib.net/fossils/zlib-1.2.11.tar.gz",
"http://zlib.net/fossils/zlib-1.2.11.tar.gz", # 2017-01-15
],
patches = [ patches = [
"@//third_party:zlib.diff", "@//third_party:zlib.diff",
], ],
@@ -157,19 +154,19 @@ http_archive(
# 2020-08-21 # 2020-08-21
http_archive( http_archive(
name = "com_github_glog_glog", name = "com_github_glog_glog",
strip_prefix = "glog-3a0d4d22c5ae0b9a2216988411cfa6bf860cc372", strip_prefix = "glog-0.6.0",
sha256 = "170d08f80210b82d95563f4723a15095eff1aad1863000e8eeb569c96a98fefb", sha256 = "8a83bf982f37bb70825df71a9709fa90ea9f4447fb3c099e1d720a439d88bad6",
urls = [ urls = [
"https://github.com/google/glog/archive/3a0d4d22c5ae0b9a2216988411cfa6bf860cc372.zip", "https://github.com/google/glog/archive/v0.6.0.tar.gz",
], ],
) )
http_archive( http_archive(
name = "com_github_glog_glog_no_gflags", name = "com_github_glog_glog_no_gflags",
strip_prefix = "glog-3a0d4d22c5ae0b9a2216988411cfa6bf860cc372", strip_prefix = "glog-0.6.0",
sha256 = "170d08f80210b82d95563f4723a15095eff1aad1863000e8eeb569c96a98fefb", sha256 = "8a83bf982f37bb70825df71a9709fa90ea9f4447fb3c099e1d720a439d88bad6",
build_file = "@//third_party:glog_no_gflags.BUILD", build_file = "@//third_party:glog_no_gflags.BUILD",
urls = [ urls = [
"https://github.com/google/glog/archive/3a0d4d22c5ae0b9a2216988411cfa6bf860cc372.zip", "https://github.com/google/glog/archive/v0.6.0.tar.gz",
], ],
patches = [ patches = [
"@//third_party:com_github_glog_glog.diff", "@//third_party:com_github_glog_glog.diff",
@@ -179,6 +176,25 @@ http_archive(
], ],
) )
# 2023-06-05
# This version of Glog is required for Windows support, but currently causes
# crashes on some Android devices.
http_archive(
name = "com_github_glog_glog_windows",
strip_prefix = "glog-3a0d4d22c5ae0b9a2216988411cfa6bf860cc372",
sha256 = "170d08f80210b82d95563f4723a15095eff1aad1863000e8eeb569c96a98fefb",
urls = [
"https://github.com/google/glog/archive/3a0d4d22c5ae0b9a2216988411cfa6bf860cc372.zip",
],
patches = [
"@//third_party:com_github_glog_glog.diff",
"@//third_party:com_github_glog_glog_windows_patch.diff",
],
patch_args = [
"-p1",
],
)
# easyexif # easyexif
http_archive( http_archive(
name = "easyexif", name = "easyexif",
@@ -485,10 +501,10 @@ http_archive(
) )
# TensorFlow repo should always go after the other external dependencies. # TensorFlow repo should always go after the other external dependencies.
# TF on 2023-06-13. # TF on 2023-07-26.
_TENSORFLOW_GIT_COMMIT = "491681a5620e41bf079a582ac39c585cc86878b9" _TENSORFLOW_GIT_COMMIT = "e92261fd4cec0b726692081c4d2966b75abf31dd"
# curl -L https://github.com/tensorflow/tensorflow/archive/<TENSORFLOW_GIT_COMMIT>.tar.gz | shasum -a 256 # curl -L https://github.com/tensorflow/tensorflow/archive/<TENSORFLOW_GIT_COMMIT>.tar.gz | shasum -a 256
_TENSORFLOW_SHA256 = "9f76389af7a2835e68413322c1eaabfadc912f02a76d71dc16be507f9ca3d3ac" _TENSORFLOW_SHA256 = "478a229bd4ec70a5b568ac23b5ea013d9fca46a47d6c43e30365a0412b9febf4"
http_archive( http_archive(
name = "org_tensorflow", name = "org_tensorflow",
urls = [ urls = [
@@ -496,6 +512,7 @@ http_archive(
], ],
patches = [ patches = [
"@//third_party:org_tensorflow_compatibility_fixes.diff", "@//third_party:org_tensorflow_compatibility_fixes.diff",
"@//third_party:org_tensorflow_system_python.diff",
# Diff is generated with a script, don't update it manually. # Diff is generated with a script, don't update it manually.
"@//third_party:org_tensorflow_custom_ops.diff", "@//third_party:org_tensorflow_custom_ops.diff",
], ],
+2 -2
View File
@@ -50,7 +50,7 @@ as the primary developer documentation site for MediaPipe as of April 3, 2023.*
3. The [`hello world`] example uses a simple MediaPipe graph in the 3. The [`hello world`] example uses a simple MediaPipe graph in the
`PrintHelloWorld()` function, defined in a [`CalculatorGraphConfig`] proto. `PrintHelloWorld()` function, defined in a [`CalculatorGraphConfig`] proto.
```C++ ```c++
absl::Status PrintHelloWorld() { absl::Status PrintHelloWorld() {
// Configures a simple graph, which concatenates 2 PassThroughCalculators. // Configures a simple graph, which concatenates 2 PassThroughCalculators.
CalculatorGraphConfig config = ParseTextProtoOrDie<CalculatorGraphConfig>(R"( CalculatorGraphConfig config = ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
@@ -126,7 +126,7 @@ as the primary developer documentation site for MediaPipe as of April 3, 2023.*
```c++ ```c++
mediapipe::Packet packet; mediapipe::Packet packet;
while (poller.Next(&packet)) { while (poller.Next(&packet)) {
LOG(INFO) << packet.Get<string>(); ABSL_LOG(INFO) << packet.Get<string>();
} }
``` ```
+1 -1
View File
@@ -138,7 +138,7 @@ Create a `BUILD` file in the `$APPLICATION_PATH` and add the following build
rules: rules:
``` ```
MIN_IOS_VERSION = "11.0" MIN_IOS_VERSION = "12.0"
load( load(
"@build_bazel_rules_apple//apple:ios.bzl", "@build_bazel_rules_apple//apple:ios.bzl",
+54 -43
View File
@@ -14,57 +14,54 @@
licenses(["notice"]) # Apache 2.0 licenses(["notice"]) # Apache 2.0
# Note: yes, these need to use "//external:android/crosstool", not load("@mediapipe//mediapipe:platforms.bzl", "config_setting_and_platform")
# @androidndk//:default_crosstool.
# Generic Android
config_setting( config_setting(
name = "android", name = "android",
values = {"crosstool_top": "//external:android/crosstool"}, constraint_values = [
"@platforms//os:android",
],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
config_setting( # Android x86 32-bit.
config_setting_and_platform(
name = "android_x86", name = "android_x86",
values = { constraint_values = [
"crosstool_top": "//external:android/crosstool", "@platforms//os:android",
"cpu": "x86", "@platforms//cpu:x86_32",
}, ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
config_setting( # Android x86 64-bit.
config_setting_and_platform(
name = "android_x86_64", name = "android_x86_64",
values = { constraint_values = [
"crosstool_top": "//external:android/crosstool", "@platforms//os:android",
"cpu": "x86_64", "@platforms//cpu:x86_64",
}, ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
config_setting( # Android ARMv7.
name = "android_armeabi", config_setting_and_platform(
values = {
"crosstool_top": "//external:android/crosstool",
"cpu": "armeabi",
},
visibility = ["//visibility:public"],
)
config_setting(
name = "android_arm", name = "android_arm",
values = { constraint_values = [
"crosstool_top": "//external:android/crosstool", "@platforms//os:android",
"cpu": "armeabi-v7a", "@platforms//cpu:armv7",
}, ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
config_setting( # Android ARM64.
config_setting_and_platform(
name = "android_arm64", name = "android_arm64",
values = { constraint_values = [
"crosstool_top": "//external:android/crosstool", "@platforms//os:android",
"cpu": "arm64-v8a", "@platforms//cpu:arm64",
}, ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
@@ -78,7 +75,7 @@ config_setting(
) )
# MacOS x86 64-bit. # MacOS x86 64-bit.
config_setting( config_setting_and_platform(
name = "macos_x86_64", name = "macos_x86_64",
constraint_values = [ constraint_values = [
"@platforms//os:macos", "@platforms//os:macos",
@@ -88,7 +85,7 @@ config_setting(
) )
# MacOS ARM64. # MacOS ARM64.
config_setting( config_setting_and_platform(
name = "macos_arm64", name = "macos_arm64",
constraint_values = [ constraint_values = [
"@platforms//os:macos", "@platforms//os:macos",
@@ -107,7 +104,7 @@ config_setting(
) )
# iOS device ARM32. # iOS device ARM32.
config_setting( config_setting_and_platform(
name = "ios_armv7", name = "ios_armv7",
constraint_values = [ constraint_values = [
"@platforms//os:ios", "@platforms//os:ios",
@@ -117,7 +114,7 @@ config_setting(
) )
# iOS device ARM64. # iOS device ARM64.
config_setting( config_setting_and_platform(
name = "ios_arm64", name = "ios_arm64",
constraint_values = [ constraint_values = [
"@platforms//os:ios", "@platforms//os:ios",
@@ -127,7 +124,7 @@ config_setting(
) )
# iOS device ARM64E. # iOS device ARM64E.
config_setting( config_setting_and_platform(
name = "ios_arm64e", name = "ios_arm64e",
constraint_values = [ constraint_values = [
"@platforms//os:ios", "@platforms//os:ios",
@@ -137,7 +134,7 @@ config_setting(
) )
# iOS simulator x86 32-bit. # iOS simulator x86 32-bit.
config_setting( config_setting_and_platform(
name = "ios_i386", name = "ios_i386",
constraint_values = [ constraint_values = [
"@platforms//os:ios", "@platforms//os:ios",
@@ -148,7 +145,7 @@ config_setting(
) )
# iOS simulator x86 64-bit. # iOS simulator x86 64-bit.
config_setting( config_setting_and_platform(
name = "ios_x86_64", name = "ios_x86_64",
constraint_values = [ constraint_values = [
"@platforms//os:ios", "@platforms//os:ios",
@@ -159,7 +156,7 @@ config_setting(
) )
# iOS simulator ARM64. # iOS simulator ARM64.
config_setting( config_setting_and_platform(
name = "ios_sim_arm64", name = "ios_sim_arm64",
constraint_values = [ constraint_values = [
"@platforms//os:ios", "@platforms//os:ios",
@@ -169,7 +166,6 @@ config_setting(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
# Generic Apple.
alias( alias(
name = "apple", name = "apple",
actual = select({ actual = select({
@@ -180,9 +176,24 @@ alias(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
config_setting( # Windows 64-bit.
config_setting_and_platform(
name = "windows", name = "windows",
values = {"cpu": "x64_windows"}, constraint_values = [
"@platforms//os:windows",
"@platforms//cpu:x86_64",
],
visibility = ["//visibility:public"],
)
# Linux 64-bit.
config_setting_and_platform(
name = "linux",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
visibility = ["//visibility:public"],
) )
exports_files( exports_files(
+9 -1
View File
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# Placeholder: load py_proto_library
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library") load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library")
licenses(["notice"]) licenses(["notice"])
@@ -145,6 +146,7 @@ cc_library(
"//mediapipe/framework/port:logging", "//mediapipe/framework/port:logging",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/util:time_series_util", "//mediapipe/util:time_series_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@com_google_audio_tools//audio/dsp/mfcc", "@com_google_audio_tools//audio/dsp/mfcc",
"@eigen_archive//:eigen3", "@eigen_archive//:eigen3",
@@ -163,8 +165,9 @@ cc_library(
"//mediapipe/framework/formats:matrix", "//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:time_series_header_cc_proto", "//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:integral_types", "//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:logging",
"//mediapipe/util:time_series_util", "//mediapipe/util:time_series_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@com_google_audio_tools//audio/dsp:resampler", "@com_google_audio_tools//audio/dsp:resampler",
"@com_google_audio_tools//audio/dsp:resampler_q", "@com_google_audio_tools//audio/dsp:resampler_q",
@@ -185,6 +188,7 @@ cc_library(
"//mediapipe/framework/port:core_proto", "//mediapipe/framework/port:core_proto",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/util:time_series_util", "//mediapipe/util:time_series_util",
"@com_google_absl//absl/log:absl_check",
], ],
alwayslink = 1, alwayslink = 1,
) )
@@ -224,6 +228,7 @@ cc_library(
"//mediapipe/framework/formats:time_series_header_cc_proto", "//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/util:time_series_util", "//mediapipe/util:time_series_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_audio_tools//audio/dsp:window_functions", "@com_google_audio_tools//audio/dsp:window_functions",
"@eigen_archive//:eigen3", "@eigen_archive//:eigen3",
], ],
@@ -294,6 +299,7 @@ cc_test(
"//mediapipe/framework/port:integral_types", "//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/util:time_series_test_util", "//mediapipe/util:time_series_test_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_audio_tools//audio/dsp:number_util", "@com_google_audio_tools//audio/dsp:number_util",
"@eigen_archive//:eigen3", "@eigen_archive//:eigen3",
], ],
@@ -327,6 +333,7 @@ cc_binary(
"//mediapipe/framework:packet", "//mediapipe/framework:packet",
"//mediapipe/framework/formats:matrix", "//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:time_series_header_cc_proto", "//mediapipe/framework/formats:time_series_header_cc_proto",
"@com_google_absl//absl/log:absl_check",
"@com_google_benchmark//:benchmark", "@com_google_benchmark//:benchmark",
], ],
) )
@@ -345,6 +352,7 @@ cc_test(
"//mediapipe/framework/port:integral_types", "//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/util:time_series_test_util", "//mediapipe/util:time_series_test_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_audio_tools//audio/dsp:window_functions", "@com_google_audio_tools//audio/dsp:window_functions",
"@eigen_archive//:eigen3", "@eigen_archive//:eigen3",
], ],
@@ -23,6 +23,7 @@
#include <vector> #include <vector>
#include "Eigen/Core" #include "Eigen/Core"
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/strings/substitute.h" #include "absl/strings/substitute.h"
@@ -138,7 +139,7 @@ absl::Status FramewiseTransformCalculatorBase::Process(CalculatorContext* cc) {
TransformFrame(input_frame, &output_frame); TransformFrame(input_frame, &output_frame);
// Copy output from vector<float> to Eigen::Vector. // Copy output from vector<float> to Eigen::Vector.
CHECK_EQ(output_frame.size(), num_output_channels_); ABSL_CHECK_EQ(output_frame.size(), num_output_channels_);
Eigen::Map<const Eigen::MatrixXd> output_frame_map(&output_frame[0], Eigen::Map<const Eigen::MatrixXd> output_frame_map(&output_frame[0],
output_frame.size(), 1); output_frame.size(), 1);
output->col(frame) = output_frame_map.cast<float>(); output->col(frame) = output_frame_map.cast<float>();
@@ -16,6 +16,8 @@
#include "mediapipe/calculators/audio/rational_factor_resample_calculator.h" #include "mediapipe/calculators/audio/rational_factor_resample_calculator.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "audio/dsp/resampler_q.h" #include "audio/dsp/resampler_q.h"
using audio_dsp::Resampler; using audio_dsp::Resampler;
@@ -45,9 +47,9 @@ void CopyVectorToChannel(const std::vector<float>& vec, Matrix* matrix,
if (matrix->cols() == 0) { if (matrix->cols() == 0) {
matrix->resize(matrix->rows(), vec.size()); matrix->resize(matrix->rows(), vec.size());
} else { } else {
CHECK_EQ(vec.size(), matrix->cols()); ABSL_CHECK_EQ(vec.size(), matrix->cols());
} }
CHECK_LT(channel, matrix->rows()); ABSL_CHECK_LT(channel, matrix->rows());
matrix->row(channel) = matrix->row(channel) =
Eigen::Map<const Eigen::ArrayXf>(vec.data(), vec.size()); Eigen::Map<const Eigen::ArrayXf>(vec.data(), vec.size());
} }
@@ -77,7 +79,7 @@ absl::Status RationalFactorResampleCalculator::Open(CalculatorContext* cc) {
r = ResamplerFromOptions(source_sample_rate_, target_sample_rate_, r = ResamplerFromOptions(source_sample_rate_, target_sample_rate_,
resample_options); resample_options);
if (!r) { if (!r) {
LOG(ERROR) << "Failed to initialize resampler."; ABSL_LOG(ERROR) << "Failed to initialize resampler.";
return absl::UnknownError("Failed to initialize resampler."); return absl::UnknownError("Failed to initialize resampler.");
} }
} }
@@ -27,7 +27,6 @@
#include "mediapipe/framework/formats/matrix.h" #include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/time_series_header.pb.h" #include "mediapipe/framework/formats/time_series_header.pb.h"
#include "mediapipe/framework/port/integral_types.h" #include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/util/time_series_util.h" #include "mediapipe/util/time_series_util.h"
namespace mediapipe { namespace mediapipe {
@@ -22,6 +22,7 @@
#include <vector> #include <vector>
#include "Eigen/Core" #include "Eigen/Core"
#include "absl/log/absl_log.h"
#include "audio/dsp/number_util.h" #include "audio/dsp/number_util.h"
#include "mediapipe/calculators/audio/spectrogram_calculator.pb.h" #include "mediapipe/calculators/audio/spectrogram_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -882,11 +883,11 @@ void BM_ProcessDC(benchmark::State& state) {
const CalculatorRunner::StreamContents& output = runner.Outputs().Index(0); const CalculatorRunner::StreamContents& output = runner.Outputs().Index(0);
const Matrix& output_matrix = output.packets[0].Get<Matrix>(); const Matrix& output_matrix = output.packets[0].Get<Matrix>();
LOG(INFO) << "Output matrix=" << output_matrix.rows() << "x" ABSL_LOG(INFO) << "Output matrix=" << output_matrix.rows() << "x"
<< output_matrix.cols(); << output_matrix.cols();
LOG(INFO) << "First values=" << output_matrix(0, 0) << ", " ABSL_LOG(INFO) << "First values=" << output_matrix(0, 0) << ", "
<< output_matrix(1, 0) << ", " << output_matrix(2, 0) << ", " << output_matrix(1, 0) << ", " << output_matrix(2, 0) << ", "
<< output_matrix(3, 0); << output_matrix(3, 0);
} }
BENCHMARK(BM_ProcessDC); BENCHMARK(BM_ProcessDC);
@@ -18,6 +18,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/audio/stabilized_log_calculator.pb.h" #include "mediapipe/calculators/audio/stabilized_log_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/matrix.h" #include "mediapipe/framework/formats/matrix.h"
@@ -59,7 +60,7 @@ class StabilizedLogCalculator : public CalculatorBase {
output_scale_ = stabilized_log_calculator_options.output_scale(); output_scale_ = stabilized_log_calculator_options.output_scale();
check_nonnegativity_ = check_nonnegativity_ =
stabilized_log_calculator_options.check_nonnegativity(); stabilized_log_calculator_options.check_nonnegativity();
CHECK_GE(stabilizer_, 0.0) ABSL_CHECK_GE(stabilizer_, 0.0)
<< "stabilizer must be >= 0.0, received a value of " << stabilizer_; << "stabilizer must be >= 0.0, received a value of " << stabilizer_;
// If the input packets have a header, propagate the header to the output. // If the input packets have a header, propagate the header to the output.
@@ -18,6 +18,7 @@
#include <vector> #include <vector>
#include "Eigen/Core" #include "Eigen/Core"
#include "absl/log/absl_check.h"
#include "audio/dsp/window_functions.h" #include "audio/dsp/window_functions.h"
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h" #include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -104,7 +105,7 @@ class TimeSeriesFramerCalculator : public CalculatorBase {
// All numbers are in input samples. // All numbers are in input samples.
const int64_t current_output_frame_start = static_cast<int64_t>( const int64_t current_output_frame_start = static_cast<int64_t>(
round(cumulative_output_frames_ * average_frame_step_samples_)); round(cumulative_output_frames_ * average_frame_step_samples_));
CHECK_EQ(current_output_frame_start, cumulative_completed_samples_); ABSL_CHECK_EQ(current_output_frame_start, cumulative_completed_samples_);
const int64_t next_output_frame_start = static_cast<int64_t>( const int64_t next_output_frame_start = static_cast<int64_t>(
round((cumulative_output_frames_ + 1) * average_frame_step_samples_)); round((cumulative_output_frames_ + 1) * average_frame_step_samples_));
return next_output_frame_start - current_output_frame_start; return next_output_frame_start - current_output_frame_start;
@@ -17,6 +17,7 @@
#include <random> #include <random>
#include <vector> #include <vector>
#include "absl/log/absl_check.h"
#include "benchmark/benchmark.h" #include "benchmark/benchmark.h"
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h" #include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -70,7 +71,7 @@ void BM_TimeSeriesFramerCalculator(benchmark::State& state) {
} }
// Initialize graph. // Initialize graph.
mediapipe::CalculatorGraph graph; mediapipe::CalculatorGraph graph;
CHECK_OK(graph.Initialize(config)); ABSL_CHECK_OK(graph.Initialize(config));
// Prepare input header. // Prepare input header.
auto header = std::make_unique<mediapipe::TimeSeriesHeader>(); auto header = std::make_unique<mediapipe::TimeSeriesHeader>();
header->set_sample_rate(kSampleRate); header->set_sample_rate(kSampleRate);
@@ -78,13 +79,13 @@ void BM_TimeSeriesFramerCalculator(benchmark::State& state) {
state.ResumeTiming(); // Resume benchmark timing. state.ResumeTiming(); // Resume benchmark timing.
CHECK_OK(graph.StartRun({}, {{"input", Adopt(header.release())}})); ABSL_CHECK_OK(graph.StartRun({}, {{"input", Adopt(header.release())}}));
for (auto& packet : input_packets) { for (auto& packet : input_packets) {
CHECK_OK(graph.AddPacketToInputStream("input", packet)); ABSL_CHECK_OK(graph.AddPacketToInputStream("input", packet));
} }
CHECK(!graph.HasError()); ABSL_CHECK(!graph.HasError());
CHECK_OK(graph.CloseAllInputStreams()); ABSL_CHECK_OK(graph.CloseAllInputStreams());
CHECK_OK(graph.WaitUntilIdle()); ABSL_CHECK_OK(graph.WaitUntilIdle());
} }
} }
BENCHMARK(BM_TimeSeriesFramerCalculator); BENCHMARK(BM_TimeSeriesFramerCalculator);
@@ -19,6 +19,7 @@
#include <vector> #include <vector>
#include "Eigen/Core" #include "Eigen/Core"
#include "absl/log/absl_log.h"
#include "audio/dsp/window_functions.h" #include "audio/dsp/window_functions.h"
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h" #include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -186,11 +187,12 @@ class TimeSeriesFramerCalculatorTest
const int num_unique_output_samples = const int num_unique_output_samples =
round((output().packets.size() - 1) * frame_step_samples) + round((output().packets.size() - 1) * frame_step_samples) +
frame_duration_samples; frame_duration_samples;
LOG(INFO) << "packets.size()=" << output().packets.size() ABSL_LOG(INFO) << "packets.size()=" << output().packets.size()
<< " frame_duration_samples=" << frame_duration_samples << " frame_duration_samples=" << frame_duration_samples
<< " frame_step_samples=" << frame_step_samples << " frame_step_samples=" << frame_step_samples
<< " num_input_samples_=" << num_input_samples_ << " num_input_samples_=" << num_input_samples_
<< " num_unique_output_samples=" << num_unique_output_samples; << " num_unique_output_samples="
<< num_unique_output_samples;
const int num_padding_samples = const int num_padding_samples =
num_unique_output_samples - num_input_samples_; num_unique_output_samples - num_input_samples_;
if (options_.pad_final_packet()) { if (options_.pad_final_packet()) {
+34 -1
View File
@@ -325,6 +325,7 @@ cc_library(
":concatenate_vector_calculator_cc_proto", ":concatenate_vector_calculator_cc_proto",
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/api2:node", "//mediapipe/framework/api2:node",
"//mediapipe/framework/formats:body_rig_cc_proto",
"//mediapipe/framework/formats:classification_cc_proto", "//mediapipe/framework/formats:classification_cc_proto",
"//mediapipe/framework/formats:landmark_cc_proto", "//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
@@ -582,6 +583,7 @@ cc_library(
"//mediapipe/framework/port:logging", "//mediapipe/framework/port:logging",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/tool:options_util", "//mediapipe/framework/tool:options_util",
"@com_google_absl//absl/log:absl_check",
], ],
alwayslink = 1, alwayslink = 1,
) )
@@ -597,6 +599,7 @@ cc_test(
"//mediapipe/framework/formats:video_stream_header", "//mediapipe/framework/formats:video_stream_header",
"//mediapipe/framework/port:gtest_main", "//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:integral_types", "//mediapipe/framework/port:integral_types",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
], ],
) )
@@ -629,6 +632,7 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
], ],
alwayslink = 1, alwayslink = 1,
) )
@@ -776,10 +780,11 @@ cc_library(
"//mediapipe/framework/deps:random", "//mediapipe/framework/deps:random",
"//mediapipe/framework/formats:video_stream_header", "//mediapipe/framework/formats:video_stream_header",
"//mediapipe/framework/port:integral_types", "//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/tool:options_util", "//mediapipe/framework/tool:options_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
], ],
alwayslink = 1, alwayslink = 1,
@@ -835,6 +840,7 @@ cc_test(
"//mediapipe/framework/port:gtest_main", "//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:logging", "//mediapipe/framework/port:logging",
"//mediapipe/framework/tool:validate_type", "//mediapipe/framework/tool:validate_type",
"@com_google_absl//absl/log:absl_check",
"@eigen_archive//:eigen3", "@eigen_archive//:eigen3",
], ],
) )
@@ -939,6 +945,7 @@ cc_library(
deps = [ deps = [
":split_vector_calculator_cc_proto", ":split_vector_calculator_cc_proto",
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:body_rig_cc_proto",
"//mediapipe/framework/formats:landmark_cc_proto", "//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
@@ -1022,6 +1029,7 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/api2:node", "//mediapipe/framework/api2:node",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
], ],
alwayslink = 1, alwayslink = 1,
) )
@@ -1060,6 +1068,7 @@ cc_test(
"//mediapipe/framework:calculator_runner", "//mediapipe/framework:calculator_runner",
"//mediapipe/framework/port:gtest_main", "//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:parse_text_proto", "//mediapipe/framework/port:parse_text_proto",
"@com_google_absl//absl/log:absl_log",
], ],
) )
@@ -1106,6 +1115,7 @@ cc_library(
"//mediapipe/framework/api2:node", "//mediapipe/framework/api2:node",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
], ],
alwayslink = 1, alwayslink = 1,
) )
@@ -1381,3 +1391,26 @@ cc_test(
"@com_google_absl//absl/types:optional", "@com_google_absl//absl/types:optional",
], ],
) )
cc_library(
name = "value_or_default_calculator",
srcs = ["value_or_default_calculator.cc"],
visibility = ["//visibility:public"],
deps = [
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:status",
],
alwayslink = True,
)
cc_test(
name = "value_or_default_calculator_test",
srcs = ["value_or_default_calculator_test.cc"],
deps = [
":value_or_default_calculator",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:calculator_runner",
"//mediapipe/framework:packet",
"//mediapipe/framework/port:gtest_main",
],
)
@@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
@@ -163,6 +164,75 @@ TEST_F(BeginEndLoopCalculatorGraphTest, MultipleVectors) {
PacketOfIntsEq(input_timestamp2, std::vector<int>{3, 4}))); PacketOfIntsEq(input_timestamp2, std::vector<int>{3, 4})));
} }
TEST(BeginEndLoopCalculatorPossibleDataRaceTest,
EndLoopForIntegersDoesNotRace) {
auto graph_config = ParseTextProtoOrDie<CalculatorGraphConfig>(
R"pb(
num_threads: 4
input_stream: "ints"
node {
calculator: "BeginLoopIntegerCalculator"
input_stream: "ITERABLE:ints"
output_stream: "ITEM:int"
output_stream: "BATCH_END:timestamp"
}
node {
calculator: "IncrementCalculator"
input_stream: "int"
output_stream: "int_plus_one"
}
# BEGIN: Data race possibility
# EndLoop###Calculator and another calculator using the same input
# may introduce race due to EndLoop###Calculator possibly consuming
# packet.
node {
calculator: "EndLoopIntegersCalculator"
input_stream: "ITEM:int_plus_one"
input_stream: "BATCH_END:timestamp"
output_stream: "ITERABLE:ints_plus_one"
}
node {
calculator: "IncrementCalculator"
input_stream: "int_plus_one"
output_stream: "int_plus_two"
}
# END: Data race possibility
node {
calculator: "EndLoopIntegersCalculator"
input_stream: "ITEM:int_plus_two"
input_stream: "BATCH_END:timestamp"
output_stream: "ITERABLE:ints_plus_two"
}
)pb");
std::vector<Packet> int_plus_one_packets;
tool::AddVectorSink("ints_plus_one", &graph_config, &int_plus_one_packets);
std::vector<Packet> int_original_packets;
tool::AddVectorSink("ints_plus_two", &graph_config, &int_original_packets);
CalculatorGraph graph;
MP_ASSERT_OK(graph.Initialize(graph_config));
MP_ASSERT_OK(graph.StartRun({}));
for (int i = 0; i < 100; ++i) {
std::vector<int> ints = {i, i + 1, i + 2};
Timestamp ts = Timestamp(i);
MP_ASSERT_OK(graph.AddPacketToInputStream(
"ints", MakePacket<std::vector<int>>(std::move(ints)).At(ts)));
MP_ASSERT_OK(graph.WaitUntilIdle());
EXPECT_THAT(int_plus_one_packets,
testing::ElementsAre(
PacketOfIntsEq(ts, std::vector<int>{i + 1, i + 2, i + 3})));
EXPECT_THAT(int_original_packets,
testing::ElementsAre(
PacketOfIntsEq(ts, std::vector<int>{i + 2, i + 3, i + 4})));
int_plus_one_packets.clear();
int_original_packets.clear();
}
MP_ASSERT_OK(graph.CloseAllPacketSources());
MP_ASSERT_OK(graph.WaitUntilDone());
}
// Passes non empty vector through or outputs empty vector in case of timestamp // Passes non empty vector through or outputs empty vector in case of timestamp
// bound update. // bound update.
class PassThroughOrEmptyVectorCalculator : public CalculatorBase { class PassThroughOrEmptyVectorCalculator : public CalculatorBase {
@@ -92,7 +92,7 @@ class BypassCalculator : public Node {
auto options = cc->Options<BypassCalculatorOptions>(); auto options = cc->Options<BypassCalculatorOptions>();
RET_CHECK_EQ(options.pass_input_stream().size(), RET_CHECK_EQ(options.pass_input_stream().size(),
options.pass_output_stream().size()); options.pass_output_stream().size());
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
auto pass_streams, auto pass_streams,
GetPassMap(options, *cc->Inputs().TagMap(), *cc->Outputs().TagMap())); GetPassMap(options, *cc->Inputs().TagMap(), *cc->Outputs().TagMap()));
std::set<CollectionItemId> pass_out; std::set<CollectionItemId> pass_out;
@@ -121,8 +121,9 @@ class BypassCalculator : public Node {
// Saves the map of passthrough input and output stream ids. // Saves the map of passthrough input and output stream ids.
absl::Status Open(CalculatorContext* cc) override { absl::Status Open(CalculatorContext* cc) override {
auto options = cc->Options<BypassCalculatorOptions>(); auto options = cc->Options<BypassCalculatorOptions>();
ASSIGN_OR_RETURN(pass_streams_, GetPassMap(options, *cc->Inputs().TagMap(), MP_ASSIGN_OR_RETURN(
*cc->Outputs().TagMap())); pass_streams_,
GetPassMap(options, *cc->Inputs().TagMap(), *cc->Outputs().TagMap()));
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -18,6 +18,7 @@
#include "mediapipe/calculators/core/concatenate_vector_calculator.pb.h" #include "mediapipe/calculators/core/concatenate_vector_calculator.pb.h"
#include "mediapipe/framework/api2/node.h" #include "mediapipe/framework/api2/node.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/body_rig.pb.h"
#include "mediapipe/framework/formats/classification.pb.h" #include "mediapipe/framework/formats/classification.pb.h"
#include "mediapipe/framework/formats/landmark.pb.h" #include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/port/canonical_errors.h" #include "mediapipe/framework/port/canonical_errors.h"
@@ -128,6 +129,19 @@ class ConcatenateClassificationListCalculator
}; };
MEDIAPIPE_REGISTER_NODE(ConcatenateClassificationListCalculator); MEDIAPIPE_REGISTER_NODE(ConcatenateClassificationListCalculator);
class ConcatenateJointListCalculator
: public ConcatenateListsCalculator<Joint, JointList> {
protected:
int ListSize(const JointList& list) const override {
return list.joint_size();
}
const Joint GetItem(const JointList& list, int idx) const override {
return list.joint(idx);
}
Joint* AddItem(JointList& list) const override { return list.add_joint(); }
};
MEDIAPIPE_REGISTER_NODE(ConcatenateJointListCalculator);
} // namespace api2 } // namespace api2
} // namespace mediapipe } // namespace mediapipe
@@ -14,6 +14,8 @@
#include "mediapipe/calculators/core/end_loop_calculator.h" #include "mediapipe/calculators/core/end_loop_calculator.h"
#include <array>
#include <utility>
#include <vector> #include <vector>
#include "mediapipe/framework/formats/classification.pb.h" #include "mediapipe/framework/formats/classification.pb.h"
@@ -84,4 +86,8 @@ typedef EndLoopCalculator<std::vector<std::array<float, 16>>>
EndLoopAffineMatrixCalculator; EndLoopAffineMatrixCalculator;
REGISTER_CALCULATOR(EndLoopAffineMatrixCalculator); REGISTER_CALCULATOR(EndLoopAffineMatrixCalculator);
typedef EndLoopCalculator<std::vector<std::pair<int, int>>>
EndLoopImageSizeCalculator;
REGISTER_CALCULATOR(EndLoopImageSizeCalculator);
} // namespace mediapipe } // namespace mediapipe
@@ -55,16 +55,16 @@ class EndLoopCalculator : public CalculatorBase {
if (!input_stream_collection_) { if (!input_stream_collection_) {
input_stream_collection_.reset(new IterableT); input_stream_collection_.reset(new IterableT);
} }
// Try to consume the item and move it into the collection. If the items
// are not consumable, then try to copy them instead. If the items are if constexpr (std::is_copy_constructible_v<ItemT>) {
// not copyable, then an error will be returned. input_stream_collection_->push_back(
auto item_ptr_or = cc->Inputs().Tag("ITEM").Value().Consume<ItemT>(); cc->Inputs().Tag("ITEM").Get<ItemT>());
if (item_ptr_or.ok()) {
input_stream_collection_->push_back(std::move(*item_ptr_or.value()));
} else { } else {
if constexpr (std::is_copy_constructible_v<ItemT>) { // Try to consume the item and move it into the collection. Return an
input_stream_collection_->push_back( // error if the items are not consumable.
cc->Inputs().Tag("ITEM").template Get<ItemT>()); auto item_ptr_or = cc->Inputs().Tag("ITEM").Value().Consume<ItemT>();
if (item_ptr_or.ok()) {
input_stream_collection_->push_back(std::move(*item_ptr_or.value()));
} else { } else {
return absl::InternalError( return absl::InternalError(
"The item type is not copiable. Consider making the " "The item type is not copiable. Consider making the "
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/log/absl_log.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h" #include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/port/gtest.h" #include "mediapipe/framework/port/gtest.h"
@@ -356,18 +357,18 @@ TEST_F(GateCalculatorTest, AllowWithStateChangeNoDataStreams) {
RunTimeStepWithoutDataStream(kTimestampValue2, "ALLOW", true); RunTimeStepWithoutDataStream(kTimestampValue2, "ALLOW", true);
constexpr int64_t kTimestampValue3 = 45; constexpr int64_t kTimestampValue3 = 45;
RunTimeStepWithoutDataStream(kTimestampValue3, "ALLOW", false); RunTimeStepWithoutDataStream(kTimestampValue3, "ALLOW", false);
LOG(INFO) << "a"; ABSL_LOG(INFO) << "a";
const std::vector<Packet>& output = const std::vector<Packet>& output =
runner()->Outputs().Get("STATE_CHANGE", 0).packets; runner()->Outputs().Get("STATE_CHANGE", 0).packets;
LOG(INFO) << "s"; ABSL_LOG(INFO) << "s";
ASSERT_EQ(2, output.size()); ASSERT_EQ(2, output.size());
LOG(INFO) << "d"; ABSL_LOG(INFO) << "d";
EXPECT_EQ(kTimestampValue1, output[0].Timestamp().Value()); EXPECT_EQ(kTimestampValue1, output[0].Timestamp().Value());
EXPECT_EQ(kTimestampValue3, output[1].Timestamp().Value()); EXPECT_EQ(kTimestampValue3, output[1].Timestamp().Value());
LOG(INFO) << "f"; ABSL_LOG(INFO) << "f";
EXPECT_EQ(true, output[0].Get<bool>()); // Allow. EXPECT_EQ(true, output[0].Get<bool>()); // Allow.
EXPECT_EQ(false, output[1].Get<bool>()); // Disallow. EXPECT_EQ(false, output[1].Get<bool>()); // Disallow.
LOG(INFO) << "g"; ABSL_LOG(INFO) << "g";
} }
TEST_F(GateCalculatorTest, DisallowWithStateChange) { TEST_F(GateCalculatorTest, DisallowWithStateChange) {
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/log/absl_log.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/ret_check.h" #include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h" #include "mediapipe/framework/port/status.h"
@@ -78,7 +79,7 @@ absl::Status ImmediateMuxCalculator::Process(CalculatorContext* cc) {
if (packet.Timestamp() >= cc->Outputs().Index(0).NextTimestampBound()) { if (packet.Timestamp() >= cc->Outputs().Index(0).NextTimestampBound()) {
cc->Outputs().Index(0).AddPacket(packet); cc->Outputs().Index(0).AddPacket(packet);
} else { } else {
LOG_FIRST_N(WARNING, 5) ABSL_LOG_FIRST_N(WARNING, 5)
<< "Dropping a packet with timestamp " << packet.Timestamp(); << "Dropping a packet with timestamp " << packet.Timestamp();
} }
if (cc->Outputs().NumEntries() >= 2) { if (cc->Outputs().NumEntries() >= 2) {
@@ -16,6 +16,7 @@
#include <vector> #include <vector>
#include "Eigen/Core" #include "Eigen/Core"
#include "absl/log/absl_check.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h" #include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/formats/matrix.h" #include "mediapipe/framework/formats/matrix.h"
@@ -209,7 +210,7 @@ TEST(MatrixMultiplyCalculatorTest, Multiply) {
MatrixFromTextProto(kSamplesText, &samples); MatrixFromTextProto(kSamplesText, &samples);
Matrix expected; Matrix expected;
MatrixFromTextProto(kExpectedText, &expected); MatrixFromTextProto(kExpectedText, &expected);
CHECK_EQ(samples.cols(), expected.cols()); ABSL_CHECK_EQ(samples.cols(), expected.cols());
for (int i = 0; i < samples.cols(); ++i) { for (int i = 0; i < samples.cols(); ++i) {
// Take a column from samples and produce a packet with just that // Take a column from samples and produce a packet with just that
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/log/absl_log.h"
#include "mediapipe/framework/api2/node.h" #include "mediapipe/framework/api2/node.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/ret_check.h" #include "mediapipe/framework/port/ret_check.h"
@@ -53,7 +54,7 @@ class MergeCalculator : public Node {
static absl::Status UpdateContract(CalculatorContract* cc) { static absl::Status UpdateContract(CalculatorContract* cc) {
RET_CHECK_GT(kIn(cc).Count(), 0) << "Needs at least one input stream"; RET_CHECK_GT(kIn(cc).Count(), 0) << "Needs at least one input stream";
if (kIn(cc).Count() == 1) { if (kIn(cc).Count() == 1) {
LOG(WARNING) ABSL_LOG(WARNING)
<< "MergeCalculator expects multiple input streams to merge but is " << "MergeCalculator expects multiple input streams to merge but is "
"receiving only one. Make sure the calculator is configured " "receiving only one. Make sure the calculator is configured "
"correctly or consider removing this calculator to reduce " "correctly or consider removing this calculator to reduce "
@@ -72,8 +73,8 @@ class MergeCalculator : public Node {
} }
} }
LOG(WARNING) << "Empty input packets at timestamp " ABSL_LOG(WARNING) << "Empty input packets at timestamp "
<< cc->InputTimestamp().Value(); << cc->InputTimestamp().Value();
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -16,6 +16,9 @@
#include <memory> #include <memory>
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
namespace { namespace {
// Reflect an integer against the lower and upper bound of an interval. // Reflect an integer against the lower and upper bound of an interval.
int64_t ReflectBetween(int64_t ts, int64_t ts_min, int64_t ts_max) { int64_t ReflectBetween(int64_t ts, int64_t ts_min, int64_t ts_max) {
@@ -177,7 +180,7 @@ PacketResamplerCalculator::GetSamplingStrategy(
const PacketResamplerCalculatorOptions& options) { const PacketResamplerCalculatorOptions& options) {
if (options.reproducible_sampling()) { if (options.reproducible_sampling()) {
if (!options.jitter_with_reflection()) { if (!options.jitter_with_reflection()) {
LOG(WARNING) ABSL_LOG(WARNING)
<< "reproducible_sampling enabled w/ jitter_with_reflection " << "reproducible_sampling enabled w/ jitter_with_reflection "
"disabled. " "disabled. "
<< "reproducible_sampling always uses jitter with reflection, " << "reproducible_sampling always uses jitter with reflection, "
@@ -200,15 +203,15 @@ PacketResamplerCalculator::GetSamplingStrategy(
Timestamp PacketResamplerCalculator::PeriodIndexToTimestamp( Timestamp PacketResamplerCalculator::PeriodIndexToTimestamp(
int64_t index) const { int64_t index) const {
CHECK_EQ(jitter_, 0.0); ABSL_CHECK_EQ(jitter_, 0.0);
CHECK_NE(first_timestamp_, Timestamp::Unset()); ABSL_CHECK_NE(first_timestamp_, Timestamp::Unset());
return first_timestamp_ + TimestampDiffFromSeconds(index / frame_rate_); return first_timestamp_ + TimestampDiffFromSeconds(index / frame_rate_);
} }
int64_t PacketResamplerCalculator::TimestampToPeriodIndex( int64_t PacketResamplerCalculator::TimestampToPeriodIndex(
Timestamp timestamp) const { Timestamp timestamp) const {
CHECK_EQ(jitter_, 0.0); ABSL_CHECK_EQ(jitter_, 0.0);
CHECK_NE(first_timestamp_, Timestamp::Unset()); ABSL_CHECK_NE(first_timestamp_, Timestamp::Unset());
return MathUtil::SafeRound<int64_t, double>( return MathUtil::SafeRound<int64_t, double>(
(timestamp - first_timestamp_).Seconds() * frame_rate_); (timestamp - first_timestamp_).Seconds() * frame_rate_);
} }
@@ -229,13 +232,15 @@ absl::Status LegacyJitterWithReflectionStrategy::Open(CalculatorContext* cc) {
if (resampler_options.output_header() != if (resampler_options.output_header() !=
PacketResamplerCalculatorOptions::NONE) { PacketResamplerCalculatorOptions::NONE) {
LOG(WARNING) << "VideoHeader::frame_rate holds the target value and not " ABSL_LOG(WARNING)
"the actual value."; << "VideoHeader::frame_rate holds the target value and not "
"the actual value.";
} }
if (calculator_->flush_last_packet_) { if (calculator_->flush_last_packet_) {
LOG(WARNING) << "PacketResamplerCalculatorOptions.flush_last_packet is " ABSL_LOG(WARNING)
"ignored, because we are adding jitter."; << "PacketResamplerCalculatorOptions.flush_last_packet is "
"ignored, because we are adding jitter.";
} }
const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>(); const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>();
@@ -254,7 +259,7 @@ absl::Status LegacyJitterWithReflectionStrategy::Open(CalculatorContext* cc) {
} }
absl::Status LegacyJitterWithReflectionStrategy::Close(CalculatorContext* cc) { absl::Status LegacyJitterWithReflectionStrategy::Close(CalculatorContext* cc) {
if (!packet_reservoir_->IsEmpty()) { if (!packet_reservoir_->IsEmpty()) {
LOG(INFO) << "Emitting pack from reservoir."; ABSL_LOG(INFO) << "Emitting pack from reservoir.";
calculator_->OutputWithinLimits(cc, packet_reservoir_->GetSample()); calculator_->OutputWithinLimits(cc, packet_reservoir_->GetSample());
} }
return absl::OkStatus(); return absl::OkStatus();
@@ -285,7 +290,7 @@ absl::Status LegacyJitterWithReflectionStrategy::Process(
if (calculator_->frame_time_usec_ < if (calculator_->frame_time_usec_ <
(cc->InputTimestamp() - calculator_->last_packet_.Timestamp()).Value()) { (cc->InputTimestamp() - calculator_->last_packet_.Timestamp()).Value()) {
LOG_FIRST_N(WARNING, 2) ABSL_LOG_FIRST_N(WARNING, 2)
<< "Adding jitter is not very useful when upsampling."; << "Adding jitter is not very useful when upsampling.";
} }
@@ -340,8 +345,8 @@ void LegacyJitterWithReflectionStrategy::UpdateNextOutputTimestampWithJitter() {
next_output_timestamp_ = Timestamp(ReflectBetween( next_output_timestamp_ = Timestamp(ReflectBetween(
next_output_timestamp_.Value(), next_output_timestamp_min_.Value(), next_output_timestamp_.Value(), next_output_timestamp_min_.Value(),
next_output_timestamp_max_.Value())); next_output_timestamp_max_.Value()));
CHECK_GE(next_output_timestamp_, next_output_timestamp_min_); ABSL_CHECK_GE(next_output_timestamp_, next_output_timestamp_min_);
CHECK_LT(next_output_timestamp_, next_output_timestamp_max_); ABSL_CHECK_LT(next_output_timestamp_, next_output_timestamp_max_);
} }
absl::Status ReproducibleJitterWithReflectionStrategy::Open( absl::Status ReproducibleJitterWithReflectionStrategy::Open(
@@ -352,13 +357,15 @@ absl::Status ReproducibleJitterWithReflectionStrategy::Open(
if (resampler_options.output_header() != if (resampler_options.output_header() !=
PacketResamplerCalculatorOptions::NONE) { PacketResamplerCalculatorOptions::NONE) {
LOG(WARNING) << "VideoHeader::frame_rate holds the target value and not " ABSL_LOG(WARNING)
"the actual value."; << "VideoHeader::frame_rate holds the target value and not "
"the actual value.";
} }
if (calculator_->flush_last_packet_) { if (calculator_->flush_last_packet_) {
LOG(WARNING) << "PacketResamplerCalculatorOptions.flush_last_packet is " ABSL_LOG(WARNING)
"ignored, because we are adding jitter."; << "PacketResamplerCalculatorOptions.flush_last_packet is "
"ignored, because we are adding jitter.";
} }
const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>(); const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>();
@@ -411,7 +418,7 @@ absl::Status ReproducibleJitterWithReflectionStrategy::Process(
// Note, if the stream is upsampling, this could lead to the same packet // Note, if the stream is upsampling, this could lead to the same packet
// being emitted twice. Upsampling and jitter doesn't make much sense // being emitted twice. Upsampling and jitter doesn't make much sense
// but does technically work. // but does technically work.
LOG_FIRST_N(WARNING, 2) ABSL_LOG_FIRST_N(WARNING, 2)
<< "Adding jitter is not very useful when upsampling."; << "Adding jitter is not very useful when upsampling.";
} }
@@ -499,13 +506,15 @@ absl::Status JitterWithoutReflectionStrategy::Open(CalculatorContext* cc) {
if (resampler_options.output_header() != if (resampler_options.output_header() !=
PacketResamplerCalculatorOptions::NONE) { PacketResamplerCalculatorOptions::NONE) {
LOG(WARNING) << "VideoHeader::frame_rate holds the target value and not " ABSL_LOG(WARNING)
"the actual value."; << "VideoHeader::frame_rate holds the target value and not "
"the actual value.";
} }
if (calculator_->flush_last_packet_) { if (calculator_->flush_last_packet_) {
LOG(WARNING) << "PacketResamplerCalculatorOptions.flush_last_packet is " ABSL_LOG(WARNING)
"ignored, because we are adding jitter."; << "PacketResamplerCalculatorOptions.flush_last_packet is "
"ignored, because we are adding jitter.";
} }
const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>(); const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>();
@@ -555,7 +564,7 @@ absl::Status JitterWithoutReflectionStrategy::Process(CalculatorContext* cc) {
if (calculator_->frame_time_usec_ < if (calculator_->frame_time_usec_ <
(cc->InputTimestamp() - calculator_->last_packet_.Timestamp()).Value()) { (cc->InputTimestamp() - calculator_->last_packet_.Timestamp()).Value()) {
LOG_FIRST_N(WARNING, 2) ABSL_LOG_FIRST_N(WARNING, 2)
<< "Adding jitter is not very useful when upsampling."; << "Adding jitter is not very useful when upsampling.";
} }
@@ -13,7 +13,6 @@
#include "mediapipe/framework/deps/random_base.h" #include "mediapipe/framework/deps/random_base.h"
#include "mediapipe/framework/formats/video_stream_header.h" #include "mediapipe/framework/formats/video_stream_header.h"
#include "mediapipe/framework/port/integral_types.h" #include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/ret_check.h" #include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h" #include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/status_macros.h" #include "mediapipe/framework/port/status_macros.h"
@@ -17,6 +17,7 @@
#include <cmath> // for ceil #include <cmath> // for ceil
#include <memory> #include <memory>
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/core/packet_thinner_calculator.pb.h" #include "mediapipe/calculators/core/packet_thinner_calculator.pb.h"
#include "mediapipe/framework/calculator_context.h" #include "mediapipe/framework/calculator_context.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -160,8 +161,8 @@ absl::Status PacketThinnerCalculator::Open(CalculatorContext* cc) {
thinner_type_ = options.thinner_type(); thinner_type_ = options.thinner_type();
// This check enables us to assume only two thinner types exist in Process() // This check enables us to assume only two thinner types exist in Process()
CHECK(thinner_type_ == PacketThinnerCalculatorOptions::ASYNC || ABSL_CHECK(thinner_type_ == PacketThinnerCalculatorOptions::ASYNC ||
thinner_type_ == PacketThinnerCalculatorOptions::SYNC) thinner_type_ == PacketThinnerCalculatorOptions::SYNC)
<< "Unsupported thinner type."; << "Unsupported thinner type.";
if (thinner_type_ == PacketThinnerCalculatorOptions::ASYNC) { if (thinner_type_ == PacketThinnerCalculatorOptions::ASYNC) {
@@ -177,7 +178,8 @@ absl::Status PacketThinnerCalculator::Open(CalculatorContext* cc) {
} else { } else {
period_ = TimestampDiff(options.period()); period_ = TimestampDiff(options.period());
} }
CHECK_LT(TimestampDiff(0), period_) << "Specified period must be positive."; ABSL_CHECK_LT(TimestampDiff(0), period_)
<< "Specified period must be positive.";
if (options.has_start_time()) { if (options.has_start_time()) {
start_time_ = Timestamp(options.start_time()); start_time_ = Timestamp(options.start_time());
@@ -189,7 +191,7 @@ absl::Status PacketThinnerCalculator::Open(CalculatorContext* cc) {
end_time_ = end_time_ =
options.has_end_time() ? Timestamp(options.end_time()) : Timestamp::Max(); options.has_end_time() ? Timestamp(options.end_time()) : Timestamp::Max();
CHECK_LT(start_time_, end_time_) ABSL_CHECK_LT(start_time_, end_time_)
<< "Invalid PacketThinner: start_time must be earlier than end_time"; << "Invalid PacketThinner: start_time must be earlier than end_time";
sync_output_timestamps_ = options.sync_output_timestamps(); sync_output_timestamps_ = options.sync_output_timestamps();
@@ -232,7 +234,7 @@ absl::Status PacketThinnerCalculator::Close(CalculatorContext* cc) {
// Emit any saved packets before quitting. // Emit any saved packets before quitting.
if (!saved_packet_.IsEmpty()) { if (!saved_packet_.IsEmpty()) {
// Only sync thinner should have saved packets. // Only sync thinner should have saved packets.
CHECK_EQ(PacketThinnerCalculatorOptions::SYNC, thinner_type_); ABSL_CHECK_EQ(PacketThinnerCalculatorOptions::SYNC, thinner_type_);
if (sync_output_timestamps_) { if (sync_output_timestamps_) {
cc->Outputs().Index(0).AddPacket( cc->Outputs().Index(0).AddPacket(
saved_packet_.At(NearestSyncTimestamp(saved_packet_.Timestamp()))); saved_packet_.At(NearestSyncTimestamp(saved_packet_.Timestamp())));
@@ -269,7 +271,7 @@ absl::Status PacketThinnerCalculator::SyncThinnerProcess(
const Timestamp saved_sync = NearestSyncTimestamp(saved); const Timestamp saved_sync = NearestSyncTimestamp(saved);
const Timestamp now = cc->InputTimestamp(); const Timestamp now = cc->InputTimestamp();
const Timestamp now_sync = NearestSyncTimestamp(now); const Timestamp now_sync = NearestSyncTimestamp(now);
CHECK_LE(saved_sync, now_sync); ABSL_CHECK_LE(saved_sync, now_sync);
if (saved_sync == now_sync) { if (saved_sync == now_sync) {
// Saved Packet is in same interval as current packet. // Saved Packet is in same interval as current packet.
// Replace saved packet with current if it is at least as // Replace saved packet with current if it is at least as
@@ -295,7 +297,7 @@ absl::Status PacketThinnerCalculator::SyncThinnerProcess(
} }
Timestamp PacketThinnerCalculator::NearestSyncTimestamp(Timestamp now) const { Timestamp PacketThinnerCalculator::NearestSyncTimestamp(Timestamp now) const {
CHECK_NE(start_time_, Timestamp::Unset()) ABSL_CHECK_NE(start_time_, Timestamp::Unset())
<< "Method only valid for sync thinner calculator."; << "Method only valid for sync thinner calculator.";
// Computation is done using int64 arithmetic. No easy way to avoid // Computation is done using int64 arithmetic. No easy way to avoid
@@ -303,12 +305,12 @@ Timestamp PacketThinnerCalculator::NearestSyncTimestamp(Timestamp now) const {
const int64_t now64 = now.Value(); const int64_t now64 = now.Value();
const int64_t start64 = start_time_.Value(); const int64_t start64 = start_time_.Value();
const int64_t period64 = period_.Value(); const int64_t period64 = period_.Value();
CHECK_LE(0, period64); ABSL_CHECK_LE(0, period64);
// Round now64 to its closest interval (units of period64). // Round now64 to its closest interval (units of period64).
int64_t sync64 = int64_t sync64 =
(now64 - start64 + period64 / 2) / period64 * period64 + start64; (now64 - start64 + period64 / 2) / period64 * period64 + start64;
CHECK_LE(abs(now64 - sync64), period64 / 2) ABSL_CHECK_LE(abs(now64 - sync64), period64 / 2)
<< "start64: " << start64 << "; now64: " << now64 << "start64: " << start64 << "; now64: " << now64
<< "; sync64: " << sync64; << "; sync64: " << sync64;
@@ -16,6 +16,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "mediapipe/calculators/core/packet_thinner_calculator.pb.h" #include "mediapipe/calculators/core/packet_thinner_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -70,7 +71,7 @@ class SimpleRunner : public CalculatorRunner {
} }
double GetFrameRate() const { double GetFrameRate() const {
CHECK(!Outputs().Index(0).header.IsEmpty()); ABSL_CHECK(!Outputs().Index(0).header.IsEmpty());
return Outputs().Index(0).header.Get<VideoHeader>().frame_rate; return Outputs().Index(0).header.Get<VideoHeader>().frame_rate;
} }
}; };
@@ -14,6 +14,7 @@
#include <deque> #include <deque>
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/core/sequence_shift_calculator.pb.h" #include "mediapipe/calculators/core/sequence_shift_calculator.pb.h"
#include "mediapipe/framework/api2/node.h" #include "mediapipe/framework/api2/node.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -101,7 +102,7 @@ void SequenceShiftCalculator::ProcessPositiveOffset(CalculatorContext* cc) {
kOut(cc).Send(packet_cache_.front().At(cc->InputTimestamp())); kOut(cc).Send(packet_cache_.front().At(cc->InputTimestamp()));
packet_cache_.pop_front(); packet_cache_.pop_front();
} else if (emit_empty_packets_before_first_packet_) { } else if (emit_empty_packets_before_first_packet_) {
LOG(FATAL) << "Not supported yet"; ABSL_LOG(FATAL) << "Not supported yet";
} }
// Store current packet for later output. // Store current packet for later output.
packet_cache_.push_back(kIn(cc).packet()); packet_cache_.push_back(kIn(cc).packet());
@@ -17,6 +17,7 @@
#include "mediapipe/calculators/core/split_vector_calculator.pb.h" #include "mediapipe/calculators/core/split_vector_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/body_rig.pb.h"
#include "mediapipe/framework/formats/landmark.pb.h" #include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/port/canonical_errors.h" #include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/ret_check.h" #include "mediapipe/framework/port/ret_check.h"
@@ -196,6 +197,18 @@ class SplitLandmarkListCalculator
}; };
REGISTER_CALCULATOR(SplitLandmarkListCalculator); REGISTER_CALCULATOR(SplitLandmarkListCalculator);
class SplitJointListCalculator : public SplitListsCalculator<Joint, JointList> {
protected:
int ListSize(const JointList& list) const override {
return list.joint_size();
}
const Joint GetItem(const JointList& list, int idx) const override {
return list.joint(idx);
}
Joint* AddItem(JointList& list) const override { return list.add_joint(); }
};
REGISTER_CALCULATOR(SplitJointListCalculator);
} // namespace mediapipe } // namespace mediapipe
// NOLINTNEXTLINE // NOLINTNEXTLINE
@@ -0,0 +1,90 @@
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/status.h"
namespace mediapipe {
namespace {
constexpr char kInputValueTag[] = "IN";
constexpr char kTickerTag[] = "TICK";
constexpr char kOutputTag[] = "OUT";
constexpr char kIndicationTag[] = "FLAG";
} // namespace
// For every packet received on the TICK stream, if the IN stream is not
// empty - emit its value as is as OUT. Otherwise output a default packet.
// FLAG outputs true every time the default value has been used. It does not
// output anything when IN has a value.
//
// Example config:
// node {
// calculator: "ValueOrDefaultCalculator"
// input_stream: "IN:sometimes_missing_value"
// input_stream: "TICK:clock"
// output_stream: "OUT:value_or_default"
// output_stream: "FLAG:used_default"
// input_side_packet: "default"
// }
//
// TODO: Consider adding an option for a default value as a input-stream
// instead of a side-packet, so it will enable using standard calculators
// instead of creating a new packet-generators. It will also allow a dynamic
// default value.
class ValueOrDefaultCalculator : public mediapipe::CalculatorBase {
public:
ValueOrDefaultCalculator() {}
ValueOrDefaultCalculator(const ValueOrDefaultCalculator&) = delete;
ValueOrDefaultCalculator& operator=(const ValueOrDefaultCalculator&) = delete;
static mediapipe::Status GetContract(mediapipe::CalculatorContract* cc) {
cc->Inputs().Tag(kInputValueTag).SetAny();
cc->Inputs().Tag(kTickerTag).SetAny();
cc->Outputs().Tag(kOutputTag).SetSameAs(&cc->Inputs().Tag(kInputValueTag));
cc->Outputs().Tag(kIndicationTag).Set<bool>();
cc->InputSidePackets().Index(0).SetSameAs(
&cc->Inputs().Tag(kInputValueTag));
return mediapipe::OkStatus();
}
mediapipe::Status Open(mediapipe::CalculatorContext* cc) override {
if (!cc->Inputs().Tag(kInputValueTag).Header().IsEmpty()) {
cc->Outputs()
.Tag(kOutputTag)
.SetHeader(cc->Inputs().Tag(kInputValueTag).Header());
}
default_ = cc->InputSidePackets().Index(0);
cc->SetOffset(mediapipe::TimestampDiff(0));
return mediapipe::OkStatus();
}
mediapipe::Status Process(mediapipe::CalculatorContext* cc) override {
// Output according to the TICK signal.
if (cc->Inputs().Tag(kTickerTag).IsEmpty()) {
return mediapipe::OkStatus();
}
if (!cc->Inputs().Tag(kInputValueTag).IsEmpty()) {
// Output the input as is:
cc->Outputs()
.Tag(kOutputTag)
.AddPacket(cc->Inputs().Tag(kInputValueTag).Value());
} else {
// Output default:
cc->Outputs()
.Tag(kOutputTag)
.AddPacket(default_.At(cc->InputTimestamp()));
cc->Outputs()
.Tag(kIndicationTag)
.Add(new bool(true), cc->InputTimestamp());
}
return mediapipe::OkStatus();
}
private:
// The default value to replicate every time there is no new value.
mediapipe::Packet default_;
};
REGISTER_CALCULATOR(ValueOrDefaultCalculator);
} // namespace mediapipe
@@ -0,0 +1,240 @@
#include <algorithm>
#include <cstdint>
#include <vector>
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/packet.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h"
#include "mediapipe/framework/port/status_matchers.h"
namespace mediapipe {
namespace {
using ::testing::AllOf;
using ::testing::ContainerEq;
using ::testing::Each;
using ::testing::ElementsAre;
using ::testing::IsEmpty;
using ::testing::SizeIs;
using ::testing::Test;
const int kDefaultValue = 0;
// Utility to a create a mediapipe graph runner with the tested calculator and a
// default value, for all the tests.
class ValueOrDefaultRunner : public mediapipe::CalculatorRunner {
public:
ValueOrDefaultRunner()
: mediapipe::CalculatorRunner(R"pb(
calculator: "ValueOrDefaultCalculator"
input_stream: "IN:in"
input_stream: "TICK:tick"
input_side_packet: "default"
output_stream: "OUT:out"
output_stream: "FLAG:used_default"
)pb") {
MutableSidePackets()->Index(0) = mediapipe::MakePacket<int>(kDefaultValue);
}
// Utility to push inputs to the runner to the TICK stream, so we could easily
// tick.
void TickAt(int64_t time) {
// The type or value of the stream isn't relevant, we use just a bool.
MutableInputs()->Tag("TICK").packets.push_back(
mediapipe::Adopt(new bool(false)).At(mediapipe::Timestamp(time)));
}
// Utility to push the real inputs to the runner (IN stream).
void ProvideInput(int64_t time, int value) {
MutableInputs()->Tag("IN").packets.push_back(
mediapipe::Adopt(new int(value)).At(mediapipe::Timestamp(time)));
}
// Extracts the timestamps (as int64) of the output stream of the calculator.
std::vector<int64_t> GetOutputTimestamps() const {
std::vector<int64_t> timestamps;
for (const mediapipe::Packet& packet : Outputs().Tag("OUT").packets) {
timestamps.emplace_back(packet.Timestamp().Value());
}
return timestamps;
}
// Extracts the values from the output stream of the calculator.
std::vector<int> GetOutputValues() const {
std::vector<int> values;
for (const mediapipe::Packet& packet : Outputs().Tag("OUT").packets) {
values.emplace_back(packet.Get<int>());
}
return values;
}
// Extracts the timestamps (as int64) of the flag stream, which indicates on
// times without an input value (i.e. using the default value).
std::vector<int64_t> GetFlagTimestamps() const {
std::vector<int64_t> timestamps;
for (const mediapipe::Packet& packet : Outputs().Tag("FLAG").packets) {
timestamps.emplace_back(packet.Timestamp().Value());
}
return timestamps;
}
// Extracts the output from the flags stream (which should always be true).
std::vector<bool> GetFlagValues() const {
std::vector<bool> flags;
for (const mediapipe::Packet& packet : Outputs().Tag("FLAG").packets) {
flags.emplace_back(packet.Get<bool>());
}
return flags;
}
};
// To be used as input values:
std::vector<int> GetIntegersRange(int size) {
std::vector<int> result;
for (int i = 0; i < size; ++i) {
// We start with default-value+1 so it won't contain the default value.
result.push_back(kDefaultValue + 1 + i);
}
return result;
}
TEST(ValueOrDefaultCalculatorTest, NoInputs) {
// Check that when no real inputs are provided - we get the default value over
// and over, with the correct timestamps.
ValueOrDefaultRunner runner;
const std::vector<int64_t> ticks = {0, 1, 2, 5, 8, 12, 33, 231};
for (int tick : ticks) {
runner.TickAt(tick);
}
MP_EXPECT_OK(runner.Run());
// Make sure we get the right timestamps:
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
// All should be default value:
EXPECT_THAT(runner.GetOutputValues(),
AllOf(Each(kDefaultValue), SizeIs(ticks.size())));
// We should get the default indication all the time:
EXPECT_THAT(runner.GetFlagTimestamps(), ContainerEq(ticks));
}
TEST(ValueOrDefaultCalculatorTest, NeverDefault) {
// Check that when we provide the inputs on time - we get them as outputs.
ValueOrDefaultRunner runner;
const std::vector<int64_t> ticks = {0, 1, 2, 5, 8, 12, 33, 231};
const std::vector<int> values = GetIntegersRange(ticks.size());
for (int i = 0; i < ticks.size(); ++i) {
runner.TickAt(ticks[i]);
runner.ProvideInput(ticks[i], values[i]);
}
MP_EXPECT_OK(runner.Run());
// Make sure we get the right timestamps:
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
// Should get the inputs values:
EXPECT_THAT(runner.GetOutputValues(), ContainerEq(values));
// We should never get the default indication:
EXPECT_THAT(runner.GetFlagTimestamps(), IsEmpty());
}
TEST(ValueOrDefaultCalculatorTest, DefaultAndValues) {
// Check that when we provide inputs only part of the time - we get them, but
// defaults at the missing times.
// That's the usual use case for this calculator.
ValueOrDefaultRunner runner;
const std::vector<int64_t> ticks = {0, 1, 5, 8, 12, 231};
// Provide inputs only part of the ticks.
// Chosen so there will be defaults before the first input, between the
// inputs and after the last input.
const std::vector<int64_t> in_ticks = {/*0,*/ 1, 5, /*8,*/ 12, /*, 231*/};
const std::vector<int> in_values = GetIntegersRange(in_ticks.size());
for (int tick : ticks) {
runner.TickAt(tick);
}
for (int i = 0; i < in_ticks.size(); ++i) {
runner.ProvideInput(in_ticks[i], in_values[i]);
}
MP_EXPECT_OK(runner.Run());
// Make sure we get all the timestamps:
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
// The timestamps of the flag should be exactly the ones not in in_ticks.
EXPECT_THAT(runner.GetFlagTimestamps(), ElementsAre(0, 8, 231));
// And the values are default in these times, and the input values for
// in_ticks.
EXPECT_THAT(
runner.GetOutputValues(),
ElementsAre(kDefaultValue, 1, 2, kDefaultValue, 3, kDefaultValue));
}
TEST(ValueOrDefaultCalculatorTest, TimestampsMissmatch) {
// Check that when we provide the inputs not on time - we don't get them.
ValueOrDefaultRunner runner;
const std::vector<int64_t> ticks = {1, 2, 5, 8, 12, 33, 231};
// The timestamps chosen so it will be before the first tick, in between ticks
// and after the last one. Also - more inputs than ticks.
const std::vector<int64_t> in_ticks = {0, 3, 4, 6, 7, 9, 10,
11, 13, 14, 15, 16, 232};
const std::vector<int> in_values = GetIntegersRange(in_ticks.size());
for (int tick : ticks) {
runner.TickAt(tick);
}
for (int i = 0; i < in_ticks.size(); ++i) {
runner.ProvideInput(in_ticks[i], in_values[i]);
}
MP_EXPECT_OK(runner.Run());
// Non of the in_ticks should be inserted:
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
EXPECT_THAT(runner.GetOutputValues(),
AllOf(Each(kDefaultValue), SizeIs(ticks.size())));
// All (and only) ticks should get the default.
EXPECT_THAT(runner.GetFlagTimestamps(), ContainerEq(ticks));
}
TEST(ValueOrDefaultCalculatorTest, FlagValue) {
// Since we anyway suppose that the Flag is a bool - there is nothing
// interesting to check, but we should check once that the value is the right
// (true) one.
ValueOrDefaultRunner runner;
runner.TickAt(0);
MP_EXPECT_OK(runner.Run());
EXPECT_THAT(runner.GetFlagValues(), ElementsAre(true));
}
TEST(ValueOrDefaultCalculatorTest, FullTest) {
// Make sure that nothing gets wrong with an input that have both right and
// wrong timestamps, some defaults etc.
ValueOrDefaultRunner runner;
const std::vector<int64_t> ticks = {1, 2, 5, 8, 12, 33, 231};
const std::vector<int64_t> in_ticks = {0, 2, 4, 6, 8, 9, 12, 33, 54, 232};
const std::vector<int> in_values = GetIntegersRange(in_ticks.size());
for (int tick : ticks) {
runner.TickAt(tick);
}
for (int i = 0; i < in_ticks.size(); ++i) {
runner.ProvideInput(in_ticks[i], in_values[i]);
}
MP_EXPECT_OK(runner.Run());
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
// Calculated by hand:
EXPECT_THAT(
runner.GetOutputValues(),
ElementsAre(kDefaultValue, 2, kDefaultValue, 5, 7, 8, kDefaultValue));
EXPECT_THAT(runner.GetFlagTimestamps(), ElementsAre(1, 5, 231));
EXPECT_THAT(runner.GetFlagValues(), AllOf(Each(true), SizeIs(3)));
}
} // namespace
} // namespace mediapipe
+44 -2
View File
@@ -97,6 +97,7 @@ cc_library(
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:source_location", "//mediapipe/framework/port:source_location",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
], ],
alwayslink = 1, alwayslink = 1,
) )
@@ -125,6 +126,7 @@ cc_library(
"//mediapipe/framework/port:opencv_imgcodecs", "//mediapipe/framework/port:opencv_imgcodecs",
"//mediapipe/framework/port:opencv_imgproc", "//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
], ],
alwayslink = 1, alwayslink = 1,
) )
@@ -151,11 +153,11 @@ cc_library(
"//mediapipe/framework/formats:image_format_cc_proto", "//mediapipe/framework/formats:image_format_cc_proto",
"//mediapipe/framework/formats:image_frame", "//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/formats:image_frame_opencv", "//mediapipe/framework/formats:image_frame_opencv",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:opencv_core", "//mediapipe/framework/port:opencv_core",
"//mediapipe/framework/port:opencv_imgproc", "//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/port:vector", "//mediapipe/framework/port:vector",
"@com_google_absl//absl/log:absl_log",
] + select({ ] + select({
"//mediapipe/gpu:disable_gpu": [], "//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [ "//conditions:default": [
@@ -202,6 +204,7 @@ cc_library(
"//mediapipe/framework/port:opencv_imgproc", "//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/port:vector", "//mediapipe/framework/port:vector",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
] + select({ ] + select({
"//mediapipe/gpu:disable_gpu": [], "//mediapipe/gpu:disable_gpu": [],
@@ -261,9 +264,12 @@ cc_library(
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/gpu:scale_mode_cc_proto", "//mediapipe/gpu:scale_mode_cc_proto",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
] + select({ ] + select({
"//mediapipe/gpu:disable_gpu": [], "//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [ "//conditions:default": [
"//mediapipe/gpu:gl_base_hdr",
"//mediapipe/gpu:gl_calculator_helper", "//mediapipe/gpu:gl_calculator_helper",
"//mediapipe/gpu:gl_quad_renderer", "//mediapipe/gpu:gl_quad_renderer",
"//mediapipe/gpu:gl_simple_shaders", "//mediapipe/gpu:gl_simple_shaders",
@@ -273,6 +279,36 @@ cc_library(
alwayslink = 1, alwayslink = 1,
) )
cc_test(
name = "image_transformation_calculator_test",
srcs = ["image_transformation_calculator_test.cc"],
data = ["//mediapipe/calculators/image/testdata:test_images"],
tags = [
"desktop_only_test",
],
deps = [
":image_transformation_calculator",
"//mediapipe/framework:calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:calculator_runner",
"//mediapipe/framework/deps:file_path",
"//mediapipe/framework/formats:image_format_cc_proto",
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/formats:image_frame_opencv",
"//mediapipe/framework/port:gtest",
"//mediapipe/framework/port:opencv_imgcodecs",
"//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:parse_text_proto",
"//mediapipe/gpu:gpu_buffer_to_image_frame_calculator",
"//mediapipe/gpu:image_frame_to_gpu_buffer_calculator",
"//third_party:opencv",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
cc_library( cc_library(
name = "image_cropping_calculator", name = "image_cropping_calculator",
srcs = ["image_cropping_calculator.cc"], srcs = ["image_cropping_calculator.cc"],
@@ -300,6 +336,7 @@ cc_library(
"//mediapipe/framework/port:opencv_imgproc", "//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
] + select({ ] + select({
"//mediapipe/gpu:disable_gpu": [], "//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [ "//conditions:default": [
@@ -396,6 +433,7 @@ cc_library(
"//mediapipe/framework/port:logging", "//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
], ],
) )
@@ -420,6 +458,8 @@ cc_library(
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/util:image_frame_util", "//mediapipe/util:image_frame_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@libyuv", "@libyuv",
], ],
@@ -625,9 +665,9 @@ cc_library(
"//mediapipe/framework/formats:image", "//mediapipe/framework/formats:image",
"//mediapipe/framework/formats:image_format_cc_proto", "//mediapipe/framework/formats:image_format_cc_proto",
"//mediapipe/framework/formats:image_frame", "//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/port:vector", "//mediapipe/framework/port:vector",
"@com_google_absl//absl/log:absl_log",
] + select({ ] + select({
"//mediapipe/gpu:disable_gpu": [], "//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [ "//conditions:default": [
@@ -665,6 +705,7 @@ cc_test(
"//mediapipe/framework/port:opencv_imgcodecs", "//mediapipe/framework/port:opencv_imgcodecs",
"//mediapipe/framework/port:opencv_imgproc", "//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:parse_text_proto", "//mediapipe/framework/port:parse_text_proto",
"@com_google_absl//absl/log:absl_log",
], ],
) )
@@ -687,6 +728,7 @@ cc_library(
"//mediapipe/gpu:gpu_buffer", "//mediapipe/gpu:gpu_buffer",
"//mediapipe/gpu:gpu_origin_cc_proto", "//mediapipe/gpu:gpu_origin_cc_proto",
"//mediapipe/gpu:shader_util", "//mediapipe/gpu:shader_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/status", "@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor", "@com_google_absl//absl/status:statusor",
@@ -20,6 +20,7 @@
#include "Eigen/Core" #include "Eigen/Core"
#include "Eigen/Geometry" #include "Eigen/Geometry"
#include "Eigen/LU" #include "Eigen/LU"
#include "absl/log/absl_log.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
@@ -53,6 +54,10 @@ bool IsMatrixVerticalFlipNeeded(GpuOrigin::Mode gpu_origin) {
#endif // __APPLE__ #endif // __APPLE__
case GpuOrigin::TOP_LEFT: case GpuOrigin::TOP_LEFT:
return false; return false;
default:
ABSL_LOG(ERROR) << "Incorrect GpuOrigin: "
<< static_cast<int>(gpu_origin);
return true;
} }
} }
@@ -218,7 +223,7 @@ class GlTextureWarpAffineRunner
absl::StrCat(mediapipe::kMediaPipeFragmentShaderPreamble, absl::StrCat(mediapipe::kMediaPipeFragmentShaderPreamble,
interpolation_def, kFragShader); interpolation_def, kFragShader);
ASSIGN_OR_RETURN(program_, create_fn(vert_src, frag_src)); MP_ASSIGN_OR_RETURN(program_, create_fn(vert_src, frag_src));
auto create_custom_zero_fn = [&]() -> absl::StatusOr<Program> { auto create_custom_zero_fn = [&]() -> absl::StatusOr<Program> {
std::string custom_zero_border_mode_def = R"( std::string custom_zero_border_mode_def = R"(
@@ -231,10 +236,10 @@ class GlTextureWarpAffineRunner
}; };
#if GL_CLAMP_TO_BORDER_MAY_BE_SUPPORTED #if GL_CLAMP_TO_BORDER_MAY_BE_SUPPORTED
if (!IsGlClampToBorderSupported(gl_helper_->GetGlContext())) { if (!IsGlClampToBorderSupported(gl_helper_->GetGlContext())) {
ASSIGN_OR_RETURN(program_custom_zero_, create_custom_zero_fn()); MP_ASSIGN_OR_RETURN(program_custom_zero_, create_custom_zero_fn());
} }
#else #else
ASSIGN_OR_RETURN(program_custom_zero_, create_custom_zero_fn()); MP_ASSIGN_OR_RETURN(program_custom_zero_, create_custom_zero_fn());
#endif // GL_CLAMP_TO_BORDER_MAY_BE_SUPPORTED #endif // GL_CLAMP_TO_BORDER_MAY_BE_SUPPORTED
glGenFramebuffers(1, &framebuffer_); glGenFramebuffers(1, &framebuffer_);
@@ -384,6 +389,8 @@ class GlTextureWarpAffineRunner
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glFlush();
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -15,6 +15,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "absl/log/absl_check.h"
#include "absl/strings/str_replace.h" #include "absl/strings/str_replace.h"
#include "mediapipe/calculators/image/bilateral_filter_calculator.pb.h" #include "mediapipe/calculators/image/bilateral_filter_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -183,8 +184,8 @@ absl::Status BilateralFilterCalculator::Open(CalculatorContext* cc) {
sigma_color_ = options_.sigma_color(); sigma_color_ = options_.sigma_color();
sigma_space_ = options_.sigma_space(); sigma_space_ = options_.sigma_space();
CHECK_GE(sigma_color_, 0.0); ABSL_CHECK_GE(sigma_color_, 0.0);
CHECK_GE(sigma_space_, 0.0); ABSL_CHECK_GE(sigma_space_, 0.0);
if (!use_gpu_) sigma_color_ *= 255.0; if (!use_gpu_) sigma_color_ *= 255.0;
if (use_gpu_) { if (use_gpu_) {
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/log/absl_check.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame.h" #include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h" #include "mediapipe/framework/formats/image_frame_opencv.h"
@@ -25,8 +26,8 @@
namespace mediapipe { namespace mediapipe {
namespace { namespace {
void SetColorChannel(int channel, uint8 value, cv::Mat* mat) { void SetColorChannel(int channel, uint8 value, cv::Mat* mat) {
CHECK(mat->depth() == CV_8U); ABSL_CHECK(mat->depth() == CV_8U);
CHECK(channel < mat->channels()); ABSL_CHECK(channel < mat->channels());
const int step = mat->channels(); const int step = mat->channels();
for (int r = 0; r < mat->rows; ++r) { for (int r = 0; r < mat->rows; ++r) {
uint8* row_ptr = mat->ptr<uint8>(r); uint8* row_ptr = mat->ptr<uint8>(r);
@@ -16,6 +16,7 @@
#include <cmath> #include <cmath>
#include "absl/log/absl_log.h"
#include "mediapipe/framework/formats/image_frame.h" #include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h" #include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/formats/rect.pb.h" #include "mediapipe/framework/formats/rect.pb.h"
@@ -202,8 +203,9 @@ absl::Status ImageCroppingCalculator::ValidateBorderModeForGPU(
switch (options.border_mode()) { switch (options.border_mode()) {
case mediapipe::ImageCroppingCalculatorOptions::BORDER_ZERO: case mediapipe::ImageCroppingCalculatorOptions::BORDER_ZERO:
LOG(WARNING) << "BORDER_ZERO mode is not supported by GPU " ABSL_LOG(WARNING)
<< "implementation and will fall back into BORDER_REPLICATE"; << "BORDER_ZERO mode is not supported by GPU "
<< "implementation and will fall back into BORDER_REPLICATE";
break; break;
case mediapipe::ImageCroppingCalculatorOptions::BORDER_REPLICATE: case mediapipe::ImageCroppingCalculatorOptions::BORDER_REPLICATE:
break; break;
@@ -92,11 +92,11 @@ absl::StatusOr<ImageFileProperties> GetImageFileProperites(
properties.set_focal_length_mm(result.FocalLength); properties.set_focal_length_mm(result.FocalLength);
properties.set_focal_length_35mm(result.FocalLengthIn35mm); properties.set_focal_length_35mm(result.FocalLengthIn35mm);
ASSIGN_OR_RETURN(auto focal_length_pixels, MP_ASSIGN_OR_RETURN(auto focal_length_pixels,
ComputeFocalLengthInPixels(properties.image_width(), ComputeFocalLengthInPixels(properties.image_width(),
properties.image_height(), properties.image_height(),
properties.focal_length_35mm(), properties.focal_length_35mm(),
properties.focal_length_mm())); properties.focal_length_mm()));
properties.set_focal_length_pixels(focal_length_pixels); properties.set_focal_length_pixels(focal_length_pixels);
return properties; return properties;
@@ -151,7 +151,7 @@ class ImageFilePropertiesCalculator : public CalculatorBase {
if (cc->InputSidePackets().NumEntries() == 1) { if (cc->InputSidePackets().NumEntries() == 1) {
const std::string& image_bytes = const std::string& image_bytes =
cc->InputSidePackets().Index(0).Get<std::string>(); cc->InputSidePackets().Index(0).Get<std::string>();
ASSIGN_OR_RETURN(properties_, GetImageFileProperites(image_bytes)); MP_ASSIGN_OR_RETURN(properties_, GetImageFileProperites(image_bytes));
read_properties_ = true; read_properties_ = true;
} }
@@ -169,7 +169,7 @@ class ImageFilePropertiesCalculator : public CalculatorBase {
return absl::OkStatus(); return absl::OkStatus();
} }
const std::string& image_bytes = cc->Inputs().Index(0).Get<std::string>(); const std::string& image_bytes = cc->Inputs().Index(0).Get<std::string>();
ASSIGN_OR_RETURN(properties_, GetImageFileProperites(image_bytes)); MP_ASSIGN_OR_RETURN(properties_, GetImageFileProperites(image_bytes));
read_properties_ = true; read_properties_ = true;
} }
if (read_properties_) { if (read_properties_) {
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/status/status.h"
#include "mediapipe/calculators/image/image_transformation_calculator.pb.h" #include "mediapipe/calculators/image/image_transformation_calculator.pb.h"
#include "mediapipe/calculators/image/rotation_mode.pb.h" #include "mediapipe/calculators/image/rotation_mode.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -27,6 +28,7 @@
#include "mediapipe/gpu/scale_mode.pb.h" #include "mediapipe/gpu/scale_mode.pb.h"
#if !MEDIAPIPE_DISABLE_GPU #if !MEDIAPIPE_DISABLE_GPU
#include "mediapipe/gpu/gl_base.h"
#include "mediapipe/gpu/gl_calculator_helper.h" #include "mediapipe/gpu/gl_calculator_helper.h"
#include "mediapipe/gpu/gl_quad_renderer.h" #include "mediapipe/gpu/gl_quad_renderer.h"
#include "mediapipe/gpu/gl_simple_shaders.h" #include "mediapipe/gpu/gl_simple_shaders.h"
@@ -60,42 +62,42 @@ constexpr char kVideoPrestreamTag[] = "VIDEO_PRESTREAM";
int RotationModeToDegrees(mediapipe::RotationMode_Mode rotation) { int RotationModeToDegrees(mediapipe::RotationMode_Mode rotation) {
switch (rotation) { switch (rotation) {
case mediapipe::RotationMode_Mode_UNKNOWN: case mediapipe::RotationMode::UNKNOWN:
case mediapipe::RotationMode_Mode_ROTATION_0: case mediapipe::RotationMode::ROTATION_0:
return 0; return 0;
case mediapipe::RotationMode_Mode_ROTATION_90: case mediapipe::RotationMode::ROTATION_90:
return 90; return 90;
case mediapipe::RotationMode_Mode_ROTATION_180: case mediapipe::RotationMode::ROTATION_180:
return 180; return 180;
case mediapipe::RotationMode_Mode_ROTATION_270: case mediapipe::RotationMode::ROTATION_270:
return 270; return 270;
} }
} }
mediapipe::RotationMode_Mode DegreesToRotationMode(int degrees) { mediapipe::RotationMode_Mode DegreesToRotationMode(int degrees) {
switch (degrees) { switch (degrees) {
case 0: case 0:
return mediapipe::RotationMode_Mode_ROTATION_0; return mediapipe::RotationMode::ROTATION_0;
case 90: case 90:
return mediapipe::RotationMode_Mode_ROTATION_90; return mediapipe::RotationMode::ROTATION_90;
case 180: case 180:
return mediapipe::RotationMode_Mode_ROTATION_180; return mediapipe::RotationMode::ROTATION_180;
case 270: case 270:
return mediapipe::RotationMode_Mode_ROTATION_270; return mediapipe::RotationMode::ROTATION_270;
default: default:
return mediapipe::RotationMode_Mode_UNKNOWN; return mediapipe::RotationMode::UNKNOWN;
} }
} }
mediapipe::ScaleMode_Mode ParseScaleMode( mediapipe::ScaleMode_Mode ParseScaleMode(
mediapipe::ScaleMode_Mode scale_mode, mediapipe::ScaleMode_Mode scale_mode,
mediapipe::ScaleMode_Mode default_mode) { mediapipe::ScaleMode_Mode default_mode) {
switch (scale_mode) { switch (scale_mode) {
case mediapipe::ScaleMode_Mode_DEFAULT: case mediapipe::ScaleMode::DEFAULT:
return default_mode; return default_mode;
case mediapipe::ScaleMode_Mode_STRETCH: case mediapipe::ScaleMode::STRETCH:
return scale_mode; return scale_mode;
case mediapipe::ScaleMode_Mode_FIT: case mediapipe::ScaleMode::FIT:
return scale_mode; return scale_mode;
case mediapipe::ScaleMode_Mode_FILL_AND_CROP: case mediapipe::ScaleMode::FILL_AND_CROP:
return scale_mode; return scale_mode;
default: default:
return default_mode; return default_mode;
@@ -208,6 +210,8 @@ class ImageTransformationCalculator : public CalculatorBase {
bool use_gpu_ = false; bool use_gpu_ = false;
cv::Scalar padding_color_; cv::Scalar padding_color_;
ImageTransformationCalculatorOptions::InterpolationMode interpolation_mode_;
#if !MEDIAPIPE_DISABLE_GPU #if !MEDIAPIPE_DISABLE_GPU
GlCalculatorHelper gpu_helper_; GlCalculatorHelper gpu_helper_;
std::unique_ptr<QuadRenderer> rgb_renderer_; std::unique_ptr<QuadRenderer> rgb_renderer_;
@@ -343,6 +347,11 @@ absl::Status ImageTransformationCalculator::Open(CalculatorContext* cc) {
options_.padding_color().green(), options_.padding_color().green(),
options_.padding_color().blue()); options_.padding_color().blue());
interpolation_mode_ = options_.interpolation_mode();
if (options_.interpolation_mode() ==
ImageTransformationCalculatorOptions::DEFAULT) {
interpolation_mode_ = ImageTransformationCalculatorOptions::LINEAR;
}
if (use_gpu_) { if (use_gpu_) {
#if !MEDIAPIPE_DISABLE_GPU #if !MEDIAPIPE_DISABLE_GPU
// Let the helper access the GL context information. // Let the helper access the GL context information.
@@ -457,26 +466,48 @@ absl::Status ImageTransformationCalculator::RenderCpu(CalculatorContext* cc) {
ComputeOutputDimensions(input_width, input_height, &output_width, ComputeOutputDimensions(input_width, input_height, &output_width,
&output_height); &output_height);
int opencv_interpolation_mode = cv::INTER_LINEAR;
if (output_width_ > 0 && output_height_ > 0) { if (output_width_ > 0 && output_height_ > 0) {
cv::Mat scaled_mat; cv::Mat scaled_mat;
if (scale_mode_ == mediapipe::ScaleMode_Mode_STRETCH) { if (scale_mode_ == mediapipe::ScaleMode::STRETCH) {
int scale_flag = if (interpolation_mode_ == ImageTransformationCalculatorOptions::LINEAR) {
input_mat.cols > output_width_ && input_mat.rows > output_height_ // Use INTER_AREA for downscaling if interpolation mode is set to
? cv::INTER_AREA // LINEAR.
: cv::INTER_LINEAR; if (input_mat.cols > output_width_ && input_mat.rows > output_height_) {
opencv_interpolation_mode = cv::INTER_AREA;
} else {
opencv_interpolation_mode = cv::INTER_LINEAR;
}
} else {
opencv_interpolation_mode = cv::INTER_NEAREST;
}
cv::resize(input_mat, scaled_mat, cv::Size(output_width_, output_height_), cv::resize(input_mat, scaled_mat, cv::Size(output_width_, output_height_),
0, 0, scale_flag); 0, 0, opencv_interpolation_mode);
} else { } else {
const float scale = const float scale =
std::min(static_cast<float>(output_width_) / input_width, std::min(static_cast<float>(output_width_) / input_width,
static_cast<float>(output_height_) / input_height); static_cast<float>(output_height_) / input_height);
const int target_width = std::round(input_width * scale); const int target_width = std::round(input_width * scale);
const int target_height = std::round(input_height * scale); const int target_height = std::round(input_height * scale);
int scale_flag = scale < 1.0f ? cv::INTER_AREA : cv::INTER_LINEAR;
if (scale_mode_ == mediapipe::ScaleMode_Mode_FIT) { if (interpolation_mode_ == ImageTransformationCalculatorOptions::LINEAR) {
// Use INTER_AREA for downscaling if interpolation mode is set to
// LINEAR.
if (scale < 1.0f) {
opencv_interpolation_mode = cv::INTER_AREA;
} else {
opencv_interpolation_mode = cv::INTER_LINEAR;
}
} else {
opencv_interpolation_mode = cv::INTER_NEAREST;
}
if (scale_mode_ == mediapipe::ScaleMode::FIT) {
cv::Mat intermediate_mat; cv::Mat intermediate_mat;
cv::resize(input_mat, intermediate_mat, cv::resize(input_mat, intermediate_mat,
cv::Size(target_width, target_height), 0, 0, scale_flag); cv::Size(target_width, target_height), 0, 0,
opencv_interpolation_mode);
const int top = (output_height_ - target_height) / 2; const int top = (output_height_ - target_height) / 2;
const int bottom = output_height_ - target_height - top; const int bottom = output_height_ - target_height - top;
const int left = (output_width_ - target_width) / 2; const int left = (output_width_ - target_width) / 2;
@@ -488,7 +519,7 @@ absl::Status ImageTransformationCalculator::RenderCpu(CalculatorContext* cc) {
padding_color_); padding_color_);
} else { } else {
cv::resize(input_mat, scaled_mat, cv::Size(target_width, target_height), cv::resize(input_mat, scaled_mat, cv::Size(target_width, target_height),
0, 0, scale_flag); 0, 0, opencv_interpolation_mode);
output_width = target_width; output_width = target_width;
output_height = target_height; output_height = target_height;
} }
@@ -514,17 +545,17 @@ absl::Status ImageTransformationCalculator::RenderCpu(CalculatorContext* cc) {
cv::warpAffine(input_mat, rotated_mat, rotation_mat, rotated_size); cv::warpAffine(input_mat, rotated_mat, rotation_mat, rotated_size);
} else { } else {
switch (rotation_) { switch (rotation_) {
case mediapipe::RotationMode_Mode_UNKNOWN: case mediapipe::RotationMode::UNKNOWN:
case mediapipe::RotationMode_Mode_ROTATION_0: case mediapipe::RotationMode::ROTATION_0:
rotated_mat = input_mat; rotated_mat = input_mat;
break; break;
case mediapipe::RotationMode_Mode_ROTATION_90: case mediapipe::RotationMode::ROTATION_90:
cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_COUNTERCLOCKWISE); cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_COUNTERCLOCKWISE);
break; break;
case mediapipe::RotationMode_Mode_ROTATION_180: case mediapipe::RotationMode::ROTATION_180:
cv::rotate(input_mat, rotated_mat, cv::ROTATE_180); cv::rotate(input_mat, rotated_mat, cv::ROTATE_180);
break; break;
case mediapipe::RotationMode_Mode_ROTATION_270: case mediapipe::RotationMode::ROTATION_270:
cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_CLOCKWISE); cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_CLOCKWISE);
break; break;
} }
@@ -561,7 +592,7 @@ absl::Status ImageTransformationCalculator::RenderGpu(CalculatorContext* cc) {
ComputeOutputDimensions(input_width, input_height, &output_width, ComputeOutputDimensions(input_width, input_height, &output_width,
&output_height); &output_height);
if (scale_mode_ == mediapipe::ScaleMode_Mode_FILL_AND_CROP) { if (scale_mode_ == mediapipe::ScaleMode::FILL_AND_CROP) {
const float scale = const float scale =
std::min(static_cast<float>(output_width_) / input_width, std::min(static_cast<float>(output_width_) / input_width,
static_cast<float>(output_height_) / input_height); static_cast<float>(output_height_) / input_height);
@@ -628,6 +659,12 @@ absl::Status ImageTransformationCalculator::RenderGpu(CalculatorContext* cc) {
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(src1.target(), src1.name()); glBindTexture(src1.target(), src1.name());
if (interpolation_mode_ == ImageTransformationCalculatorOptions::NEAREST) {
// TODO: revert texture params.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
MP_RETURN_IF_ERROR(renderer->GlRender( MP_RETURN_IF_ERROR(renderer->GlRender(
src1.width(), src1.height(), dst.width(), dst.height(), scale_mode, src1.width(), src1.height(), dst.width(), dst.height(), scale_mode,
rotation, flip_horizontally_, flip_vertically_, rotation, flip_horizontally_, flip_vertically_,
@@ -652,8 +689,8 @@ void ImageTransformationCalculator::ComputeOutputDimensions(
if (output_width_ > 0 && output_height_ > 0) { if (output_width_ > 0 && output_height_ > 0) {
*output_width = output_width_; *output_width = output_width_;
*output_height = output_height_; *output_height = output_height_;
} else if (rotation_ == mediapipe::RotationMode_Mode_ROTATION_90 || } else if (rotation_ == mediapipe::RotationMode::ROTATION_90 ||
rotation_ == mediapipe::RotationMode_Mode_ROTATION_270) { rotation_ == mediapipe::RotationMode::ROTATION_270) {
*output_width = input_height; *output_width = input_height;
*output_height = input_width; *output_height = input_width;
} else { } else {
@@ -666,9 +703,9 @@ void ImageTransformationCalculator::ComputeOutputLetterboxPadding(
int input_width, int input_height, int output_width, int output_height, int input_width, int input_height, int output_width, int output_height,
std::array<float, 4>* padding) { std::array<float, 4>* padding) {
padding->fill(0.f); padding->fill(0.f);
if (scale_mode_ == mediapipe::ScaleMode_Mode_FIT) { if (scale_mode_ == mediapipe::ScaleMode::FIT) {
if (rotation_ == mediapipe::RotationMode_Mode_ROTATION_90 || if (rotation_ == mediapipe::RotationMode::ROTATION_90 ||
rotation_ == mediapipe::RotationMode_Mode_ROTATION_270) { rotation_ == mediapipe::RotationMode::ROTATION_270) {
std::swap(input_width, input_height); std::swap(input_width, input_height);
} }
const float input_aspect_ratio = const float input_aspect_ratio =
@@ -54,4 +54,15 @@ message ImageTransformationCalculatorOptions {
// The color for the padding. This option is only used when the scale mode is // The color for the padding. This option is only used when the scale mode is
// FIT. Default is black. This is for CPU only. // FIT. Default is black. This is for CPU only.
optional Color padding_color = 8; optional Color padding_color = 8;
// Interpolation method to use. Note that on CPU when LINEAR is specified,
// INTER_LINEAR is used for upscaling and INTER_AREA is used for downscaling.
enum InterpolationMode {
DEFAULT = 0;
LINEAR = 1;
NEAREST = 2;
}
// Mode DEFAULT will use LINEAR interpolation.
optional InterpolationMode interpolation_mode = 9;
} }
@@ -0,0 +1,315 @@
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_set.h"
#include "absl/flags/flag.h"
#include "absl/strings/substitute.h"
#include "mediapipe/framework/calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/deps/file_path.h"
#include "mediapipe/framework/formats/image_format.pb.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/port/gtest.h"
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
#include "mediapipe/framework/port/opencv_imgproc_inc.h"
#include "mediapipe/framework/port/parse_text_proto.h"
#include "testing/base/public/gmock.h"
#include "testing/base/public/googletest.h"
#include "third_party/OpenCV/core.hpp" // IWYU pragma: keep
#include "third_party/OpenCV/core/mat.hpp"
namespace mediapipe {
namespace {
absl::flat_hash_set<int> computeUniqueValues(const cv::Mat& mat) {
// Compute the unique values in cv::Mat
absl::flat_hash_set<int> unique_values;
for (int i = 0; i < mat.rows; i++) {
for (int j = 0; j < mat.cols; j++) {
unique_values.insert(mat.at<unsigned char>(i, j));
}
}
return unique_values;
}
TEST(ImageTransformationCalculatorTest, NearestNeighborResizing) {
cv::Mat input_mat;
cv::cvtColor(cv::imread(file::JoinPath("./",
"/mediapipe/calculators/"
"image/testdata/binary_mask.png")),
input_mat, cv::COLOR_BGR2GRAY);
Packet input_image_packet = MakePacket<ImageFrame>(
ImageFormat::GRAY8, input_mat.size().width, input_mat.size().height);
input_mat.copyTo(formats::MatView(&(input_image_packet.Get<ImageFrame>())));
std::vector<std::pair<int, int>> output_dims{
{256, 333}, {512, 512}, {1024, 1024}};
for (auto& output_dim : output_dims) {
Packet input_output_dim_packet =
MakePacket<std::pair<int, int>>(output_dim);
std::vector<std::string> scale_modes{"FIT", "STRETCH"};
for (const auto& scale_mode : scale_modes) {
CalculatorGraphConfig::Node node_config =
ParseTextProtoOrDie<CalculatorGraphConfig::Node>(
absl::Substitute(R"(
calculator: "ImageTransformationCalculator"
input_stream: "IMAGE:input_image"
input_stream: "OUTPUT_DIMENSIONS:image_size"
output_stream: "IMAGE:output_image"
options: {
[mediapipe.ImageTransformationCalculatorOptions.ext]: {
scale_mode: $0
interpolation_mode: NEAREST
}
})",
scale_mode));
CalculatorRunner runner(node_config);
runner.MutableInputs()->Tag("IMAGE").packets.push_back(
input_image_packet.At(Timestamp(0)));
runner.MutableInputs()
->Tag("OUTPUT_DIMENSIONS")
.packets.push_back(input_output_dim_packet.At(Timestamp(0)));
MP_ASSERT_OK(runner.Run());
const auto& outputs = runner.Outputs();
ASSERT_EQ(outputs.NumEntries(), 1);
const std::vector<Packet>& packets = outputs.Tag("IMAGE").packets;
ASSERT_EQ(packets.size(), 1);
const auto& result = packets[0].Get<ImageFrame>();
ASSERT_EQ(output_dim.first, result.Width());
ASSERT_EQ(output_dim.second, result.Height());
auto unique_input_values = computeUniqueValues(input_mat);
auto unique_output_values =
computeUniqueValues(formats::MatView(&result));
EXPECT_THAT(unique_input_values,
::testing::ContainerEq(unique_output_values));
}
}
}
TEST(ImageTransformationCalculatorTest,
NearestNeighborResizingWorksForFloatInput) {
cv::Mat input_mat;
cv::cvtColor(cv::imread(file::JoinPath("./",
"/mediapipe/calculators/"
"image/testdata/binary_mask.png")),
input_mat, cv::COLOR_BGR2GRAY);
Packet input_image_packet = MakePacket<ImageFrame>(
ImageFormat::VEC32F1, input_mat.size().width, input_mat.size().height);
cv::Mat packet_mat_view =
formats::MatView(&(input_image_packet.Get<ImageFrame>()));
input_mat.convertTo(packet_mat_view, CV_32FC1, 1 / 255.f);
std::vector<std::pair<int, int>> output_dims{
{256, 333}, {512, 512}, {1024, 1024}};
for (auto& output_dim : output_dims) {
Packet input_output_dim_packet =
MakePacket<std::pair<int, int>>(output_dim);
std::vector<std::string> scale_modes{"FIT", "STRETCH"};
for (const auto& scale_mode : scale_modes) {
CalculatorGraphConfig::Node node_config =
ParseTextProtoOrDie<CalculatorGraphConfig::Node>(
absl::Substitute(R"(
calculator: "ImageTransformationCalculator"
input_stream: "IMAGE:input_image"
input_stream: "OUTPUT_DIMENSIONS:image_size"
output_stream: "IMAGE:output_image"
options: {
[mediapipe.ImageTransformationCalculatorOptions.ext]: {
scale_mode: $0
interpolation_mode: NEAREST
}
})",
scale_mode));
CalculatorRunner runner(node_config);
runner.MutableInputs()->Tag("IMAGE").packets.push_back(
input_image_packet.At(Timestamp(0)));
runner.MutableInputs()
->Tag("OUTPUT_DIMENSIONS")
.packets.push_back(input_output_dim_packet.At(Timestamp(0)));
MP_ASSERT_OK(runner.Run());
const auto& outputs = runner.Outputs();
ASSERT_EQ(outputs.NumEntries(), 1);
const std::vector<Packet>& packets = outputs.Tag("IMAGE").packets;
ASSERT_EQ(packets.size(), 1);
const auto& result = packets[0].Get<ImageFrame>();
ASSERT_EQ(output_dim.first, result.Width());
ASSERT_EQ(output_dim.second, result.Height());
auto unique_input_values = computeUniqueValues(packet_mat_view);
auto unique_output_values =
computeUniqueValues(formats::MatView(&result));
EXPECT_THAT(unique_input_values,
::testing::ContainerEq(unique_output_values));
}
}
}
TEST(ImageTransformationCalculatorTest, NearestNeighborResizingGpu) {
cv::Mat input_mat;
cv::cvtColor(cv::imread(file::JoinPath("./",
"/mediapipe/calculators/"
"image/testdata/binary_mask.png")),
input_mat, cv::COLOR_BGR2RGBA);
std::vector<std::pair<int, int>> output_dims{
{256, 333}, {512, 512}, {1024, 1024}};
for (auto& output_dim : output_dims) {
std::vector<std::string> scale_modes{"FIT"}; //, "STRETCH"};
for (const auto& scale_mode : scale_modes) {
CalculatorGraphConfig graph_config =
ParseTextProtoOrDie<CalculatorGraphConfig>(
absl::Substitute(R"(
input_stream: "input_image"
input_stream: "image_size"
output_stream: "output_image"
node {
calculator: "ImageFrameToGpuBufferCalculator"
input_stream: "input_image"
output_stream: "input_image_gpu"
}
node {
calculator: "ImageTransformationCalculator"
input_stream: "IMAGE_GPU:input_image_gpu"
input_stream: "OUTPUT_DIMENSIONS:image_size"
output_stream: "IMAGE_GPU:output_image_gpu"
options: {
[mediapipe.ImageTransformationCalculatorOptions.ext]: {
scale_mode: $0
interpolation_mode: NEAREST
}
}
}
node {
calculator: "GpuBufferToImageFrameCalculator"
input_stream: "output_image_gpu"
output_stream: "output_image"
})",
scale_mode));
ImageFrame input_image(ImageFormat::SRGBA, input_mat.size().width,
input_mat.size().height);
input_mat.copyTo(formats::MatView(&input_image));
std::vector<Packet> output_image_packets;
tool::AddVectorSink("output_image", &graph_config, &output_image_packets);
CalculatorGraph graph(graph_config);
MP_ASSERT_OK(graph.StartRun({}));
MP_ASSERT_OK(graph.AddPacketToInputStream(
"input_image",
MakePacket<ImageFrame>(std::move(input_image)).At(Timestamp(0))));
MP_ASSERT_OK(graph.AddPacketToInputStream(
"image_size",
MakePacket<std::pair<int, int>>(output_dim).At(Timestamp(0))));
MP_ASSERT_OK(graph.WaitUntilIdle());
ASSERT_THAT(output_image_packets, testing::SizeIs(1));
const auto& output_image = output_image_packets[0].Get<ImageFrame>();
ASSERT_EQ(output_dim.first, output_image.Width());
ASSERT_EQ(output_dim.second, output_image.Height());
auto unique_input_values = computeUniqueValues(input_mat);
auto unique_output_values =
computeUniqueValues(formats::MatView(&output_image));
EXPECT_THAT(unique_input_values,
::testing::ContainerEq(unique_output_values));
}
}
}
TEST(ImageTransformationCalculatorTest,
NearestNeighborResizingWorksForFloatTexture) {
cv::Mat input_mat;
cv::cvtColor(cv::imread(file::JoinPath("./",
"/mediapipe/calculators/"
"image/testdata/binary_mask.png")),
input_mat, cv::COLOR_BGR2GRAY);
Packet input_image_packet = MakePacket<ImageFrame>(
ImageFormat::VEC32F1, input_mat.size().width, input_mat.size().height);
cv::Mat packet_mat_view =
formats::MatView(&(input_image_packet.Get<ImageFrame>()));
input_mat.convertTo(packet_mat_view, CV_32FC1, 1 / 255.f);
std::vector<std::pair<int, int>> output_dims{
{256, 333}, {512, 512}, {1024, 1024}};
for (auto& output_dim : output_dims) {
std::vector<std::string> scale_modes{"FIT"}; //, "STRETCH"};
for (const auto& scale_mode : scale_modes) {
CalculatorGraphConfig graph_config =
ParseTextProtoOrDie<CalculatorGraphConfig>(
absl::Substitute(R"(
input_stream: "input_image"
input_stream: "image_size"
output_stream: "output_image"
node {
calculator: "ImageFrameToGpuBufferCalculator"
input_stream: "input_image"
output_stream: "input_image_gpu"
}
node {
calculator: "ImageTransformationCalculator"
input_stream: "IMAGE_GPU:input_image_gpu"
input_stream: "OUTPUT_DIMENSIONS:image_size"
output_stream: "IMAGE_GPU:output_image_gpu"
options: {
[mediapipe.ImageTransformationCalculatorOptions.ext]: {
scale_mode: $0
interpolation_mode: NEAREST
}
}
}
node {
calculator: "GpuBufferToImageFrameCalculator"
input_stream: "output_image_gpu"
output_stream: "output_image"
})",
scale_mode));
std::vector<Packet> output_image_packets;
tool::AddVectorSink("output_image", &graph_config, &output_image_packets);
CalculatorGraph graph(graph_config);
MP_ASSERT_OK(graph.StartRun({}));
MP_ASSERT_OK(graph.AddPacketToInputStream(
"input_image", input_image_packet.At(Timestamp(0))));
MP_ASSERT_OK(graph.AddPacketToInputStream(
"image_size",
MakePacket<std::pair<int, int>>(output_dim).At(Timestamp(0))));
MP_ASSERT_OK(graph.WaitUntilIdle());
ASSERT_THAT(output_image_packets, testing::SizeIs(1));
const auto& output_image = output_image_packets[0].Get<ImageFrame>();
ASSERT_EQ(output_dim.first, output_image.Width());
ASSERT_EQ(output_dim.second, output_image.Height());
auto unique_input_values = computeUniqueValues(packet_mat_view);
auto unique_output_values =
computeUniqueValues(formats::MatView(&output_image));
EXPECT_THAT(unique_input_values,
::testing::ContainerEq(unique_output_values));
}
}
}
} // namespace
} // namespace mediapipe
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h" #include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame_opencv.h" #include "mediapipe/framework/formats/image_frame_opencv.h"
@@ -61,7 +62,7 @@ absl::Status OpenCvImageEncoderCalculator::Open(CalculatorContext* cc) {
absl::Status OpenCvImageEncoderCalculator::Process(CalculatorContext* cc) { absl::Status OpenCvImageEncoderCalculator::Process(CalculatorContext* cc) {
const ImageFrame& image_frame = cc->Inputs().Index(0).Get<ImageFrame>(); const ImageFrame& image_frame = cc->Inputs().Index(0).Get<ImageFrame>();
CHECK_EQ(1, image_frame.ByteDepth()); ABSL_CHECK_EQ(1, image_frame.ByteDepth());
std::unique_ptr<OpenCvImageEncoderCalculatorResults> encoded_result = std::unique_ptr<OpenCvImageEncoderCalculatorResults> encoded_result =
absl::make_unique<OpenCvImageEncoderCalculatorResults>(); absl::make_unique<OpenCvImageEncoderCalculatorResults>();
@@ -18,6 +18,8 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h" #include "absl/strings/substitute.h"
#include "libyuv/scale.h" #include "libyuv/scale.h"
@@ -293,7 +295,7 @@ absl::Status ScaleImageCalculator::InitializeFrameInfo(CalculatorContext* cc) {
header->width = output_width_; header->width = output_width_;
header->height = output_height_; header->height = output_height_;
header->format = output_format_; header->format = output_format_;
LOG(INFO) << "OUTPUTTING HEADER on stream"; ABSL_LOG(INFO) << "OUTPUTTING HEADER on stream";
cc->Outputs() cc->Outputs()
.Tag("VIDEO_HEADER") .Tag("VIDEO_HEADER")
.Add(header.release(), Timestamp::PreStream()); .Add(header.release(), Timestamp::PreStream());
@@ -393,10 +395,11 @@ absl::Status ScaleImageCalculator::Open(CalculatorContext* cc) {
.SetHeader(Adopt(output_header.release())); .SetHeader(Adopt(output_header.release()));
has_header_ = true; has_header_ = true;
} else { } else {
LOG(WARNING) << "Stream had a VideoHeader which didn't have sufficient " ABSL_LOG(WARNING)
"information. " << "Stream had a VideoHeader which didn't have sufficient "
"Dropping VideoHeader and trying to deduce needed " "information. "
"information."; "Dropping VideoHeader and trying to deduce needed "
"information.";
input_width_ = 0; input_width_ = 0;
input_height_ = 0; input_height_ = 0;
if (!options_.has_input_format()) { if (!options_.has_input_format()) {
@@ -507,7 +510,7 @@ absl::Status ScaleImageCalculator::ValidateImageFrame(
absl::Status ScaleImageCalculator::ValidateYUVImage(CalculatorContext* cc, absl::Status ScaleImageCalculator::ValidateYUVImage(CalculatorContext* cc,
const YUVImage& yuv_image) { const YUVImage& yuv_image) {
CHECK_EQ(input_format_, ImageFormat::YCBCR420P); ABSL_CHECK_EQ(input_format_, ImageFormat::YCBCR420P);
if (!has_header_) { if (!has_header_) {
if (input_width_ != yuv_image.width() || if (input_width_ != yuv_image.width() ||
input_height_ != yuv_image.height()) { input_height_ != yuv_image.height()) {
@@ -18,6 +18,7 @@
#include <string> #include <string>
#include "absl/log/absl_check.h"
#include "absl/strings/str_split.h" #include "absl/strings/str_split.h"
#include "mediapipe/framework/port/logging.h" #include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/ret_check.h" #include "mediapipe/framework/port/ret_check.h"
@@ -40,10 +41,10 @@ absl::Status FindCropDimensions(int input_width, int input_height, //
const std::string& max_aspect_ratio, // const std::string& max_aspect_ratio, //
int* crop_width, int* crop_height, // int* crop_width, int* crop_height, //
int* col_start, int* row_start) { int* col_start, int* row_start) {
CHECK(crop_width); ABSL_CHECK(crop_width);
CHECK(crop_height); ABSL_CHECK(crop_height);
CHECK(col_start); ABSL_CHECK(col_start);
CHECK(row_start); ABSL_CHECK(row_start);
double min_aspect_ratio_q = 0.0; double min_aspect_ratio_q = 0.0;
double max_aspect_ratio_q = 0.0; double max_aspect_ratio_q = 0.0;
@@ -83,8 +84,8 @@ absl::Status FindCropDimensions(int input_width, int input_height, //
} }
} }
CHECK_LE(*crop_width, input_width); ABSL_CHECK_LE(*crop_width, input_width);
CHECK_LE(*crop_height, input_height); ABSL_CHECK_LE(*crop_height, input_height);
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -96,8 +97,8 @@ absl::Status FindOutputDimensions(int input_width, //
bool preserve_aspect_ratio, // bool preserve_aspect_ratio, //
int scale_to_multiple_of, // int scale_to_multiple_of, //
int* output_width, int* output_height) { int* output_width, int* output_height) {
CHECK(output_width); ABSL_CHECK(output_width);
CHECK(output_height); ABSL_CHECK(output_height);
if (target_max_area > 0 && input_width * input_height > target_max_area) { if (target_max_area > 0 && input_width * input_height > target_max_area) {
preserve_aspect_ratio = true; preserve_aspect_ratio = true;
@@ -15,13 +15,13 @@
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h" #include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_options.pb.h" #include "mediapipe/framework/calculator_options.pb.h"
#include "mediapipe/framework/formats/image.h" #include "mediapipe/framework/formats/image.h"
#include "mediapipe/framework/formats/image_format.pb.h" #include "mediapipe/framework/formats/image_format.pb.h"
#include "mediapipe/framework/formats/image_frame.h" #include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/status.h" #include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/vector.h" #include "mediapipe/framework/port/vector.h"
@@ -273,7 +273,7 @@ absl::Status SegmentationSmoothingCalculator::RenderGpu(CalculatorContext* cc) {
const auto& previous_frame = cc->Inputs().Tag(kPreviousMaskTag).Get<Image>(); const auto& previous_frame = cc->Inputs().Tag(kPreviousMaskTag).Get<Image>();
if (previous_frame.format() != current_frame.format()) { if (previous_frame.format() != current_frame.format()) {
LOG(ERROR) << "Warning: mixing input format types. "; ABSL_LOG(ERROR) << "Warning: mixing input format types. ";
} }
auto previous_texture = gpu_helper_.CreateSourceTexture(previous_frame); auto previous_texture = gpu_helper_.CreateSourceTexture(previous_frame);
@@ -14,6 +14,7 @@
#include <memory> #include <memory>
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h" #include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h" #include "mediapipe/framework/calculator_runner.h"
@@ -169,7 +170,7 @@ void RunTest(bool use_gpu, float mix_ratio, cv::Mat& test_result) {
} }
} }
} else { } else {
LOG(ERROR) << "invalid ratio"; ABSL_LOG(ERROR) << "invalid ratio";
} }
} }
@@ -14,13 +14,13 @@
#include <memory> #include <memory>
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/image/set_alpha_calculator.pb.h" #include "mediapipe/calculators/image/set_alpha_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_options.pb.h" #include "mediapipe/framework/calculator_options.pb.h"
#include "mediapipe/framework/formats/image_format.pb.h" #include "mediapipe/framework/formats/image_format.pb.h"
#include "mediapipe/framework/formats/image_frame.h" #include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h" #include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/opencv_core_inc.h" #include "mediapipe/framework/port/opencv_core_inc.h"
#include "mediapipe/framework/port/opencv_imgproc_inc.h" #include "mediapipe/framework/port/opencv_imgproc_inc.h"
#include "mediapipe/framework/port/status.h" #include "mediapipe/framework/port/status.h"
@@ -268,7 +268,7 @@ absl::Status SetAlphaCalculator::RenderCpu(CalculatorContext* cc) {
const auto& input_frame = cc->Inputs().Tag(kInputFrameTag).Get<ImageFrame>(); const auto& input_frame = cc->Inputs().Tag(kInputFrameTag).Get<ImageFrame>();
const cv::Mat input_mat = formats::MatView(&input_frame); const cv::Mat input_mat = formats::MatView(&input_frame);
if (!(input_mat.type() == CV_8UC3 || input_mat.type() == CV_8UC4)) { if (!(input_mat.type() == CV_8UC3 || input_mat.type() == CV_8UC4)) {
LOG(ERROR) << "Only 3 or 4 channel 8-bit input image supported"; ABSL_LOG(ERROR) << "Only 3 or 4 channel 8-bit input image supported";
} }
// Setup destination image // Setup destination image
@@ -328,7 +328,7 @@ absl::Status SetAlphaCalculator::RenderGpu(CalculatorContext* cc) {
cc->Inputs().Tag(kInputFrameTagGpu).Get<mediapipe::GpuBuffer>(); cc->Inputs().Tag(kInputFrameTagGpu).Get<mediapipe::GpuBuffer>();
if (!(input_frame.format() == mediapipe::GpuBufferFormat::kBGRA32 || if (!(input_frame.format() == mediapipe::GpuBufferFormat::kBGRA32 ||
input_frame.format() == mediapipe::GpuBufferFormat::kRGB24)) { input_frame.format() == mediapipe::GpuBufferFormat::kRGB24)) {
LOG(ERROR) << "Only RGB or RGBA input image supported"; ABSL_LOG(ERROR) << "Only RGB or RGBA input image supported";
} }
auto input_texture = gpu_helper_.CreateSourceTexture(input_frame); auto input_texture = gpu_helper_.CreateSourceTexture(input_frame);
+1
View File
@@ -18,6 +18,7 @@ licenses(["notice"])
filegroup( filegroup(
name = "test_images", name = "test_images",
srcs = [ srcs = [
"binary_mask.png",
"dino.jpg", "dino.jpg",
"dino_quality_50.jpg", "dino_quality_50.jpg",
"dino_quality_80.jpg", "dino_quality_80.jpg",
Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

@@ -79,8 +79,8 @@ class WarpAffineRunnerHolder<ImageFrame> {
} }
absl::StatusOr<RunnerType*> GetRunner() { absl::StatusOr<RunnerType*> GetRunner() {
if (!runner_) { if (!runner_) {
ASSIGN_OR_RETURN(runner_, MP_ASSIGN_OR_RETURN(
CreateAffineTransformationOpenCvRunner(interpolation_)); runner_, CreateAffineTransformationOpenCvRunner(interpolation_));
} }
return runner_.get(); return runner_.get();
} }
@@ -108,8 +108,9 @@ class WarpAffineRunnerHolder<mediapipe::GpuBuffer> {
} }
absl::StatusOr<RunnerType*> GetRunner() { absl::StatusOr<RunnerType*> GetRunner() {
if (!runner_) { if (!runner_) {
ASSIGN_OR_RETURN(runner_, CreateAffineTransformationGlRunner( MP_ASSIGN_OR_RETURN(
gl_helper_, gpu_origin_, interpolation_)); runner_, CreateAffineTransformationGlRunner(gl_helper_, gpu_origin_,
interpolation_));
} }
return runner_.get(); return runner_.get();
} }
@@ -151,24 +152,25 @@ class WarpAffineRunnerHolder<mediapipe::Image> {
AffineTransformation::BorderMode border_mode) override { AffineTransformation::BorderMode border_mode) override {
if (input.UsesGpu()) { if (input.UsesGpu()) {
#if !MEDIAPIPE_DISABLE_GPU #if !MEDIAPIPE_DISABLE_GPU
ASSIGN_OR_RETURN(auto* runner, gpu_holder_.GetRunner()); MP_ASSIGN_OR_RETURN(auto* runner, gpu_holder_.GetRunner());
ASSIGN_OR_RETURN(auto result, runner->Run(input.GetGpuBuffer(), matrix, MP_ASSIGN_OR_RETURN(
size, border_mode)); auto result,
runner->Run(input.GetGpuBuffer(), matrix, size, border_mode));
return mediapipe::Image(*result); return mediapipe::Image(*result);
#else #else
return absl::UnavailableError("GPU support is disabled"); return absl::UnavailableError("GPU support is disabled");
#endif // !MEDIAPIPE_DISABLE_GPU #endif // !MEDIAPIPE_DISABLE_GPU
} }
#if !MEDIAPIPE_DISABLE_OPENCV #if !MEDIAPIPE_DISABLE_OPENCV
ASSIGN_OR_RETURN(auto* runner, cpu_holder_.GetRunner()); MP_ASSIGN_OR_RETURN(auto* runner, cpu_holder_.GetRunner());
const auto& frame_ptr = input.GetImageFrameSharedPtr(); const auto& frame_ptr = input.GetImageFrameSharedPtr();
// Wrap image into image frame. // Wrap image into image frame.
const ImageFrame image_frame(frame_ptr->Format(), frame_ptr->Width(), const ImageFrame image_frame(frame_ptr->Format(), frame_ptr->Width(),
frame_ptr->Height(), frame_ptr->WidthStep(), frame_ptr->Height(), frame_ptr->WidthStep(),
const_cast<uint8_t*>(frame_ptr->PixelData()), const_cast<uint8_t*>(frame_ptr->PixelData()),
[](uint8_t* data){}); [](uint8_t* data){});
ASSIGN_OR_RETURN(auto result, MP_ASSIGN_OR_RETURN(auto result,
runner->Run(image_frame, matrix, size, border_mode)); runner->Run(image_frame, matrix, size, border_mode));
return mediapipe::Image(std::make_shared<ImageFrame>(std::move(result))); return mediapipe::Image(std::make_shared<ImageFrame>(std::move(result)));
#else #else
return absl::UnavailableError("OpenCV support is disabled"); return absl::UnavailableError("OpenCV support is disabled");
@@ -213,8 +215,8 @@ class WarpAffineCalculatorImpl : public mediapipe::api2::NodeImpl<InterfaceT> {
AffineTransformation::Size output_size; AffineTransformation::Size output_size;
output_size.width = out_width; output_size.width = out_width;
output_size.height = out_height; output_size.height = out_height;
ASSIGN_OR_RETURN(auto* runner, holder_.GetRunner()); MP_ASSIGN_OR_RETURN(auto* runner, holder_.GetRunner());
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
auto result, auto result,
runner->Run( runner->Run(
*InterfaceT::kInImage(cc), transform, output_size, *InterfaceT::kInImage(cc), transform, output_size,
+2
View File
@@ -31,12 +31,14 @@ mediapipe_proto_library(
cc_library( cc_library(
name = "callback_packet_calculator", name = "callback_packet_calculator",
srcs = ["callback_packet_calculator.cc"], srcs = ["callback_packet_calculator.cc"],
hdrs = ["callback_packet_calculator.h"],
visibility = ["//mediapipe/framework:__subpackages__"], visibility = ["//mediapipe/framework:__subpackages__"],
deps = [ deps = [
":callback_packet_calculator_cc_proto", ":callback_packet_calculator_cc_proto",
"//mediapipe/framework:calculator_base", "//mediapipe/framework:calculator_base",
"//mediapipe/framework:calculator_registry", "//mediapipe/framework:calculator_registry",
"//mediapipe/framework:output_side_packet", "//mediapipe/framework:output_side_packet",
"@com_google_absl//absl/status",
], ],
alwayslink = 1, alwayslink = 1,
) )
@@ -11,10 +11,12 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "mediapipe/calculators/internal/callback_packet_calculator.h"
#include <functional> #include <functional>
#include <string> #include <string>
#include "absl/status/status.h"
#include "mediapipe/calculators/internal/callback_packet_calculator.pb.h" // NOLINT #include "mediapipe/calculators/internal/callback_packet_calculator.pb.h" // NOLINT
#include "mediapipe/framework/calculator_base.h" #include "mediapipe/framework/calculator_base.h"
#include "mediapipe/framework/calculator_registry.h" #include "mediapipe/framework/calculator_registry.h"
@@ -39,64 +41,55 @@ void DumpPostStreamPacket(Packet* post_stream_packet, const Packet& packet) {
*post_stream_packet = packet; *post_stream_packet = packet;
} }
} }
} // namespace } // namespace
// Creates a callback which takes a packet and stores it either in a absl::Status CallbackPacketCalculator::GetContract(CalculatorContract* cc) {
// vector of packets or stores only the packet at PostStream timestamp. const auto& options = cc->Options<CallbackPacketCalculatorOptions>();
// The kind of callback is controlled by an option. The callback is switch (options.type()) {
// a std::function and is directly usable by CallbackCalculator. case CallbackPacketCalculatorOptions::VECTOR_PACKET:
// Since the options for the packet generator include a serialized pointer case CallbackPacketCalculatorOptions::POST_STREAM_PACKET:
// value, the resulting callback is only valid on the original machine cc->OutputSidePackets()
// while that pointer is still alive. .Index(0)
class CallbackPacketCalculator : public CalculatorBase { .Set<std::function<void(const Packet&)>>();
public: break;
static absl::Status GetContract(CalculatorContract* cc) { default:
const auto& options = cc->Options<CallbackPacketCalculatorOptions>();
switch (options.type()) {
case CallbackPacketCalculatorOptions::VECTOR_PACKET:
case CallbackPacketCalculatorOptions::POST_STREAM_PACKET:
cc->OutputSidePackets()
.Index(0)
.Set<std::function<void(const Packet&)>>();
break;
default:
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Invalid type of callback to produce.";
}
return absl::OkStatus();
}
absl::Status Open(CalculatorContext* cc) override {
const auto& options = cc->Options<CallbackPacketCalculatorOptions>();
void* ptr;
if (sscanf(options.pointer().c_str(), "%p", &ptr) != 1) {
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC) return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Stored pointer value in options is invalid."; << "Invalid type of callback to produce.";
}
switch (options.type()) {
case CallbackPacketCalculatorOptions::VECTOR_PACKET:
cc->OutputSidePackets().Index(0).Set(
MakePacket<std::function<void(const Packet&)>>(std::bind(
&DumpToVector, reinterpret_cast<std::vector<Packet>*>(ptr),
std::placeholders::_1)));
break;
case CallbackPacketCalculatorOptions::POST_STREAM_PACKET:
cc->OutputSidePackets().Index(0).Set(
MakePacket<std::function<void(const Packet&)>>(
std::bind(&DumpPostStreamPacket, reinterpret_cast<Packet*>(ptr),
std::placeholders::_1)));
break;
default:
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Invalid type to dump into.";
}
return absl::OkStatus();
} }
return absl::OkStatus();
}
absl::Status Process(CalculatorContext* cc) override { absl::Status CallbackPacketCalculator::Open(CalculatorContext* cc) {
return absl::OkStatus(); const auto& options = cc->Options<CallbackPacketCalculatorOptions>();
void* ptr;
if (sscanf(options.pointer().c_str(), "%p", &ptr) != 1) {
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Stored pointer value in options is invalid.";
} }
}; switch (options.type()) {
case CallbackPacketCalculatorOptions::VECTOR_PACKET:
cc->OutputSidePackets().Index(0).Set(
MakePacket<std::function<void(const Packet&)>>(std::bind(
&DumpToVector, reinterpret_cast<std::vector<Packet>*>(ptr),
std::placeholders::_1)));
break;
case CallbackPacketCalculatorOptions::POST_STREAM_PACKET:
cc->OutputSidePackets().Index(0).Set(
MakePacket<std::function<void(const Packet&)>>(
std::bind(&DumpPostStreamPacket, reinterpret_cast<Packet*>(ptr),
std::placeholders::_1)));
break;
default:
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Invalid type to dump into.";
}
return absl::OkStatus();
}
absl::Status CallbackPacketCalculator::Process(CalculatorContext* cc) {
return absl::OkStatus();
}
REGISTER_CALCULATOR(CallbackPacketCalculator); REGISTER_CALCULATOR(CallbackPacketCalculator);
@@ -0,0 +1,39 @@
// 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.
#ifndef MEDIAPIPE_CALCULATORS_INTERNAL_CALLBACK_PACKET_CALCULATOR_H_
#define MEDIAPIPE_CALCULATORS_INTERNAL_CALLBACK_PACKET_CALCULATOR_H_
#include "absl/status/status.h"
#include "mediapipe/framework/calculator_base.h"
namespace mediapipe {
// Creates a callback which takes a packet and stores it either in a
// vector of packets or stores only the packet at PostStream timestamp.
// The kind of callback is controlled by an option. The callback is
// a std::function and is directly usable by CallbackCalculator.
// Since the options for the packet generator include a serialized pointer
// value, the resulting callback is only valid on the original machine
// while that pointer is still alive.
class CallbackPacketCalculator : public CalculatorBase {
public:
static absl::Status GetContract(CalculatorContract* cc);
absl::Status Open(CalculatorContext* cc) override;
absl::Status Process(CalculatorContext* cc) override;
};
} // namespace mediapipe
#endif // MEDIAPIPE_CALCULATORS_INTERNAL_CALLBACK_PACKET_CALCULATOR_H_
+68
View File
@@ -87,6 +87,7 @@ cc_library(
"//mediapipe/framework/formats:time_series_header_cc_proto", "//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/util:time_series_util", "//mediapipe/util:time_series_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/status", "@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor", "@com_google_absl//absl/status:statusor",
@@ -181,6 +182,7 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/api2:node", "//mediapipe/framework/api2:node",
"//mediapipe/framework/formats:tensor", "//mediapipe/framework/formats:tensor",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/status", "@com_google_absl//absl/status",
], ],
alwayslink = 1, alwayslink = 1,
@@ -198,6 +200,7 @@ cc_test(
"//mediapipe/framework/formats:tensor", "//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:gtest_main", "//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:parse_text_proto", "//mediapipe/framework/port:parse_text_proto",
"@com_google_absl//absl/log:absl_check",
"@org_tensorflow//tensorflow/lite/c:common", "@org_tensorflow//tensorflow/lite/c:common",
], ],
) )
@@ -445,6 +448,7 @@ cc_library(
"//mediapipe/framework/deps:file_path", "//mediapipe/framework/deps:file_path",
"//mediapipe/gpu:gl_calculator_helper", "//mediapipe/gpu:gl_calculator_helper",
"//mediapipe/util/tflite:tflite_gpu_runner", "//mediapipe/util/tflite:tflite_gpu_runner",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/status", "@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor", "@com_google_absl//absl/status:statusor",
@@ -474,6 +478,7 @@ cc_library(
"//mediapipe/gpu:gpu_buffer", "//mediapipe/gpu:gpu_buffer",
"//mediapipe/objc:mediapipe_framework_ios", "//mediapipe/objc:mediapipe_framework_ios",
"//mediapipe/util/tflite:config", "//mediapipe/util/tflite:config",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/strings:str_format",
"@org_tensorflow//tensorflow/lite/delegates/gpu:metal_delegate", "@org_tensorflow//tensorflow/lite/delegates/gpu:metal_delegate",
@@ -620,6 +625,7 @@ mediapipe_proto_library(
deps = [ deps = [
"//mediapipe/framework:calculator_options_proto", "//mediapipe/framework:calculator_options_proto",
"//mediapipe/framework:calculator_proto", "//mediapipe/framework:calculator_proto",
"//mediapipe/gpu:gpu_origin_proto",
], ],
) )
@@ -649,7 +655,18 @@ cc_library(
"//mediapipe/framework/formats:matrix", "//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:tensor", "//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/framework/port:statusor",
"//mediapipe/gpu:gpu_buffer_format",
"//mediapipe/gpu:gpu_origin_cc_proto",
"//mediapipe/util:resource_util", "//mediapipe/util:resource_util",
"@com_google_absl//absl/log",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings:str_format",
] + select({ ] + select({
"//mediapipe/gpu:disable_gpu": [], "//mediapipe/gpu:disable_gpu": [],
"//conditions:default": ["tensor_converter_calculator_gpu_deps"], "//conditions:default": ["tensor_converter_calculator_gpu_deps"],
@@ -699,9 +716,11 @@ cc_test(
"//mediapipe/framework/formats:tensor", "//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:gtest_main", "//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:integral_types", "//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:opencv_core",
"//mediapipe/framework/port:parse_text_proto", "//mediapipe/framework/port:parse_text_proto",
"//mediapipe/framework/tool:validate_type", "//mediapipe/framework/tool:validate_type",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
], ],
) )
@@ -737,6 +756,8 @@ cc_library(
"//mediapipe/framework/formats:tensor", "//mediapipe/framework/formats:tensor",
"//mediapipe/framework/formats/object_detection:anchor_cc_proto", "//mediapipe/framework/formats/object_detection:anchor_cc_proto",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/types:span", "@com_google_absl//absl/types:span",
] + selects.with_or({ ] + selects.with_or({
@@ -793,6 +814,7 @@ cc_library(
"//mediapipe/framework/formats:landmark_cc_proto", "//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:tensor", "//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"@com_google_absl//absl/log:absl_check",
], ],
alwayslink = 1, alwayslink = 1,
) )
@@ -958,6 +980,48 @@ cc_test(
], ],
) )
cc_library(
name = "tensor_to_joints_calculator",
srcs = ["tensor_to_joints_calculator.cc"],
hdrs = ["tensor_to_joints_calculator.h"],
deps = [
":tensor_to_joints_calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/api2:node",
"//mediapipe/framework/formats:body_rig_cc_proto",
"//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
],
alwayslink = 1,
)
mediapipe_proto_library(
name = "tensor_to_joints_calculator_proto",
srcs = ["tensor_to_joints_calculator.proto"],
deps = [
"//mediapipe/framework:calculator_options_proto",
"//mediapipe/framework:calculator_proto",
],
)
cc_test(
name = "tensor_to_joints_calculator_test",
srcs = ["tensor_to_joints_calculator_test.cc"],
deps = [
":tensor_to_joints_calculator",
":tensor_to_joints_calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:calculator_runner",
"//mediapipe/framework:timestamp",
"//mediapipe/framework/formats:body_rig_cc_proto",
"//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:parse_text_proto",
"@com_google_absl//absl/strings",
],
)
cc_library( cc_library(
name = "image_to_tensor_calculator", name = "image_to_tensor_calculator",
srcs = ["image_to_tensor_calculator.cc"], srcs = ["image_to_tensor_calculator.cc"],
@@ -985,6 +1049,8 @@ cc_library(
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/port:statusor", "//mediapipe/framework/port:statusor",
"//mediapipe/gpu:gpu_origin_cc_proto", "//mediapipe/gpu:gpu_origin_cc_proto",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
] + select({ ] + select({
"//mediapipe/gpu:disable_gpu": [], "//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [":image_to_tensor_calculator_gpu_deps"], "//conditions:default": [":image_to_tensor_calculator_gpu_deps"],
@@ -1077,6 +1143,7 @@ cc_test(
"//mediapipe/framework/port:parse_text_proto", "//mediapipe/framework/port:parse_text_proto",
"//mediapipe/util:image_test_utils", "//mediapipe/util:image_test_utils",
"@com_google_absl//absl/flags:flag", "@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/strings:str_format",
@@ -1204,6 +1271,7 @@ cc_library(
"//mediapipe/gpu:gl_calculator_helper", "//mediapipe/gpu:gl_calculator_helper",
"//mediapipe/gpu:gl_simple_shaders", "//mediapipe/gpu:gl_simple_shaders",
"//mediapipe/gpu:shader_util", "//mediapipe/gpu:shader_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
], ],
}), }),
@@ -20,6 +20,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "absl/log/absl_check.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
@@ -348,7 +349,7 @@ absl::Status AudioToTensorCalculator::Process(CalculatorContext* cc) {
return absl::InvalidArgumentError( return absl::InvalidArgumentError(
"The audio data should be stored in column-major."); "The audio data should be stored in column-major.");
} }
CHECK(channels_match || mono_output); ABSL_CHECK(channels_match || mono_output);
const Matrix& input = channels_match ? input_frame const Matrix& input = channels_match ? input_frame
// Mono mixdown. // Mono mixdown.
: input_frame.colwise().mean(); : input_frame.colwise().mean();
@@ -457,7 +458,7 @@ absl::Status AudioToTensorCalculator::SetupStreamingResampler(
} }
void AudioToTensorCalculator::AppendZerosToSampleBuffer(int num_samples) { void AudioToTensorCalculator::AppendZerosToSampleBuffer(int num_samples) {
CHECK_GE(num_samples, 0); // Ensured by `UpdateContract`. ABSL_CHECK_GE(num_samples, 0); // Ensured by `UpdateContract`.
if (num_samples == 0) { if (num_samples == 0) {
return; return;
} }
@@ -516,8 +517,8 @@ absl::Status AudioToTensorCalculator::OutputTensor(const Matrix& block,
// The last two elements are Nyquist component. // The last two elements are Nyquist component.
fft_output_matrix(fft_size_ - 2) = fft_output_[1]; // Nyquist real part fft_output_matrix(fft_size_ - 2) = fft_output_[1]; // Nyquist real part
fft_output_matrix(fft_size_ - 1) = 0.0f; // Nyquist imagery part fft_output_matrix(fft_size_ - 1) = 0.0f; // Nyquist imagery part
ASSIGN_OR_RETURN(output_tensor, ConvertToTensor(fft_output_matrix, MP_ASSIGN_OR_RETURN(output_tensor, ConvertToTensor(fft_output_matrix,
{2, fft_size_ / 2})); {2, fft_size_ / 2}));
break; break;
} }
case Options::WITH_DC_AND_NYQUIST: { case Options::WITH_DC_AND_NYQUIST: {
@@ -528,7 +529,7 @@ absl::Status AudioToTensorCalculator::OutputTensor(const Matrix& block,
// The last two elements are Nyquist component. // The last two elements are Nyquist component.
fft_output_matrix(fft_size_) = fft_output_[1]; // Nyquist real part fft_output_matrix(fft_size_) = fft_output_[1]; // Nyquist real part
fft_output_matrix(fft_size_ + 1) = 0.0f; // Nyquist imagery part fft_output_matrix(fft_size_ + 1) = 0.0f; // Nyquist imagery part
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
output_tensor, output_tensor,
ConvertToTensor(fft_output_matrix, {2, (fft_size_ + 2) / 2})); ConvertToTensor(fft_output_matrix, {2, (fft_size_ + 2) / 2}));
break; break;
@@ -536,7 +537,7 @@ absl::Status AudioToTensorCalculator::OutputTensor(const Matrix& block,
case Options::WITHOUT_DC_AND_NYQUIST: { case Options::WITHOUT_DC_AND_NYQUIST: {
Matrix fft_output_matrix = Matrix fft_output_matrix =
Eigen::Map<const Matrix>(fft_output_.data() + 2, 1, fft_size_ - 2); Eigen::Map<const Matrix>(fft_output_.data() + 2, 1, fft_size_ - 2);
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
output_tensor, output_tensor,
ConvertToTensor(fft_output_matrix, {2, (fft_size_ - 2) / 2})); ConvertToTensor(fft_output_matrix, {2, (fft_size_ - 2) / 2}));
break; break;
@@ -546,8 +547,8 @@ absl::Status AudioToTensorCalculator::OutputTensor(const Matrix& block,
} }
} else { } else {
ASSIGN_OR_RETURN(output_tensor, MP_ASSIGN_OR_RETURN(output_tensor,
ConvertToTensor(block, {num_channels_, num_samples_})); ConvertToTensor(block, {num_channels_, num_samples_}));
} }
kTensorsOut(cc).Send(std::move(output_tensor), timestamp); kTensorsOut(cc).Send(std::move(output_tensor), timestamp);
return absl::OkStatus(); return absl::OkStatus();
@@ -161,9 +161,9 @@ absl::Status BertPreprocessorCalculator::Open(CalculatorContext* cc) {
&kMetadataExtractorSideIn(cc).Get(); &kMetadataExtractorSideIn(cc).Get();
const tflite::ProcessUnit* tokenizer_metadata = const tflite::ProcessUnit* tokenizer_metadata =
metadata_extractor->GetInputProcessUnit(kTokenizerProcessUnitIndex); metadata_extractor->GetInputProcessUnit(kTokenizerProcessUnitIndex);
ASSIGN_OR_RETURN(tokenizer_, MP_ASSIGN_OR_RETURN(tokenizer_,
tasks::text::tokenizers::CreateTokenizerFromProcessUnit( tasks::text::tokenizers::CreateTokenizerFromProcessUnit(
tokenizer_metadata, metadata_extractor)); tokenizer_metadata, metadata_extractor));
auto* input_tensors_metadata = metadata_extractor->GetInputTensorMetadata(); auto* input_tensors_metadata = metadata_extractor->GetInputTensorMetadata();
input_ids_tensor_index_ = FindTensorIndexByMetadataName( input_ids_tensor_index_ = FindTensorIndexByMetadataName(
@@ -67,9 +67,10 @@ absl::StatusOr<std::vector<std::vector<int>>> RunBertPreprocessorCalculator(
tool::AddVectorSink("tensors", &graph_config, &output_packets); tool::AddVectorSink("tensors", &graph_config, &output_packets);
std::string model_buffer = tasks::core::LoadBinaryContent(model_path.data()); std::string model_buffer = tasks::core::LoadBinaryContent(model_path.data());
ASSIGN_OR_RETURN(std::unique_ptr<ModelMetadataExtractor> metadata_extractor, MP_ASSIGN_OR_RETURN(
ModelMetadataExtractor::CreateFromModelBuffer( std::unique_ptr<ModelMetadataExtractor> metadata_extractor,
model_buffer.data(), model_buffer.size())); ModelMetadataExtractor::CreateFromModelBuffer(model_buffer.data(),
model_buffer.size()));
// Run the graph. // Run the graph.
CalculatorGraph graph; CalculatorGraph graph;
MP_RETURN_IF_ERROR(graph.Initialize( MP_RETURN_IF_ERROR(graph.Initialize(
@@ -18,6 +18,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/tensor/feedback_tensors_calculator.pb.h" #include "mediapipe/calculators/tensor/feedback_tensors_calculator.pb.h"
#include "mediapipe/framework/calculator.pb.h" #include "mediapipe/framework/calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
@@ -65,7 +66,7 @@ template <typename T>
Tensor MakeTensor(std::initializer_list<int> shape, Tensor MakeTensor(std::initializer_list<int> shape,
std::initializer_list<T> values) { std::initializer_list<T> values) {
Tensor tensor(TensorElementType<T>::value, shape); Tensor tensor(TensorElementType<T>::value, shape);
CHECK_EQ(values.size(), tensor.shape().num_elements()) ABSL_CHECK_EQ(values.size(), tensor.shape().num_elements())
<< "The size of `values` is incompatible with `shape`"; << "The size of `values` is incompatible with `shape`";
absl::c_copy(values, tensor.GetCpuWriteView().buffer<T>()); absl::c_copy(values, tensor.GetCpuWriteView().buffer<T>());
return tensor; return tensor;
@@ -16,6 +16,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/tensor/image_to_tensor_calculator.pb.h" #include "mediapipe/calculators/tensor/image_to_tensor_calculator.pb.h"
#include "mediapipe/calculators/tensor/image_to_tensor_converter.h" #include "mediapipe/calculators/tensor/image_to_tensor_converter.h"
#include "mediapipe/calculators/tensor/image_to_tensor_utils.h" #include "mediapipe/calculators/tensor/image_to_tensor_utils.h"
@@ -191,18 +192,19 @@ class ImageToTensorCalculator : public Node {
} }
#if MEDIAPIPE_DISABLE_GPU #if MEDIAPIPE_DISABLE_GPU
ASSIGN_OR_RETURN(auto image, GetInputImage(kIn(cc))); MP_ASSIGN_OR_RETURN(auto image, GetInputImage(kIn(cc)));
#else #else
const bool is_input_gpu = kInGpu(cc).IsConnected(); const bool is_input_gpu = kInGpu(cc).IsConnected();
ASSIGN_OR_RETURN(auto image, is_input_gpu ? GetInputImage(kInGpu(cc)) MP_ASSIGN_OR_RETURN(auto image, is_input_gpu ? GetInputImage(kInGpu(cc))
: GetInputImage(kIn(cc))); : GetInputImage(kIn(cc)));
#endif // MEDIAPIPE_DISABLE_GPU #endif // MEDIAPIPE_DISABLE_GPU
RotatedRect roi = GetRoi(image->width(), image->height(), norm_rect); RotatedRect roi = GetRoi(image->width(), image->height(), norm_rect);
const int tensor_width = params_.output_width.value_or(image->width()); const int tensor_width = params_.output_width.value_or(image->width());
const int tensor_height = params_.output_height.value_or(image->height()); const int tensor_height = params_.output_height.value_or(image->height());
ASSIGN_OR_RETURN(auto padding, PadRoi(tensor_width, tensor_height, MP_ASSIGN_OR_RETURN(auto padding,
options_.keep_aspect_ratio(), &roi)); PadRoi(tensor_width, tensor_height,
options_.keep_aspect_ratio(), &roi));
if (kOutLetterboxPadding(cc).IsConnected()) { if (kOutLetterboxPadding(cc).IsConnected()) {
kOutLetterboxPadding(cc).Send(padding); kOutLetterboxPadding(cc).Send(padding);
} }
@@ -246,20 +248,20 @@ class ImageToTensorCalculator : public Node {
if (!gpu_converter_) { if (!gpu_converter_) {
#if !MEDIAPIPE_DISABLE_GPU #if !MEDIAPIPE_DISABLE_GPU
#if MEDIAPIPE_METAL_ENABLED #if MEDIAPIPE_METAL_ENABLED
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
gpu_converter_, gpu_converter_,
CreateMetalConverter(cc, GetBorderMode(options_.border_mode()))); CreateMetalConverter(cc, GetBorderMode(options_.border_mode())));
#elif MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #elif MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
ASSIGN_OR_RETURN(gpu_converter_, MP_ASSIGN_OR_RETURN(gpu_converter_,
CreateImageToGlBufferTensorConverter( CreateImageToGlBufferTensorConverter(
cc, DoesGpuInputStartAtBottom(options_), cc, DoesGpuInputStartAtBottom(options_),
GetBorderMode(options_.border_mode()))); GetBorderMode(options_.border_mode())));
#else #else
if (!gpu_converter_) { if (!gpu_converter_) {
ASSIGN_OR_RETURN(gpu_converter_, MP_ASSIGN_OR_RETURN(gpu_converter_,
CreateImageToGlTextureTensorConverter( CreateImageToGlTextureTensorConverter(
cc, DoesGpuInputStartAtBottom(options_), cc, DoesGpuInputStartAtBottom(options_),
GetBorderMode(options_.border_mode()))); GetBorderMode(options_.border_mode())));
} }
if (!gpu_converter_) { if (!gpu_converter_) {
return absl::UnimplementedError( return absl::UnimplementedError(
@@ -271,22 +273,24 @@ class ImageToTensorCalculator : public Node {
} else { } else {
if (!cpu_converter_) { if (!cpu_converter_) {
#if !MEDIAPIPE_DISABLE_OPENCV #if !MEDIAPIPE_DISABLE_OPENCV
ASSIGN_OR_RETURN(cpu_converter_, MP_ASSIGN_OR_RETURN(
CreateOpenCvConverter( cpu_converter_,
cc, GetBorderMode(options_.border_mode()), CreateOpenCvConverter(
GetOutputTensorType(/*uses_gpu=*/false, params_))); cc, GetBorderMode(options_.border_mode()),
GetOutputTensorType(/*uses_gpu=*/false, params_)));
// TODO: FrameBuffer-based converter needs to call GetGpuBuffer() // TODO: FrameBuffer-based converter needs to call GetGpuBuffer()
// to get access to a FrameBuffer view. Investigate if GetGpuBuffer() can be // to get access to a FrameBuffer view. Investigate if GetGpuBuffer() can be
// made available even with MEDIAPIPE_DISABLE_GPU set. // made available even with MEDIAPIPE_DISABLE_GPU set.
#elif MEDIAPIPE_ENABLE_HALIDE #elif MEDIAPIPE_ENABLE_HALIDE
ASSIGN_OR_RETURN(cpu_converter_, MP_ASSIGN_OR_RETURN(
CreateFrameBufferConverter( cpu_converter_,
cc, GetBorderMode(options_.border_mode()), CreateFrameBufferConverter(
GetOutputTensorType(/*uses_gpu=*/false, params_))); cc, GetBorderMode(options_.border_mode()),
GetOutputTensorType(/*uses_gpu=*/false, params_)));
#else #else
LOG(FATAL) << "Cannot create image to tensor CPU converter since " ABSL_LOG(FATAL) << "Cannot create image to tensor CPU converter since "
"MEDIAPIPE_DISABLE_OPENCV is defined and " "MEDIAPIPE_DISABLE_OPENCV is defined and "
"MEDIAPIPE_ENABLE_HALIDE is not defined."; "MEDIAPIPE_ENABLE_HALIDE is not defined.";
#endif // !MEDIAPIPE_DISABLE_HALIDE #endif // !MEDIAPIPE_DISABLE_HALIDE
} }
} }
@@ -18,6 +18,7 @@
#include <vector> #include <vector>
#include "absl/flags/flag.h" #include "absl/flags/flag.h"
#include "absl/log/absl_check.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/strings/substitute.h" #include "absl/strings/substitute.h"
@@ -205,7 +206,7 @@ mediapipe::ImageFormat::Format GetImageFormat(int image_channels) {
} else if (image_channels == 1) { } else if (image_channels == 1) {
return ImageFormat::GRAY8; return ImageFormat::GRAY8;
} }
CHECK(false) << "Unsupported input image channles: " << image_channels; ABSL_CHECK(false) << "Unsupported input image channles: " << image_channels;
} }
Packet MakeImageFramePacket(cv::Mat input) { Packet MakeImageFramePacket(cv::Mat input) {
@@ -175,9 +175,9 @@ absl::Status FrameBufferProcessor::CropRotateResize90Degrees(
cropped_buffer_ = std::make_unique<uint8_t[]>(cropped_buffer_size); cropped_buffer_ = std::make_unique<uint8_t[]>(cropped_buffer_size);
cropped_buffer_size_ = cropped_buffer_size; cropped_buffer_size_ = cropped_buffer_size;
} }
ASSIGN_OR_RETURN(cropped, MP_ASSIGN_OR_RETURN(
frame_buffer::CreateFromRawBuffer( cropped, frame_buffer::CreateFromRawBuffer(
cropped_buffer_.get(), cropped_dims, input->format())); cropped_buffer_.get(), cropped_dims, input->format()));
} }
MP_RETURN_IF_ERROR( MP_RETURN_IF_ERROR(
frame_buffer::Crop(*input, left, top, right, bottom, cropped.get())); frame_buffer::Crop(*input, left, top, right, bottom, cropped.get()));
@@ -194,9 +194,9 @@ absl::Status FrameBufferProcessor::CropRotateResize90Degrees(
rotated_buffer_ = std::make_unique<uint8_t[]>(rotated_buffer_size); rotated_buffer_ = std::make_unique<uint8_t[]>(rotated_buffer_size);
rotated_buffer_size_ = rotated_buffer_size; rotated_buffer_size_ = rotated_buffer_size;
} }
ASSIGN_OR_RETURN(auto rotated, frame_buffer::CreateFromRawBuffer( MP_ASSIGN_OR_RETURN(auto rotated, frame_buffer::CreateFromRawBuffer(
rotated_buffer_.get(), rotated_dims, rotated_buffer_.get(), rotated_dims,
cropped->format())); cropped->format()));
} }
MP_RETURN_IF_ERROR( MP_RETURN_IF_ERROR(
frame_buffer::Rotate(*cropped, rotation_degrees, rotated.get())); frame_buffer::Rotate(*cropped, rotation_degrees, rotated.get()));
@@ -217,9 +217,10 @@ absl::Status FrameBufferProcessor::ConvertToFloatTensor(
RET_CHECK(output_tensor.element_type() == Tensor::ElementType::kFloat32); RET_CHECK(output_tensor.element_type() == Tensor::ElementType::kFloat32);
constexpr float kInputImageRangeMin = 0.0f; constexpr float kInputImageRangeMin = 0.0f;
constexpr float kInputImageRangeMax = 255.0f; constexpr float kInputImageRangeMax = 255.0f;
ASSIGN_OR_RETURN(auto transform, GetValueRangeTransformation( MP_ASSIGN_OR_RETURN(
kInputImageRangeMin, kInputImageRangeMax, auto transform,
range_min, range_max)); GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax,
range_min, range_max));
return frame_buffer::ToFloatTensor(*input_frame, transform.scale, return frame_buffer::ToFloatTensor(*input_frame, transform.scale,
transform.offset, output_tensor); transform.offset, output_tensor);
} }
@@ -255,7 +255,7 @@ class GlProcessor : public ImageToTensorConverter {
<< "OpenGL ES 3.1 is required."; << "OpenGL ES 3.1 is required.";
command_queue_ = tflite::gpu::gl::NewCommandQueue(gpu_info); command_queue_ = tflite::gpu::gl::NewCommandQueue(gpu_info);
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
auto extractor, auto extractor,
SubRectExtractorGl::Create(gl_helper_.GetGlContext(), SubRectExtractorGl::Create(gl_helper_.GetGlContext(),
input_starts_at_bottom, border_mode)); input_starts_at_bottom, border_mode));
@@ -293,10 +293,10 @@ class GlProcessor : public ImageToTensorConverter {
constexpr float kInputImageRangeMin = 0.0f; constexpr float kInputImageRangeMin = 0.0f;
constexpr float kInputImageRangeMax = 1.0f; constexpr float kInputImageRangeMax = 1.0f;
ASSIGN_OR_RETURN(auto transform, MP_ASSIGN_OR_RETURN(auto transform,
GetValueRangeTransformation(kInputImageRangeMin, GetValueRangeTransformation(
kInputImageRangeMax, kInputImageRangeMin, kInputImageRangeMax,
range_min, range_max)); range_min, range_max));
const int output_size = output_tensor.bytes() / output_shape.dims[0]; const int output_size = output_tensor.bytes() / output_shape.dims[0];
auto buffer_view = output_tensor.GetOpenGlBufferWriteView(); auto buffer_view = output_tensor.GetOpenGlBufferWriteView();
@@ -22,6 +22,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "absl/log/absl_log.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "mediapipe/calculators/tensor/image_to_tensor_converter.h" #include "mediapipe/calculators/tensor/image_to_tensor_converter.h"
#include "mediapipe/calculators/tensor/image_to_tensor_converter_gl_utils.h" #include "mediapipe/calculators/tensor/image_to_tensor_converter_gl_utils.h"
@@ -192,10 +193,10 @@ class GlProcessor : public ImageToTensorConverter {
constexpr float kInputImageRangeMin = 0.0f; constexpr float kInputImageRangeMin = 0.0f;
constexpr float kInputImageRangeMax = 1.0f; constexpr float kInputImageRangeMax = 1.0f;
ASSIGN_OR_RETURN(auto transform, MP_ASSIGN_OR_RETURN(auto transform,
GetValueRangeTransformation(kInputImageRangeMin, GetValueRangeTransformation(
kInputImageRangeMax, kInputImageRangeMin, kInputImageRangeMax,
range_min, range_max)); range_min, range_max));
auto tensor_view = output_tensor.GetOpenGlTexture2dWriteView(); auto tensor_view = output_tensor.GetOpenGlTexture2dWriteView();
MP_RETURN_IF_ERROR(ExtractSubRect(input_texture, roi, MP_RETURN_IF_ERROR(ExtractSubRect(input_texture, roi,
/*flip_horizontaly=*/false, /*flip_horizontaly=*/false,
@@ -259,7 +260,7 @@ class GlProcessor : public ImageToTensorConverter {
// error. So in that case, we'll grab the transpose of our original matrix // error. So in that case, we'll grab the transpose of our original matrix
// and send that instead. // and send that instead.
const auto gl_context = mediapipe::GlContext::GetCurrent(); const auto gl_context = mediapipe::GlContext::GetCurrent();
LOG_IF(FATAL, !gl_context) << "GlContext is not bound to the thread."; ABSL_LOG_IF(FATAL, !gl_context) << "GlContext is not bound to the thread.";
if (gl_context->GetGlVersion() == mediapipe::GlVersion::kGLES2) { if (gl_context->GetGlVersion() == mediapipe::GlVersion::kGLES2) {
GetTransposedRotatedSubRectToRectTransformMatrix( GetTransposedRotatedSubRectToRectTransformMatrix(
sub_rect, texture.width(), texture.height(), flip_horizontaly, sub_rect, texture.width(), texture.height(), flip_horizontaly,
@@ -303,6 +304,7 @@ class GlProcessor : public ImageToTensorConverter {
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glFlush();
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -345,9 +345,9 @@ class MetalProcessor : public ImageToTensorConverter {
absl::Status Init(CalculatorContext* cc, BorderMode border_mode) { absl::Status Init(CalculatorContext* cc, BorderMode border_mode) {
metal_helper_ = [[MPPMetalHelper alloc] initWithCalculatorContext:cc]; metal_helper_ = [[MPPMetalHelper alloc] initWithCalculatorContext:cc];
RET_CHECK(metal_helper_); RET_CHECK(metal_helper_);
ASSIGN_OR_RETURN(extractor_, SubRectExtractorMetal::Make( MP_ASSIGN_OR_RETURN(extractor_, SubRectExtractorMetal::Make(
metal_helper_.mtlDevice, metal_helper_.mtlDevice,
OutputFormat::kF32C4, border_mode)); OutputFormat::kF32C4, border_mode));
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -373,7 +373,7 @@ class MetalProcessor : public ImageToTensorConverter {
constexpr float kInputImageRangeMin = 0.0f; constexpr float kInputImageRangeMin = 0.0f;
constexpr float kInputImageRangeMax = 1.0f; constexpr float kInputImageRangeMax = 1.0f;
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
auto transform, auto transform,
GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax, GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax,
range_min, range_max)); range_min, range_max));
@@ -159,7 +159,7 @@ class OpenCvProcessor : public ImageToTensorConverter {
constexpr float kInputImageRangeMin = 0.0f; constexpr float kInputImageRangeMin = 0.0f;
constexpr float kInputImageRangeMax = 255.0f; constexpr float kInputImageRangeMax = 255.0f;
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
auto transform, auto transform,
GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax, GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax,
range_min, range_max)); range_min, range_max));
@@ -88,6 +88,20 @@ message InferenceCalculatorOptions {
// serialized model is invalid or missing. // serialized model is invalid or missing.
optional string serialized_model_dir = 7; optional string serialized_model_dir = 7;
enum CacheWritingBehavior {
// Do not write any caches.
NO_WRITE = 0;
// Try to write caches, log on failure.
TRY_WRITE = 1;
// Write caches or return an error if write fails.
WRITE_OR_ERROR = 2;
}
// Specifies how GPU caches are written to disk.
optional CacheWritingBehavior cache_writing_behavior = 10
[default = WRITE_OR_ERROR];
// Unique token identifying the model. Used in conjunction with // Unique token identifying the model. Used in conjunction with
// "serialized_model_dir". It is the caller's responsibility to ensure // "serialized_model_dir". It is the caller's responsibility to ensure
// there is no clash of the tokens. // there is no clash of the tokens.
@@ -60,7 +60,7 @@ absl::Status InferenceCalculatorCpuImpl::UpdateContract(
} }
absl::Status InferenceCalculatorCpuImpl::Open(CalculatorContext* cc) { absl::Status InferenceCalculatorCpuImpl::Open(CalculatorContext* cc) {
ASSIGN_OR_RETURN(inference_runner_, CreateInferenceRunner(cc)); MP_ASSIGN_OR_RETURN(inference_runner_, CreateInferenceRunner(cc));
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -71,8 +71,8 @@ absl::Status InferenceCalculatorCpuImpl::Process(CalculatorContext* cc) {
const auto& input_tensors = *kInTensors(cc); const auto& input_tensors = *kInTensors(cc);
RET_CHECK(!input_tensors.empty()); RET_CHECK(!input_tensors.empty());
ASSIGN_OR_RETURN(std::vector<Tensor> output_tensors, MP_ASSIGN_OR_RETURN(std::vector<Tensor> output_tensors,
inference_runner_->Run(cc, input_tensors)); inference_runner_->Run(cc, input_tensors));
kOutTensors(cc).Send(std::move(output_tensors)); kOutTensors(cc).Send(std::move(output_tensors));
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -84,11 +84,11 @@ absl::Status InferenceCalculatorCpuImpl::Close(CalculatorContext* cc) {
absl::StatusOr<std::unique_ptr<InferenceRunner>> absl::StatusOr<std::unique_ptr<InferenceRunner>>
InferenceCalculatorCpuImpl::CreateInferenceRunner(CalculatorContext* cc) { InferenceCalculatorCpuImpl::CreateInferenceRunner(CalculatorContext* cc) {
ASSIGN_OR_RETURN(auto model_packet, GetModelAsPacket(cc)); MP_ASSIGN_OR_RETURN(auto model_packet, GetModelAsPacket(cc));
ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc)); MP_ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc));
const int interpreter_num_threads = const int interpreter_num_threads =
cc->Options<mediapipe::InferenceCalculatorOptions>().cpu_num_thread(); cc->Options<mediapipe::InferenceCalculatorOptions>().cpu_num_thread();
ASSIGN_OR_RETURN(TfLiteDelegatePtr delegate, MaybeCreateDelegate(cc)); MP_ASSIGN_OR_RETURN(TfLiteDelegatePtr delegate, MaybeCreateDelegate(cc));
return CreateInferenceInterpreterDelegateRunner( return CreateInferenceInterpreterDelegateRunner(
std::move(model_packet), std::move(op_resolver_packet), std::move(model_packet), std::move(op_resolver_packet),
std::move(delegate), interpreter_num_threads); std::move(delegate), interpreter_num_threads);
@@ -100,7 +100,7 @@ absl::Status InferenceCalculatorGlImpl::GpuInferenceRunner::Init(
absl::Status InferenceCalculatorGlImpl::GpuInferenceRunner::LoadModel( absl::Status InferenceCalculatorGlImpl::GpuInferenceRunner::LoadModel(
CalculatorContext* cc) { CalculatorContext* cc) {
ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc)); MP_ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc));
const auto& model = *model_packet_.Get(); const auto& model = *model_packet_.Get();
if (kSideInOpResolver(cc).IsConnected()) { if (kSideInOpResolver(cc).IsConnected()) {
const tflite::OpResolver& op_resolver = kSideInOpResolver(cc).Get(); const tflite::OpResolver& op_resolver = kSideInOpResolver(cc).Get();
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <cstdint>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <string> #include <string>
@@ -26,6 +27,7 @@
#include "mediapipe/util/tflite/tflite_gpu_runner.h" #include "mediapipe/util/tflite/tflite_gpu_runner.h"
#if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS) #if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS)
#include "absl/log/absl_log.h"
#include "mediapipe/framework/deps/file_path.h" #include "mediapipe/framework/deps/file_path.h"
#include "mediapipe/util/android/file/base/file.h" #include "mediapipe/util/android/file/base/file.h"
#include "mediapipe/util/android/file/base/filesystem.h" #include "mediapipe/util/android/file/base/filesystem.h"
@@ -68,14 +70,21 @@ class InferenceCalculatorGlAdvancedImpl
const mediapipe::InferenceCalculatorOptions::Delegate::Gpu& const mediapipe::InferenceCalculatorOptions::Delegate::Gpu&
gpu_delegate_options); gpu_delegate_options);
absl::Status ReadGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const; absl::Status ReadGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const;
absl::Status SaveGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const; // Writes caches to disk based on |cache_writing_behavior_|.
absl::Status SaveGpuCachesBasedOnBehavior(
tflite::gpu::TFLiteGPURunner* gpu_runner) const;
bool UseSerializedModel() const { return use_serialized_model_; } bool UseSerializedModel() const { return use_serialized_model_; }
private: private:
// Writes caches to disk, returns error on failure.
absl::Status SaveGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const;
bool use_kernel_caching_ = false; bool use_kernel_caching_ = false;
std::string cached_kernel_filename_; std::string cached_kernel_filename_;
bool use_serialized_model_ = false; bool use_serialized_model_ = false;
std::string serialized_model_path_; std::string serialized_model_path_;
mediapipe::InferenceCalculatorOptions::Delegate::Gpu::CacheWritingBehavior
cache_writing_behavior_;
}; };
// Helper class that wraps everything related to GPU inference acceleration. // Helper class that wraps everything related to GPU inference acceleration.
@@ -161,7 +170,7 @@ absl::Status
InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::InitTFLiteGPURunner( InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::InitTFLiteGPURunner(
CalculatorContext* cc, CalculatorContext* cc,
const mediapipe::InferenceCalculatorOptions::Delegate& delegate) { const mediapipe::InferenceCalculatorOptions::Delegate& delegate) {
ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc)); MP_ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc));
const auto& model = *model_packet_.Get(); const auto& model = *model_packet_.Get();
bool allow_precision_loss = delegate.gpu().allow_precision_loss(); bool allow_precision_loss = delegate.gpu().allow_precision_loss();
@@ -232,7 +241,8 @@ InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::InitTFLiteGPURunner(
MP_RETURN_IF_ERROR( MP_RETURN_IF_ERROR(
on_disk_cache_helper_.ReadGpuCaches(tflite_gpu_runner_.get())); on_disk_cache_helper_.ReadGpuCaches(tflite_gpu_runner_.get()));
MP_RETURN_IF_ERROR(tflite_gpu_runner_->Build()); MP_RETURN_IF_ERROR(tflite_gpu_runner_->Build());
return on_disk_cache_helper_.SaveGpuCaches(tflite_gpu_runner_.get()); return on_disk_cache_helper_.SaveGpuCachesBasedOnBehavior(
tflite_gpu_runner_.get());
} }
#if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS) #if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS)
@@ -261,24 +271,51 @@ absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::Init(
mediapipe::file::JoinPath(gpu_delegate_options.serialized_model_dir(), mediapipe::file::JoinPath(gpu_delegate_options.serialized_model_dir(),
gpu_delegate_options.model_token()); gpu_delegate_options.model_token());
} }
cache_writing_behavior_ = gpu_delegate_options.has_cache_writing_behavior()
? gpu_delegate_options.cache_writing_behavior()
: mediapipe::InferenceCalculatorOptions::
Delegate::Gpu::WRITE_OR_ERROR;
return absl::OkStatus(); return absl::OkStatus();
} }
absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::
SaveGpuCachesBasedOnBehavior(
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
switch (cache_writing_behavior_) {
case mediapipe::InferenceCalculatorOptions::Delegate::Gpu::NO_WRITE:
return absl::OkStatus();
case mediapipe::InferenceCalculatorOptions::Delegate::Gpu::TRY_WRITE: {
auto status = SaveGpuCaches(gpu_runner);
if (!status.ok()) {
ABSL_LOG_FIRST_N(WARNING, 1) << "Failed to save gpu caches: " << status;
}
return absl::OkStatus();
}
case mediapipe::InferenceCalculatorOptions::Delegate::Gpu::WRITE_OR_ERROR:
return SaveGpuCaches(gpu_runner);
default:
ABSL_LOG_FIRST_N(ERROR, 1)
<< "Unknown cache writing behavior: "
<< static_cast<uint32_t>(cache_writing_behavior_);
return absl::InvalidArgumentError("Unknown cache writing behavior.");
}
}
absl::Status absl::Status
InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::SaveGpuCaches( InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::SaveGpuCaches(
tflite::gpu::TFLiteGPURunner* gpu_runner) const { tflite::gpu::TFLiteGPURunner* gpu_runner) const {
if (use_kernel_caching_) { if (use_kernel_caching_) {
// Save kernel file. // Save kernel file.
ASSIGN_OR_RETURN(std::vector<uint8_t> kernel_cache, MP_ASSIGN_OR_RETURN(std::vector<uint8_t> kernel_cache,
gpu_runner->GetSerializedBinaryCache()); gpu_runner->GetSerializedBinaryCache());
std::string cache_str(kernel_cache.begin(), kernel_cache.end()); std::string cache_str(kernel_cache.begin(), kernel_cache.end());
MP_RETURN_IF_ERROR( MP_RETURN_IF_ERROR(
mediapipe::file::SetContents(cached_kernel_filename_, cache_str)); mediapipe::file::SetContents(cached_kernel_filename_, cache_str));
} }
if (use_serialized_model_) { if (use_serialized_model_) {
// Save serialized model file. // Save serialized model file.
ASSIGN_OR_RETURN(std::vector<uint8_t> serialized_model_vec, MP_ASSIGN_OR_RETURN(std::vector<uint8_t> serialized_model_vec,
gpu_runner->GetSerializedModel()); gpu_runner->GetSerializedModel());
absl::string_view serialized_model( absl::string_view serialized_model(
reinterpret_cast<char*>(serialized_model_vec.data()), reinterpret_cast<char*>(serialized_model_vec.data()),
serialized_model_vec.size()); serialized_model_vec.size());
@@ -318,6 +355,12 @@ absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::Init(
return absl::OkStatus(); return absl::OkStatus();
} }
absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::
SaveGpuCachesBasedOnBehavior(
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
return absl::OkStatus();
}
absl::Status absl::Status
InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::ReadGpuCaches( InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::ReadGpuCaches(
tflite::gpu::TFLiteGPURunner* gpu_runner) const { tflite::gpu::TFLiteGPURunner* gpu_runner) const {
@@ -369,8 +412,8 @@ absl::Status InferenceCalculatorGlAdvancedImpl::Process(CalculatorContext* cc) {
RET_CHECK(!input_tensors.empty()); RET_CHECK(!input_tensors.empty());
auto output_tensors = absl::make_unique<std::vector<Tensor>>(); auto output_tensors = absl::make_unique<std::vector<Tensor>>();
ASSIGN_OR_RETURN(*output_tensors, MP_ASSIGN_OR_RETURN(*output_tensors,
gpu_inference_runner_->Process(cc, input_tensors)); gpu_inference_runner_->Process(cc, input_tensors));
kOutTensors(cc).Send(std::move(output_tensors)); kOutTensors(cc).Send(std::move(output_tensors));
return absl::OkStatus(); return absl::OkStatus();
@@ -21,6 +21,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "absl/log/absl_log.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "mediapipe/calculators/tensor/inference_calculator.h" #include "mediapipe/calculators/tensor/inference_calculator.h"
@@ -74,7 +75,7 @@ tflite::gpu::BHWC BhwcFromTensorShape(const Tensor::Shape& shape) {
break; break;
default: default:
// Handles 0 and >4. // Handles 0 and >4.
LOG(FATAL) ABSL_LOG(FATAL)
<< "Dimensions size must be in range [1,4] for GPU inference, but " << "Dimensions size must be in range [1,4] for GPU inference, but "
<< shape.dims.size() << " is provided"; << shape.dims.size() << " is provided";
} }
@@ -207,9 +208,9 @@ absl::Status InferenceCalculatorMetalImpl::Close(CalculatorContext* cc) {
absl::Status InferenceCalculatorMetalImpl::InitInterpreter( absl::Status InferenceCalculatorMetalImpl::InitInterpreter(
CalculatorContext* cc) { CalculatorContext* cc) {
ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc)); MP_ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc));
const auto& model = *model_packet_.Get(); const auto& model = *model_packet_.Get();
ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc)); MP_ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc));
const auto& op_resolver = op_resolver_packet.Get(); const auto& op_resolver = op_resolver_packet.Get();
tflite::InterpreterBuilder interpreter_builder(model, op_resolver); tflite::InterpreterBuilder interpreter_builder(model, op_resolver);
AddDelegate(cc, &interpreter_builder); AddDelegate(cc, &interpreter_builder);
@@ -16,7 +16,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "absl/log/check.h" #include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_replace.h" #include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
@@ -58,7 +58,7 @@ absl::Status InferenceCalculatorXnnpackImpl::UpdateContract(
} }
absl::Status InferenceCalculatorXnnpackImpl::Open(CalculatorContext* cc) { absl::Status InferenceCalculatorXnnpackImpl::Open(CalculatorContext* cc) {
ASSIGN_OR_RETURN(inference_runner_, CreateInferenceRunner(cc)); MP_ASSIGN_OR_RETURN(inference_runner_, CreateInferenceRunner(cc));
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -69,8 +69,8 @@ absl::Status InferenceCalculatorXnnpackImpl::Process(CalculatorContext* cc) {
const auto& input_tensors = *kInTensors(cc); const auto& input_tensors = *kInTensors(cc);
RET_CHECK(!input_tensors.empty()); RET_CHECK(!input_tensors.empty());
ASSIGN_OR_RETURN(std::vector<Tensor> output_tensors, MP_ASSIGN_OR_RETURN(std::vector<Tensor> output_tensors,
inference_runner_->Run(cc, input_tensors)); inference_runner_->Run(cc, input_tensors));
kOutTensors(cc).Send(std::move(output_tensors)); kOutTensors(cc).Send(std::move(output_tensors));
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -82,11 +82,11 @@ absl::Status InferenceCalculatorXnnpackImpl::Close(CalculatorContext* cc) {
absl::StatusOr<std::unique_ptr<InferenceRunner>> absl::StatusOr<std::unique_ptr<InferenceRunner>>
InferenceCalculatorXnnpackImpl::CreateInferenceRunner(CalculatorContext* cc) { InferenceCalculatorXnnpackImpl::CreateInferenceRunner(CalculatorContext* cc) {
ASSIGN_OR_RETURN(auto model_packet, GetModelAsPacket(cc)); MP_ASSIGN_OR_RETURN(auto model_packet, GetModelAsPacket(cc));
ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc)); MP_ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc));
const int interpreter_num_threads = const int interpreter_num_threads =
cc->Options<mediapipe::InferenceCalculatorOptions>().cpu_num_thread(); cc->Options<mediapipe::InferenceCalculatorOptions>().cpu_num_thread();
ASSIGN_OR_RETURN(TfLiteDelegatePtr delegate, CreateDelegate(cc)); MP_ASSIGN_OR_RETURN(TfLiteDelegatePtr delegate, CreateDelegate(cc));
return CreateInferenceInterpreterDelegateRunner( return CreateInferenceInterpreterDelegateRunner(
std::move(model_packet), std::move(op_resolver_packet), std::move(model_packet), std::move(op_resolver_packet),
std::move(delegate), interpreter_num_threads); std::move(delegate), interpreter_num_threads);
@@ -106,7 +106,7 @@ absl::Status RegexPreprocessorCalculator::Open(CalculatorContext* cc) {
return absl::InvalidArgumentError("No tensor metadata found"); return absl::InvalidArgumentError("No tensor metadata found");
} }
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
const auto* tokenizer_metadata, const auto* tokenizer_metadata,
metadata_extractor->FindFirstProcessUnit( metadata_extractor->FindFirstProcessUnit(
*tensor_metadata, tflite::ProcessUnitOptions_RegexTokenizerOptions)); *tensor_metadata, tflite::ProcessUnitOptions_RegexTokenizerOptions));
@@ -115,9 +115,9 @@ absl::Status RegexPreprocessorCalculator::Open(CalculatorContext* cc) {
} }
const tflite::RegexTokenizerOptions* regex_tokenizer_options = const tflite::RegexTokenizerOptions* regex_tokenizer_options =
tokenizer_metadata->options_as<tflite::RegexTokenizerOptions>(); tokenizer_metadata->options_as<tflite::RegexTokenizerOptions>();
ASSIGN_OR_RETURN(tokenizer_, MP_ASSIGN_OR_RETURN(tokenizer_,
tasks::text::tokenizers::CreateRegexTokenizerFromOptions( tasks::text::tokenizers::CreateRegexTokenizerFromOptions(
regex_tokenizer_options, metadata_extractor)); regex_tokenizer_options, metadata_extractor));
const auto& options = const auto& options =
cc->Options<mediapipe::RegexPreprocessorCalculatorOptions>(); cc->Options<mediapipe::RegexPreprocessorCalculatorOptions>();
@@ -67,9 +67,10 @@ absl::StatusOr<std::vector<int>> RunRegexPreprocessorCalculator(
tool::AddVectorSink("tensors", &graph_config, &output_packets); tool::AddVectorSink("tensors", &graph_config, &output_packets);
std::string model_buffer = tasks::core::LoadBinaryContent(kTestModelPath); std::string model_buffer = tasks::core::LoadBinaryContent(kTestModelPath);
ASSIGN_OR_RETURN(std::unique_ptr<ModelMetadataExtractor> metadata_extractor, MP_ASSIGN_OR_RETURN(
ModelMetadataExtractor::CreateFromModelBuffer( std::unique_ptr<ModelMetadataExtractor> metadata_extractor,
model_buffer.data(), model_buffer.size())); ModelMetadataExtractor::CreateFromModelBuffer(model_buffer.data(),
model_buffer.size()));
// Run the graph. // Run the graph.
CalculatorGraph graph; CalculatorGraph graph;
MP_RETURN_IF_ERROR(graph.Initialize( MP_RETURN_IF_ERROR(graph.Initialize(
@@ -12,9 +12,15 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <cstdint>
#include <string> #include <string>
#include <vector> #include <vector>
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "mediapipe/calculators/tensor/tensor_converter_calculator.pb.h" #include "mediapipe/calculators/tensor/tensor_converter_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame.h" #include "mediapipe/framework/formats/image_frame.h"
@@ -22,7 +28,8 @@
#include "mediapipe/framework/formats/tensor.h" #include "mediapipe/framework/formats/tensor.h"
#include "mediapipe/framework/port.h" #include "mediapipe/framework/port.h"
#include "mediapipe/framework/port/ret_check.h" #include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/util/resource_util.h" #include "mediapipe/gpu/gpu_buffer_format.h"
#include "mediapipe/gpu/gpu_origin.pb.h"
#if !MEDIAPIPE_DISABLE_GPU #if !MEDIAPIPE_DISABLE_GPU
#include "mediapipe/gpu/gpu_buffer.h" #include "mediapipe/gpu/gpu_buffer.h"
@@ -43,12 +50,50 @@
#endif // !MEDIAPIPE_DISABLE_GPU #endif // !MEDIAPIPE_DISABLE_GPU
namespace { namespace {
constexpr int kWorkgroupSize = 8; // Block size for GPU shader. constexpr int kWorkgroupSize = 8; // Block size for GPU shader.
// Commonly used to compute the number of blocks to launch in a kernel. // Commonly used to compute the number of blocks to launch in a kernel.
int NumGroups(const int size, const int group_size) { // NOLINT int NumGroups(const int size, const int group_size) { // NOLINT
return (size + group_size - 1) / group_size; return (size + group_size - 1) / group_size;
} }
absl::StatusOr<bool> ShouldFlipVertically(
const mediapipe::TensorConverterCalculatorOptions& options, bool use_gpu) {
if (options.has_flip_vertically() && options.has_gpu_origin()) {
return absl::FailedPreconditionError(absl::StrFormat(
"Cannot specify both flip_vertically and gpu_origin options"));
}
if (!options.has_gpu_origin()) {
// Fall back to flip_vertically.
return options.flip_vertically();
}
// Warn if gpu_origin is specified with a CPU input image.
// Those are always TOP_LEFT, so no flipping is necessary.
if (!use_gpu) {
ABSL_LOG(WARNING)
<< "Ignoring gpu_origin option since IMAGE_GPU input is not specified";
return false;
}
switch (options.gpu_origin()) {
case mediapipe::GpuOrigin::TOP_LEFT:
return false;
case mediapipe::GpuOrigin::DEFAULT:
case mediapipe::GpuOrigin::CONVENTIONAL:
// TOP_LEFT on Metal, BOTTOM_LEFT on OpenGL.
#ifdef __APPLE__
return false;
#else
return true;
#endif
default:
return absl::InvalidArgumentError(
absl::StrFormat("Unhandled GPU origin %i", options.gpu_origin()));
}
}
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
RowMajorMatrixXf; RowMajorMatrixXf;
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor> typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>
@@ -58,6 +103,7 @@ constexpr char kImageFrameTag[] = "IMAGE";
constexpr char kGpuBufferTag[] = "IMAGE_GPU"; constexpr char kGpuBufferTag[] = "IMAGE_GPU";
constexpr char kTensorsTag[] = "TENSORS"; constexpr char kTensorsTag[] = "TENSORS";
constexpr char kMatrixTag[] = "MATRIX"; constexpr char kMatrixTag[] = "MATRIX";
} // namespace } // namespace
namespace mediapipe { namespace mediapipe {
@@ -109,7 +155,7 @@ class TensorConverterCalculator : public CalculatorBase {
private: private:
absl::Status InitGpu(CalculatorContext* cc); absl::Status InitGpu(CalculatorContext* cc);
absl::Status LoadOptions(CalculatorContext* cc); absl::Status LoadOptions(CalculatorContext* cc, bool use_gpu);
template <class T> template <class T>
absl::Status NormalizeImage(const ImageFrame& image_frame, absl::Status NormalizeImage(const ImageFrame& image_frame,
bool flip_vertically, float* tensor_ptr); bool flip_vertically, float* tensor_ptr);
@@ -145,7 +191,8 @@ absl::Status TensorConverterCalculator::GetContract(CalculatorContract* cc) {
RET_CHECK(static_cast<int>(cc->Inputs().HasTag(kImageFrameTag)) + RET_CHECK(static_cast<int>(cc->Inputs().HasTag(kImageFrameTag)) +
static_cast<int>(cc->Inputs().HasTag(kGpuBufferTag)) + static_cast<int>(cc->Inputs().HasTag(kGpuBufferTag)) +
static_cast<int>(cc->Inputs().HasTag(kMatrixTag)) == static_cast<int>(cc->Inputs().HasTag(kMatrixTag)) ==
1); 1)
<< "Only one input tag of {IMAGE, IMAGE_GPU, MATRIX} may be specified";
if (cc->Inputs().HasTag(kImageFrameTag)) { if (cc->Inputs().HasTag(kImageFrameTag)) {
cc->Inputs().Tag(kImageFrameTag).Set<ImageFrame>(); cc->Inputs().Tag(kImageFrameTag).Set<ImageFrame>();
@@ -173,8 +220,6 @@ absl::Status TensorConverterCalculator::GetContract(CalculatorContract* cc) {
absl::Status TensorConverterCalculator::Open(CalculatorContext* cc) { absl::Status TensorConverterCalculator::Open(CalculatorContext* cc) {
cc->SetOffset(TimestampDiff(0)); cc->SetOffset(TimestampDiff(0));
MP_RETURN_IF_ERROR(LoadOptions(cc));
#if !MEDIAPIPE_DISABLE_GPU #if !MEDIAPIPE_DISABLE_GPU
if (cc->Inputs().HasTag(kGpuBufferTag)) { if (cc->Inputs().HasTag(kGpuBufferTag)) {
use_gpu_ = true; use_gpu_ = true;
@@ -187,6 +232,8 @@ absl::Status TensorConverterCalculator::Open(CalculatorContext* cc) {
} }
#endif // !MEDIAPIPE_DISABLE_GPU #endif // !MEDIAPIPE_DISABLE_GPU
MP_RETURN_IF_ERROR(LoadOptions(cc, use_gpu_));
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -359,6 +406,7 @@ absl::Status TensorConverterCalculator::ProcessGPU(CalculatorContext* cc) {
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
glFlush();
src.Release(); src.Release();
return absl::OkStatus(); return absl::OkStatus();
})); }));
@@ -378,23 +426,34 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
// Get input image sizes. // Get input image sizes.
const auto& input = const auto& input =
cc->Inputs().Tag(kGpuBufferTag).Get<mediapipe::GpuBuffer>(); cc->Inputs().Tag(kGpuBufferTag).Get<mediapipe::GpuBuffer>();
mediapipe::ImageFormat::Format format = mediapipe::GpuBufferFormat format = input.format();
mediapipe::ImageFormatForGpuBufferFormat(input.format());
const bool include_alpha = (max_num_channels_ == 4); const bool include_alpha = (max_num_channels_ == 4);
const bool single_channel = (max_num_channels_ == 1); const bool single_channel = (max_num_channels_ == 1);
if (!(format == mediapipe::ImageFormat::GRAY8 ||
format == mediapipe::ImageFormat::SRGB || RET_CHECK(format == mediapipe::GpuBufferFormat::kBGRA32 ||
format == mediapipe::ImageFormat::SRGBA)) format == mediapipe::GpuBufferFormat::kRGB24 ||
RET_CHECK_FAIL() << "Unsupported GPU input format."; format == mediapipe::GpuBufferFormat::kRGBA32 ||
if (include_alpha && (format != mediapipe::ImageFormat::SRGBA)) format == mediapipe::GpuBufferFormat::kRGBAFloat128 ||
RET_CHECK_FAIL() << "Num input channels is less than desired output."; format == mediapipe::GpuBufferFormat::kRGBAHalf64 ||
format == mediapipe::GpuBufferFormat::kGrayFloat32 ||
format == mediapipe::GpuBufferFormat::kGrayHalf16 ||
format == mediapipe::GpuBufferFormat::kOneComponent8)
<< "Unsupported GPU input format: " << static_cast<uint32_t>(format);
if (include_alpha) {
RET_CHECK(format == mediapipe::GpuBufferFormat::kBGRA32 ||
format == mediapipe::GpuBufferFormat::kRGBA32 ||
format == mediapipe::GpuBufferFormat::kRGBAFloat128 ||
format == mediapipe::GpuBufferFormat::kRGBAHalf64)
<< "Num input channels is less than desired output, input format: "
<< static_cast<uint32_t>(format);
}
#if MEDIAPIPE_METAL_ENABLED #if MEDIAPIPE_METAL_ENABLED
id<MTLDevice> device = gpu_helper_.mtlDevice; id<MTLDevice> device = gpu_helper_.mtlDevice;
// Shader to convert GL Texture to Metal Buffer, // Shader to convert GL Texture to Metal Buffer,
// with normalization to either: [0,1] or [-1,1]. // with normalization to either: [0,1] or [-1,1].
const std::string shader_source = absl::Substitute( const std::string shader_source = absl::Substitute(
R"( R"glsl(
#include <metal_stdlib> #include <metal_stdlib>
using namespace metal; using namespace metal;
@@ -413,7 +472,7 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
$3 // g & b channels $3 // g & b channels
$4 // alpha channel $4 // alpha channel
} }
)", )glsl",
/*$0=*/ /*$0=*/
output_range_.has_value() output_range_.has_value()
? absl::Substitute("pixel = pixel * half($0) + half($1);", ? absl::Substitute("pixel = pixel * half($0) + half($1);",
@@ -423,8 +482,8 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
/*$1=*/max_num_channels_, /*$1=*/max_num_channels_,
/*$2=*/flip_vertically_ ? "(in_tex.get_height() - 1 - gid.y)" : "gid.y", /*$2=*/flip_vertically_ ? "(in_tex.get_height() - 1 - gid.y)" : "gid.y",
/*$3=*/ /*$3=*/
single_channel ? "" : R"(out_buf[linear_index + 1] = pixel.y; single_channel ? "" : R"glsl(out_buf[linear_index + 1] = pixel.y;
out_buf[linear_index + 2] = pixel.z;)", out_buf[linear_index + 2] = pixel.z;)glsl",
/*$4=*/include_alpha ? "out_buf[linear_index + 3] = pixel.w;" : ""); /*$4=*/include_alpha ? "out_buf[linear_index + 3] = pixel.w;" : "");
NSString* library_source = NSString* library_source =
@@ -442,17 +501,17 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
RET_CHECK(to_buffer_program_ != nil) << "Couldn't create pipeline state " << RET_CHECK(to_buffer_program_ != nil) << "Couldn't create pipeline state " <<
[[error localizedDescription] UTF8String]; [[error localizedDescription] UTF8String];
#elif MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30 #elif MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
MP_RETURN_IF_ERROR(gpu_helper_.RunInGlContext([this, &include_alpha, MP_RETURN_IF_ERROR(
gpu_helper_.RunInGlContext([this, &include_alpha,
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
&input, &input,
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
&single_channel]() &single_channel]() -> absl::Status {
-> absl::Status {
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
// Shader to convert GL Texture to Shader Storage Buffer Object (SSBO), // Shader to convert GL Texture to Shader Storage Buffer Object (SSBO),
// with normalization to either: [0,1] or [-1,1]. // with normalization to either: [0,1] or [-1,1].
const std::string shader_source = absl::Substitute( const std::string shader_source = absl::Substitute(
R"( #version 310 es R"glsl( #version 310 es
layout(local_size_x = $0, local_size_y = $0) in; layout(local_size_x = $0, local_size_y = $0) in;
layout(binding = 0) uniform sampler2D input_texture; layout(binding = 0) uniform sampler2D input_texture;
layout(std430, binding = 1) buffer Output {float elements[];} output_data; layout(std430, binding = 1) buffer Output {float elements[];} output_data;
@@ -466,38 +525,40 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
output_data.elements[linear_index + 0] = pixel.x; // r channel output_data.elements[linear_index + 0] = pixel.x; // r channel
$5 // g & b channels $5 // g & b channels
$6 // alpha channel $6 // alpha channel
})", })glsl",
/*$0=*/kWorkgroupSize, /*$1=*/input.width(), /*$2=*/input.height(), /*$0=*/kWorkgroupSize, /*$1=*/input.width(), /*$2=*/input.height(),
/*$3=*/ /*$3=*/
output_range_.has_value() output_range_.has_value()
? absl::Substitute("pixel = pixel * float($0) + float($1);", ? absl::Substitute(
(output_range_->second - output_range_->first), "pixel = pixel * float($0) + float($1);",
output_range_->first) (output_range_->second - output_range_->first),
: "", output_range_->first)
/*$4=*/flip_vertically_ ? "(width_height.y - 1 - gid.y)" : "gid.y", : "",
/*$5=*/ /*$4=*/flip_vertically_ ? "(width_height.y - 1 - gid.y)" : "gid.y",
single_channel ? "" /*$5=*/
: R"(output_data.elements[linear_index + 1] = pixel.y; single_channel
output_data.elements[linear_index + 2] = pixel.z;)", ? ""
/*$6=*/ : R"glsl(output_data.elements[linear_index + 1] = pixel.y;
include_alpha ? "output_data.elements[linear_index + 3] = pixel.w;" output_data.elements[linear_index + 2] = pixel.z;)glsl",
: "", /*$6=*/
/*$7=*/max_num_channels_); include_alpha ? "output_data.elements[linear_index + 3] = pixel.w;"
GLuint shader = glCreateShader(GL_COMPUTE_SHADER); : "",
const GLchar* sources[] = {shader_source.c_str()}; /*$7=*/max_num_channels_);
glShaderSource(shader, 1, sources, NULL); GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
glCompileShader(shader); const GLchar* sources[] = {shader_source.c_str()};
GLint compiled = GL_FALSE; glShaderSource(shader, 1, sources, NULL);
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); glCompileShader(shader);
RET_CHECK(compiled == GL_TRUE); GLint compiled = GL_FALSE;
to_buffer_program_ = glCreateProgram(); glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
glAttachShader(to_buffer_program_, shader); RET_CHECK(compiled == GL_TRUE);
glDeleteShader(shader); to_buffer_program_ = glCreateProgram();
glLinkProgram(to_buffer_program_); glAttachShader(to_buffer_program_, shader);
glDeleteShader(shader);
glLinkProgram(to_buffer_program_);
#else #else
// OpenGL ES 3.0 fragment shader Texture2d -> Texture2d conversion. // OpenGL ES 3.0 fragment shader Texture2d -> Texture2d conversion.
const std::string shader_source = absl::Substitute( const std::string shader_source = absl::Substitute(
R"( R"glsl(
#if __VERSION__ < 130 #if __VERSION__ < 130
#define in varying #define in varying
#endif // __VERSION__ < 130 #endif // __VERSION__ < 130
@@ -523,49 +584,51 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
fragColor.r = pixel.r; // r channel fragColor.r = pixel.r; // r channel
$3 // g & b channels $3 // g & b channels
$4 // alpha channel $4 // alpha channel
})", })glsl",
/*$0=*/single_channel ? "vec1" : "vec4", /*$0=*/single_channel ? "vec1" : "vec4",
/*$1=*/ /*$1=*/
flip_vertically_ flip_vertically_
? "vec2(sample_coordinate.x, 1.0 - sample_coordinate.y);" ? "vec2(sample_coordinate.x, 1.0 - sample_coordinate.y);"
: "sample_coordinate;", : "sample_coordinate;",
/*$2=*/output_range_.has_value() /*$2=*/output_range_.has_value()
? absl::Substitute("pixel = pixel * float($0) + float($1);", ? absl::Substitute(
(output_range_->second - output_range_->first), "pixel = pixel * float($0) + float($1);",
output_range_->first) (output_range_->second - output_range_->first),
: "", output_range_->first)
/*$3=*/single_channel ? "" : R"(fragColor.g = pixel.g; : "",
fragColor.b = pixel.b;)", /*$3=*/single_channel ? "" : R"glsl(fragColor.g = pixel.g;
/*$4=*/ fragColor.b = pixel.b;)glsl",
include_alpha ? "fragColor.a = pixel.a;" /*$4=*/
: (single_channel ? "" : "fragColor.a = 1.0;")); include_alpha ? "fragColor.a = pixel.a;"
: (single_channel ? "" : "fragColor.a = 1.0;"));
const GLint attr_location[NUM_ATTRIBUTES] = { const GLint attr_location[NUM_ATTRIBUTES] = {
ATTRIB_VERTEX, ATTRIB_VERTEX,
ATTRIB_TEXTURE_POSITION, ATTRIB_TEXTURE_POSITION,
}; };
const GLchar* attr_name[NUM_ATTRIBUTES] = { const GLchar* attr_name[NUM_ATTRIBUTES] = {
"position", "position",
"texture_coordinate", "texture_coordinate",
}; };
// shader program and params // shader program and params
mediapipe::GlhCreateProgram( mediapipe::GlhCreateProgram(
mediapipe::kBasicVertexShader, shader_source.c_str(), NUM_ATTRIBUTES, mediapipe::kBasicVertexShader, shader_source.c_str(),
&attr_name[0], attr_location, &to_tex2d_program_); NUM_ATTRIBUTES, &attr_name[0], attr_location, &to_tex2d_program_);
RET_CHECK(to_tex2d_program_) << "Problem initializing the program."; RET_CHECK(to_tex2d_program_) << "Problem initializing the program.";
glUseProgram(to_tex2d_program_); glUseProgram(to_tex2d_program_);
glUniform1i(glGetUniformLocation(to_tex2d_program_, "frame"), 1); glUniform1i(glGetUniformLocation(to_tex2d_program_, "frame"), 1);
glGenFramebuffers(1, &framebuffer_); glGenFramebuffers(1, &framebuffer_);
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
return absl::OkStatus(); return absl::OkStatus();
})); }));
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30 #endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
#endif // !MEDIAPIPE_DISABLE_GPU #endif // !MEDIAPIPE_DISABLE_GPU
return absl::OkStatus(); return absl::OkStatus();
} }
absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc) { absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc,
bool use_gpu) {
// Get calculator options specified in the graph. // Get calculator options specified in the graph.
const auto& options = const auto& options =
cc->Options<::mediapipe::TensorConverterCalculatorOptions>(); cc->Options<::mediapipe::TensorConverterCalculatorOptions>();
@@ -582,7 +645,7 @@ absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc) {
if (options.has_output_tensor_float_range()) { if (options.has_output_tensor_float_range()) {
output_range_.emplace(options.output_tensor_float_range().min(), output_range_.emplace(options.output_tensor_float_range().min(),
options.output_tensor_float_range().max()); options.output_tensor_float_range().max());
CHECK_GT(output_range_->second, output_range_->first); ABSL_CHECK_GT(output_range_->second, output_range_->first);
} }
// Custom div and sub values. // Custom div and sub values.
@@ -593,16 +656,16 @@ absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc) {
} }
// Get y-flip mode. // Get y-flip mode.
flip_vertically_ = options.flip_vertically(); MP_ASSIGN_OR_RETURN(flip_vertically_, ShouldFlipVertically(options, use_gpu));
// Get row_major_matrix mode. // Get row_major_matrix mode.
row_major_matrix_ = options.row_major_matrix(); row_major_matrix_ = options.row_major_matrix();
// Get desired way to handle input channels. // Get desired way to handle input channels.
max_num_channels_ = options.max_num_channels(); max_num_channels_ = options.max_num_channels();
CHECK_GE(max_num_channels_, 1); ABSL_CHECK_GE(max_num_channels_, 1);
CHECK_LE(max_num_channels_, 4); ABSL_CHECK_LE(max_num_channels_, 4);
CHECK_NE(max_num_channels_, 2); ABSL_CHECK_NE(max_num_channels_, 2);
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -3,6 +3,7 @@ syntax = "proto2";
package mediapipe; package mediapipe;
import "mediapipe/framework/calculator.proto"; import "mediapipe/framework/calculator.proto";
import "mediapipe/gpu/gpu_origin.proto";
// Full Example: // Full Example:
// //
@@ -43,8 +44,16 @@ message TensorConverterCalculatorOptions {
// with a coordinate system where the origin is at the bottom-left corner // with a coordinate system where the origin is at the bottom-left corner
// (e.g., in OpenGL) whereas the ML model expects an image with a top-left // (e.g., in OpenGL) whereas the ML model expects an image with a top-left
// origin. // origin.
// Prefer gpu_origin over this field when using GPU input images.
optional bool flip_vertically = 2 [default = false]; optional bool flip_vertically = 2 [default = false];
// Determines when the input GPU image should be flipped vertically.
// See GpuOrigin.Mode for more information.
// Affects only IMAGE_GPU inputs.
// If unset, falls back to flip_vertically for backwards compatibility.
// Cannot set both gpu_origin and flip_vertically.
optional GpuOrigin.Mode gpu_origin = 10;
// Controls how many channels of the input image get passed through to the // Controls how many channels of the input image get passed through to the
// tensor. Valid values are 1,3,4 only. Ignored for iOS GPU. // tensor. Valid values are 1,3,4 only. Ignored for iOS GPU.
optional int32 max_num_channels = 3 [default = 3]; optional int32 max_num_channels = 3 [default = 3];
@@ -12,10 +12,15 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <cmath>
#include <cstdint>
#include <memory>
#include <random> #include <random>
#include <utility>
#include <vector> #include <vector>
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/strings/substitute.h" #include "absl/strings/substitute.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h" #include "mediapipe/framework/calculator_runner.h"
@@ -24,8 +29,10 @@
#include "mediapipe/framework/formats/image_frame_opencv.h" #include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/formats/matrix.h" #include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/tensor.h" #include "mediapipe/framework/formats/tensor.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h" #include "mediapipe/framework/port/gtest.h"
#include "mediapipe/framework/port/integral_types.h" #include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/opencv_core_inc.h"
#include "mediapipe/framework/port/parse_text_proto.h" #include "mediapipe/framework/port/parse_text_proto.h"
#include "mediapipe/framework/port/status_matchers.h" // NOLINT #include "mediapipe/framework/port/status_matchers.h" // NOLINT
#include "mediapipe/framework/tool/validate_type.h" #include "mediapipe/framework/tool/validate_type.h"
@@ -40,7 +47,7 @@ constexpr char kTransposeOptionsString[] =
} // namespace } // namespace
using RandomEngine = std::mt19937_64; using RandomEngine = std::mt19937_64;
using testing::Eq; using ::testing::HasSubstr;
const uint32_t kSeed = 1234; const uint32_t kSeed = 1234;
const int kNumSizes = 8; const int kNumSizes = 8;
const int sizes[kNumSizes][2] = {{1, 1}, {12, 1}, {1, 9}, {2, 2}, const int sizes[kNumSizes][2] = {{1, 1}, {12, 1}, {1, 9}, {2, 2},
@@ -53,7 +60,7 @@ class TensorConverterCalculatorTest : public ::testing::Test {
bool row_major_matrix = false) { bool row_major_matrix = false) {
RandomEngine random(kSeed); RandomEngine random(kSeed);
std::uniform_real_distribution<> uniform_dist(0, 1.0); std::uniform_real_distribution<> uniform_dist(0, 1.0);
auto matrix = ::absl::make_unique<Matrix>(); auto matrix = std::make_unique<Matrix>();
matrix->resize(num_rows, num_columns); matrix->resize(num_rows, num_columns);
if (row_major_matrix) { if (row_major_matrix) {
for (int y = 0; y < num_rows; ++y) { for (int y = 0; y < num_rows; ++y) {
@@ -101,7 +108,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixColMajor) {
tool::AddVectorSink("tensor", &graph_config, &output_packets); tool::AddVectorSink("tensor", &graph_config, &output_packets);
// Run the graph. // Run the graph.
graph_ = absl::make_unique<CalculatorGraph>(); graph_ = std::make_unique<CalculatorGraph>();
MP_ASSERT_OK(graph_->Initialize(graph_config)); MP_ASSERT_OK(graph_->Initialize(graph_config));
MP_ASSERT_OK(graph_->StartRun({})); MP_ASSERT_OK(graph_->StartRun({}));
@@ -110,12 +117,12 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixColMajor) {
// Wait until the calculator done processing. // Wait until the calculator done processing.
MP_ASSERT_OK(graph_->WaitUntilIdle()); MP_ASSERT_OK(graph_->WaitUntilIdle());
EXPECT_EQ(1, output_packets.size()); ASSERT_EQ(output_packets.size(), 1);
// Get and process results. // Get and process results.
const std::vector<Tensor>& tensor_vec = const std::vector<Tensor>& tensor_vec =
output_packets[0].Get<std::vector<Tensor>>(); output_packets[0].Get<std::vector<Tensor>>();
EXPECT_EQ(1, tensor_vec.size()); ASSERT_EQ(tensor_vec.size(), 1);
const Tensor* tensor = &tensor_vec[0]; const Tensor* tensor = &tensor_vec[0];
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type()); EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
@@ -127,7 +134,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixColMajor) {
auto tensor_buffer = view.buffer<float>(); auto tensor_buffer = view.buffer<float>();
for (int i = 0; i < num_rows * num_columns; ++i) { for (int i = 0; i < num_rows * num_columns; ++i) {
const float expected = uniform_dist(random); const float expected = uniform_dist(random);
EXPECT_EQ(expected, tensor_buffer[i]) << "at i = " << i; EXPECT_FLOAT_EQ(tensor_buffer[i], expected) << "at i = " << i;
} }
// Fully close graph at end, otherwise calculator+tensors are destroyed // Fully close graph at end, otherwise calculator+tensors are destroyed
@@ -163,7 +170,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixRowMajor) {
tool::AddVectorSink("tensor", &graph_config, &output_packets); tool::AddVectorSink("tensor", &graph_config, &output_packets);
// Run the graph. // Run the graph.
graph_ = absl::make_unique<CalculatorGraph>(); graph_ = std::make_unique<CalculatorGraph>();
MP_ASSERT_OK(graph_->Initialize(graph_config)); MP_ASSERT_OK(graph_->Initialize(graph_config));
MP_ASSERT_OK(graph_->StartRun({})); MP_ASSERT_OK(graph_->StartRun({}));
@@ -172,12 +179,12 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixRowMajor) {
// Wait until the calculator done processing. // Wait until the calculator done processing.
MP_ASSERT_OK(graph_->WaitUntilIdle()); MP_ASSERT_OK(graph_->WaitUntilIdle());
EXPECT_EQ(1, output_packets.size()); ASSERT_EQ(output_packets.size(), 1);
// Get and process results. // Get and process results.
const std::vector<Tensor>& tensor_vec = const std::vector<Tensor>& tensor_vec =
output_packets[0].Get<std::vector<Tensor>>(); output_packets[0].Get<std::vector<Tensor>>();
EXPECT_EQ(1, tensor_vec.size()); ASSERT_EQ(tensor_vec.size(), 1);
const Tensor* tensor = &tensor_vec[0]; const Tensor* tensor = &tensor_vec[0];
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type()); EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
@@ -189,7 +196,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixRowMajor) {
auto tensor_buffer = view.buffer<float>(); auto tensor_buffer = view.buffer<float>();
for (int i = 0; i < num_rows * num_columns; ++i) { for (int i = 0; i < num_rows * num_columns; ++i) {
const float expected = uniform_dist(random); const float expected = uniform_dist(random);
EXPECT_EQ(expected, tensor_buffer[i]) << "at i = " << i; EXPECT_EQ(tensor_buffer[i], expected) << "at i = " << i;
} }
// Fully close graph at end, otherwise calculator+tensors are destroyed // Fully close graph at end, otherwise calculator+tensors are destroyed
@@ -227,7 +234,7 @@ TEST_F(TensorConverterCalculatorTest, CustomDivAndSub) {
// Run the graph. // Run the graph.
MP_ASSERT_OK(graph.Initialize(graph_config)); MP_ASSERT_OK(graph.Initialize(graph_config));
MP_ASSERT_OK(graph.StartRun({})); MP_ASSERT_OK(graph.StartRun({}));
auto input_image = absl::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1); auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1);
cv::Mat mat = mediapipe::formats::MatView(input_image.get()); cv::Mat mat = mediapipe::formats::MatView(input_image.get());
mat.at<uint8_t>(0, 0) = 200; mat.at<uint8_t>(0, 0) = 200;
MP_ASSERT_OK(graph.AddPacketToInputStream( MP_ASSERT_OK(graph.AddPacketToInputStream(
@@ -239,12 +246,12 @@ TEST_F(TensorConverterCalculatorTest, CustomDivAndSub) {
// Get and process results. // Get and process results.
const std::vector<Tensor>& tensor_vec = const std::vector<Tensor>& tensor_vec =
output_packets[0].Get<std::vector<Tensor>>(); output_packets[0].Get<std::vector<Tensor>>();
EXPECT_EQ(1, tensor_vec.size()); ASSERT_EQ(tensor_vec.size(), 1);
const Tensor* tensor = &tensor_vec[0]; const Tensor* tensor = &tensor_vec[0];
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type()); EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
auto view = tensor->GetCpuReadView(); auto view = tensor->GetCpuReadView();
EXPECT_FLOAT_EQ(67.0f, *view.buffer<float>()); EXPECT_FLOAT_EQ(*view.buffer<float>(), 67.0f);
// Fully close graph at end, otherwise calculator+tensors are destroyed // Fully close graph at end, otherwise calculator+tensors are destroyed
// after calling WaitUntilDone(). // after calling WaitUntilDone().
@@ -259,32 +266,29 @@ TEST_F(TensorConverterCalculatorTest, SetOutputRange) {
for (std::pair<float, float> range : range_values) { for (std::pair<float, float> range : range_values) {
CalculatorGraph graph; CalculatorGraph graph;
CalculatorGraphConfig graph_config = CalculatorGraphConfig graph_config =
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>( mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(absl::Substitute(
absl::Substitute(R"( R"pb(
input_stream: "input_image" input_stream: "input_image"
node { node {
calculator: "TensorConverterCalculator" calculator: "TensorConverterCalculator"
input_stream: "IMAGE:input_image" input_stream: "IMAGE:input_image"
output_stream: "TENSORS:tensor" output_stream: "TENSORS:tensor"
options { options {
[mediapipe.TensorConverterCalculatorOptions.ext] { [mediapipe.TensorConverterCalculatorOptions.ext] {
output_tensor_float_range { output_tensor_float_range { min: $0 max: $1 }
min: $0 }
max: $1 }
} }
} )pb",
} /*$0=*/range.first,
} /*$1=*/range.second));
)",
/*$0=*/range.first,
/*$1=*/range.second));
std::vector<Packet> output_packets; std::vector<Packet> output_packets;
tool::AddVectorSink("tensor", &graph_config, &output_packets); tool::AddVectorSink("tensor", &graph_config, &output_packets);
// Run the graph. // Run the graph.
MP_ASSERT_OK(graph.Initialize(graph_config)); MP_ASSERT_OK(graph.Initialize(graph_config));
MP_ASSERT_OK(graph.StartRun({})); MP_ASSERT_OK(graph.StartRun({}));
auto input_image = absl::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1); auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1);
cv::Mat mat = mediapipe::formats::MatView(input_image.get()); cv::Mat mat = mediapipe::formats::MatView(input_image.get());
mat.at<uint8_t>(0, 0) = 200; mat.at<uint8_t>(0, 0) = 200;
MP_ASSERT_OK(graph.AddPacketToInputStream( MP_ASSERT_OK(graph.AddPacketToInputStream(
@@ -292,26 +296,23 @@ TEST_F(TensorConverterCalculatorTest, SetOutputRange) {
// Wait until the calculator finishes processing. // Wait until the calculator finishes processing.
MP_ASSERT_OK(graph.WaitUntilIdle()); MP_ASSERT_OK(graph.WaitUntilIdle());
EXPECT_THAT(output_packets.size(), Eq(1)); ASSERT_EQ(output_packets.size(), 1);
// Get and process results. // Get and process results.
const std::vector<Tensor>& tensor_vec = const std::vector<Tensor>& tensor_vec =
output_packets[0].Get<std::vector<Tensor>>(); output_packets[0].Get<std::vector<Tensor>>();
EXPECT_THAT(tensor_vec.size(), Eq(1)); ASSERT_EQ(tensor_vec.size(), 1);
const Tensor* tensor = &tensor_vec[0]; const Tensor* tensor = &tensor_vec[0];
// Calculate the expected normalized value: // Calculate the expected normalized value:
float normalized_value = float expected_value =
range.first + (200 * (range.second - range.first)) / 255.0; range.first + (200 * (range.second - range.first)) / 255.0;
EXPECT_THAT(tensor->element_type(), Eq(Tensor::ElementType::kFloat32)); EXPECT_EQ(tensor->element_type(), Tensor::ElementType::kFloat32);
auto view = tensor->GetCpuReadView(); auto view = tensor->GetCpuReadView();
float dataf = *view.buffer<float>(); float actual_value = *view.buffer<float>();
EXPECT_THAT( EXPECT_FLOAT_EQ(actual_value, expected_value);
normalized_value,
testing::FloatNear(dataf, 2.0f * std::abs(dataf) *
std::numeric_limits<float>::epsilon()));
// Fully close graph at end, otherwise calculator+tensors are destroyed // Fully close graph at end, otherwise calculator+tensors are destroyed
// after calling WaitUntilDone(). // after calling WaitUntilDone().
@@ -320,4 +321,153 @@ TEST_F(TensorConverterCalculatorTest, SetOutputRange) {
} }
} }
TEST_F(TensorConverterCalculatorTest, FlipVertically) {
CalculatorGraph graph;
CalculatorGraphConfig graph_config =
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
input_stream: "input_image"
node {
calculator: "TensorConverterCalculator"
input_stream: "IMAGE:input_image"
output_stream: "TENSORS:tensor"
options {
[mediapipe.TensorConverterCalculatorOptions.ext] {
flip_vertically: true
output_tensor_float_range { min: 0 max: 255 }
}
}
}
)pb");
std::vector<Packet> output_packets;
tool::AddVectorSink("tensor", &graph_config, &output_packets);
// Run the graph.
MP_ASSERT_OK(graph.Initialize(graph_config));
MP_ASSERT_OK(graph.StartRun({}));
auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 2);
cv::Mat mat = mediapipe::formats::MatView(input_image.get());
constexpr uint8_t kY0Value = 100;
constexpr uint8_t kY1Value = 200;
mat.at<uint8_t>(0, 0) = kY0Value;
mat.at<uint8_t>(1, 0) = kY1Value; // Note: y, x!
MP_ASSERT_OK(graph.AddPacketToInputStream(
"input_image", Adopt(input_image.release()).At(Timestamp(0))));
// Wait until the calculator finishes processing.
MP_ASSERT_OK(graph.WaitUntilIdle());
ASSERT_EQ(output_packets.size(), 1);
// Get and process results.
const std::vector<Tensor>& tensor_vec =
output_packets[0].Get<std::vector<Tensor>>();
ASSERT_EQ(tensor_vec.size(), 1);
const Tensor* tensor = &tensor_vec[0];
EXPECT_EQ(tensor->element_type(), Tensor::ElementType::kFloat32);
const float* dataf = tensor->GetCpuReadView().buffer<float>();
EXPECT_EQ(static_cast<int>(roundf(dataf[0])), kY1Value); // Y0, Y1 flipped!
EXPECT_EQ(static_cast<int>(roundf(dataf[1])), kY0Value);
// Fully close graph at end, otherwise calculator+tensors are destroyed
// after calling WaitUntilDone().
MP_ASSERT_OK(graph.CloseInputStream("input_image"));
MP_ASSERT_OK(graph.WaitUntilDone());
}
TEST_F(TensorConverterCalculatorTest,
CannotSpecifyBothFlipVerticallyAndGpuOrigin) {
CalculatorGraph graph;
CalculatorGraphConfig graph_config =
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
input_stream: "input_image"
node {
calculator: "TensorConverterCalculator"
input_stream: "IMAGE:input_image"
output_stream: "TENSORS:tensor"
options {
[mediapipe.TensorConverterCalculatorOptions.ext] {
flip_vertically: true
gpu_origin: TOP_LEFT
output_tensor_float_range { min: 0 max: 255 }
}
}
}
)pb");
std::vector<Packet> output_packets;
tool::AddVectorSink("tensor", &graph_config, &output_packets);
// Run the graph.
MP_ASSERT_OK(graph.Initialize(graph_config));
MP_ASSERT_OK(graph.StartRun({}));
auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1);
MP_ASSERT_OK(graph.AddPacketToInputStream(
"input_image", Adopt(input_image.release()).At(Timestamp(0))));
// Processing should fail as we specified both flip_vertically and gpu_origin.
absl::Status status = graph.WaitUntilIdle();
EXPECT_FALSE(status.ok());
EXPECT_THAT(status.message(), HasSubstr("flip_vertically and gpu_origin"));
EXPECT_EQ(output_packets.size(), 0);
// Fully close graph at end, otherwise calculator+tensors are destroyed
// after calling WaitUntilDone().
MP_ASSERT_OK(graph.CloseInputStream("input_image"));
EXPECT_FALSE(graph.WaitUntilDone().ok());
}
TEST_F(TensorConverterCalculatorTest, GpuOriginIsIgnoredWithCpuImage) {
CalculatorGraph graph;
CalculatorGraphConfig graph_config =
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
input_stream: "input_image"
node {
calculator: "TensorConverterCalculator"
input_stream: "IMAGE:input_image"
output_stream: "TENSORS:tensor"
options {
[mediapipe.TensorConverterCalculatorOptions.ext] {
gpu_origin: CONVENTIONAL
output_tensor_float_range { min: 0 max: 255 }
}
}
}
)pb");
std::vector<Packet> output_packets;
tool::AddVectorSink("tensor", &graph_config, &output_packets);
// Run the graph.
MP_ASSERT_OK(graph.Initialize(graph_config));
MP_ASSERT_OK(graph.StartRun({}));
auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 2);
cv::Mat mat = mediapipe::formats::MatView(input_image.get());
constexpr uint8_t kY0Value = 100;
constexpr uint8_t kY1Value = 200;
mat.at<uint8_t>(0, 0) = kY0Value;
mat.at<uint8_t>(1, 0) = kY1Value; // Note: y, x!
MP_ASSERT_OK(graph.AddPacketToInputStream(
"input_image", Adopt(input_image.release()).At(Timestamp(0))));
// Wait until the calculator finishes processing.
MP_ASSERT_OK(graph.WaitUntilIdle());
ASSERT_EQ(output_packets.size(), 1);
// Get and process results.
const std::vector<Tensor>& tensor_vec =
output_packets[0].Get<std::vector<Tensor>>();
ASSERT_EQ(tensor_vec.size(), 1);
const Tensor* tensor = &tensor_vec[0];
EXPECT_EQ(tensor->element_type(), Tensor::ElementType::kFloat32);
const float* dataf = tensor->GetCpuReadView().buffer<float>();
EXPECT_EQ(static_cast<int>(roundf(dataf[0])), kY0Value); // Not flipped!
EXPECT_EQ(static_cast<int>(roundf(dataf[1])), kY1Value);
// Fully close graph at end, otherwise calculator+tensors are destroyed
// after calling WaitUntilDone().
MP_ASSERT_OK(graph.CloseInputStream("input_image"));
MP_ASSERT_OK(graph.WaitUntilDone());
}
} // namespace mediapipe } // namespace mediapipe
@@ -0,0 +1,84 @@
// 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.
#include "mediapipe/calculators/tensor/tensor_to_joints_calculator.h"
#include <utility>
#include "mediapipe/calculators/tensor/tensor_to_joints_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/body_rig.pb.h"
#include "mediapipe/framework/formats/tensor.h"
#include "mediapipe/framework/port/ret_check.h"
namespace mediapipe {
namespace api2 {
namespace {
// Number of values in 6D representation of rotation.
constexpr int kRotation6dSize = 6;
} // namespace
class TensorToJointsCalculatorImpl
: public mediapipe::api2::NodeImpl<TensorToJointsCalculator> {
public:
absl::Status Open(CalculatorContext* cc) override {
const auto& options = cc->Options<TensorToJointsCalculatorOptions>();
// Get number of joints.
RET_CHECK_GE(options.num_joints(), 0);
num_joints_ = options.num_joints();
// Get start index.
start_index_ = options.start_index();
return absl::OkStatus();
}
absl::Status Process(CalculatorContext* cc) override {
// Skip if Tensor is empty.
if (kInTensor(cc).IsEmpty()) {
return absl::OkStatus();
}
// Get raw floats from the Tensor.
const Tensor& tensor = kInTensor(cc).Get();
RET_CHECK_EQ(tensor.shape().num_elements(),
num_joints_ * kRotation6dSize + start_index_)
<< "Unexpected number of values in Tensor";
const float* raw_floats = tensor.GetCpuReadView().buffer<float>();
// Convert raw floats into Joint rotations.
JointList joints;
for (int joint_idx = 0; joint_idx < num_joints_; ++joint_idx) {
Joint* joint = joints.add_joint();
for (int idx_6d = 0; idx_6d < kRotation6dSize; ++idx_6d) {
joint->add_rotation_6d(
raw_floats[start_index_ + joint_idx * kRotation6dSize + idx_6d]);
}
}
kOutJoints(cc).Send(std::move(joints));
return absl::OkStatus();
}
private:
int num_joints_ = 0;
int start_index_ = 0;
};
MEDIAPIPE_NODE_IMPLEMENTATION(TensorToJointsCalculatorImpl);
} // namespace api2
} // namespace mediapipe
@@ -0,0 +1,64 @@
// 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.
#ifndef MEDIAPIPE_CALCULATORS_TENSOR_TENSOR_TO_JOINTS_CALCULATOR_H_
#define MEDIAPIPE_CALCULATORS_TENSOR_TENSOR_TO_JOINTS_CALCULATOR_H_
#include <memory>
#include "mediapipe/framework/api2/node.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/body_rig.pb.h"
#include "mediapipe/framework/formats/tensor.h"
namespace mediapipe {
namespace api2 {
// A calculator to convert Tensors to JointList.
//
// Calculator fills in only rotation of the joints leaving visibility undefined.
//
// Input:
// TENSOR - std::vector<Tensor> with kFloat32 values
// Vector of tensors to be converted to joints. Only the first tensor will
// be used. Number of values is expected to be multiple of six.
//
// Output:
// JOINTS - JointList
// List of joints with rotations extracted from given tensor and undefined
// visibility.
//
// Example:
// node {
// calculator: "TensorToJointsCalculator"
// input_stream: "TENSOR:tensor"
// output_stream: "JOINTS:joints"
// options: {
// [mediapipe.TensorToJointsCalculatorOptions.ext] {
// num_joints: 56
// start_index: 3
// }
// }
// }
class TensorToJointsCalculator : public NodeIntf {
public:
static constexpr Input<mediapipe::Tensor> kInTensor{"TENSOR"};
static constexpr Output<mediapipe::JointList> kOutJoints{"JOINTS"};
MEDIAPIPE_NODE_INTERFACE(TensorToJointsCalculator, kInTensor, kOutJoints);
};
} // namespace api2
} // namespace mediapipe
#endif // MEDIAPIPE_CALCULATORS_TENSOR_TENSOR_TO_JOINTS_CALCULATOR_H_
@@ -0,0 +1,32 @@
// 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.
syntax = "proto2";
package mediapipe;
import "mediapipe/framework/calculator.proto";
message TensorToJointsCalculatorOptions {
extend CalculatorOptions {
optional TensorToJointsCalculatorOptions ext = 406440177;
}
// Number of joints from the output of the model. Calculator will expect the
// tensor to contain `6 * num_joints + start_index` values.
optional int32 num_joints = 1;
// Index to start reading 6 value blocks from.
optional int32 start_index = 2 [default = 0];
}
@@ -0,0 +1,123 @@
// 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.
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/strings/substitute.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/formats/body_rig.pb.h"
#include "mediapipe/framework/formats/tensor.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h"
#include "mediapipe/framework/port/parse_text_proto.h"
#include "mediapipe/framework/port/status_matchers.h"
#include "mediapipe/framework/timestamp.h"
namespace mediapipe {
namespace api2 {
namespace {
using Node = ::mediapipe::CalculatorGraphConfig::Node;
struct TensorToJointsTestCase {
std::string test_name;
int num_joints;
int start_index;
std::vector<float> raw_values;
std::vector<std::vector<float>> expected_rotations;
};
using TensorToJointsTest = ::testing::TestWithParam<TensorToJointsTestCase>;
TEST_P(TensorToJointsTest, TensorToJointsTest) {
const TensorToJointsTestCase& tc = GetParam();
// Prepare graph.
mediapipe::CalculatorRunner runner(ParseTextProtoOrDie<Node>(absl::Substitute(
R"(
calculator: "TensorToJointsCalculator"
input_stream: "TENSOR:tensor"
output_stream: "JOINTS:joints"
options: {
[mediapipe.TensorToJointsCalculatorOptions.ext] {
num_joints: $0
start_index: $1
}
}
)",
tc.num_joints, tc.start_index)));
// Prepare tensor.
Tensor tensor(Tensor::ElementType::kFloat32,
Tensor::Shape{1, 1, static_cast<int>(tc.raw_values.size()), 1});
float* tensor_buffer = tensor.GetCpuWriteView().buffer<float>();
ASSERT_NE(tensor_buffer, nullptr);
for (int i = 0; i < tc.raw_values.size(); ++i) {
tensor_buffer[i] = tc.raw_values[i];
}
// Send tensor to the graph.
runner.MutableInputs()->Tag("TENSOR").packets.push_back(
mediapipe::MakePacket<Tensor>(std::move(tensor)).At(Timestamp(0)));
// Run the graph.
MP_ASSERT_OK(runner.Run());
const auto& output_packets = runner.Outputs().Tag("JOINTS").packets;
EXPECT_EQ(1, output_packets.size());
const auto& joints = output_packets[0].Get<JointList>();
EXPECT_EQ(joints.joint_size(), tc.expected_rotations.size());
for (int i = 0; i < joints.joint_size(); ++i) {
const Joint& joint = joints.joint(i);
std::vector<float> expected_rotation_6d = tc.expected_rotations[i];
EXPECT_EQ(joint.rotation_6d_size(), expected_rotation_6d.size())
<< "Unexpected joint #" << i << " rotation";
for (int j = 0; j < joint.rotation_6d_size(); ++j) {
EXPECT_EQ(joint.rotation_6d(j), expected_rotation_6d[j])
<< "Unexpected joint #" << i << " rotation";
}
EXPECT_FALSE(joint.has_visibility());
}
}
INSTANTIATE_TEST_SUITE_P(
TensorToJointsTests, TensorToJointsTest,
testing::ValuesIn<TensorToJointsTestCase>({
{"Empty", 0, 3, {0, 0, 0}, {}},
{"Single",
1,
3,
{0, 0, 0, 10, 11, 12, 13, 14, 15},
{{10, 11, 12, 13, 14, 15}}},
{"Double",
2,
3,
{0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21},
{{10, 11, 12, 13, 14, 15}, {16, 17, 18, 19, 20, 21}}},
}),
[](const testing::TestParamInfo<TensorToJointsTest::ParamType>& info) {
return info.param.test_name;
});
} // namespace
} // namespace api2
} // namespace mediapipe
@@ -110,8 +110,8 @@ absl::Status TensorsToClassificationCalculator::Open(CalculatorContext* cc) {
sort_by_descending_score_ = options.sort_by_descending_score(); sort_by_descending_score_ = options.sort_by_descending_score();
if (options.has_label_map_path()) { if (options.has_label_map_path()) {
std::string string_path; std::string string_path;
ASSIGN_OR_RETURN(string_path, MP_ASSIGN_OR_RETURN(string_path,
PathToResourceAsFile(options.label_map_path())); PathToResourceAsFile(options.label_map_path()));
std::string label_map_string; std::string label_map_string;
MP_RETURN_IF_ERROR( MP_RETURN_IF_ERROR(
mediapipe::GetResourceContents(string_path, &label_map_string)); mediapipe::GetResourceContents(string_path, &label_map_string));
@@ -15,6 +15,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "absl/log/absl_log.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/types/span.h" #include "absl/types/span.h"
#include "mediapipe/calculators/tensor/tensors_to_detections_calculator.pb.h" #include "mediapipe/calculators/tensor/tensors_to_detections_calculator.pb.h"
@@ -83,7 +84,7 @@ void ConvertRawValuesToAnchors(const float* raw_anchors, int num_boxes,
void ConvertAnchorsToRawValues(const std::vector<Anchor>& anchors, void ConvertAnchorsToRawValues(const std::vector<Anchor>& anchors,
int num_boxes, float* raw_anchors) { int num_boxes, float* raw_anchors) {
CHECK_EQ(anchors.size(), num_boxes); ABSL_CHECK_EQ(anchors.size(), num_boxes);
int box = 0; int box = 0;
for (const auto& anchor : anchors) { for (const auto& anchor : anchors) {
raw_anchors[box * kNumCoordsPerBox + 0] = anchor.y_center(); raw_anchors[box * kNumCoordsPerBox + 0] = anchor.y_center();
@@ -329,7 +330,7 @@ absl::Status TensorsToDetectionsCalculator::Process(CalculatorContext* cc) {
} else if (status.code() == absl::StatusCode::kFailedPrecondition) { } else if (status.code() == absl::StatusCode::kFailedPrecondition) {
// For initialization error because of hardware limitation, fallback to // For initialization error because of hardware limitation, fallback to
// CPU processing. // CPU processing.
LOG(WARNING) << status.message(); ABSL_LOG(WARNING) << status.message();
} else { } else {
// For other error, let the error propagates. // For other error, let the error propagates.
return status; return status;
@@ -668,7 +669,7 @@ absl::Status TensorsToDetectionsCalculator::ProcessGPU(
output_detections)); output_detections));
#else #else
LOG(ERROR) << "GPU input on non-Android not supported yet."; ABSL_LOG(ERROR) << "GPU input on non-Android not supported yet.";
#endif // !defined(MEDIAPIPE_DISABLE_GL_COMPUTE) #endif // !defined(MEDIAPIPE_DISABLE_GL_COMPUTE)
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -703,18 +704,18 @@ absl::Status TensorsToDetectionsCalculator::LoadOptions(CalculatorContext* cc) {
num_boxes_ = options_.num_boxes(); num_boxes_ = options_.num_boxes();
num_coords_ = options_.num_coords(); num_coords_ = options_.num_coords();
box_output_format_ = GetBoxFormat(options_); box_output_format_ = GetBoxFormat(options_);
CHECK_NE(options_.max_results(), 0) ABSL_CHECK_NE(options_.max_results(), 0)
<< "The maximum number of the top-scored detection results must be " << "The maximum number of the top-scored detection results must be "
"non-zero."; "non-zero.";
max_results_ = options_.max_results(); max_results_ = options_.max_results();
// Currently only support 2D when num_values_per_keypoint equals to 2. // Currently only support 2D when num_values_per_keypoint equals to 2.
CHECK_EQ(options_.num_values_per_keypoint(), 2); ABSL_CHECK_EQ(options_.num_values_per_keypoint(), 2);
// Check if the output size is equal to the requested boxes and keypoints. // Check if the output size is equal to the requested boxes and keypoints.
CHECK_EQ(options_.num_keypoints() * options_.num_values_per_keypoint() + ABSL_CHECK_EQ(options_.num_keypoints() * options_.num_values_per_keypoint() +
kNumCoordsPerBox, kNumCoordsPerBox,
num_coords_); num_coords_);
if (kSideInIgnoreClasses(cc).IsConnected()) { if (kSideInIgnoreClasses(cc).IsConnected()) {
RET_CHECK(!kSideInIgnoreClasses(cc).IsEmpty()); RET_CHECK(!kSideInIgnoreClasses(cc).IsEmpty());
@@ -1154,11 +1155,12 @@ void main() {
} }
// TODO support better filtering. // TODO support better filtering.
if (class_index_set_.is_allowlist) { if (class_index_set_.is_allowlist) {
CHECK_EQ(class_index_set_.values.size(), ABSL_CHECK_EQ(class_index_set_.values.size(),
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1) IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
<< "Only all classes >= class 0 or >= class 1"; << "Only all classes >= class 0 or >= class 1";
} else { } else {
CHECK_EQ(class_index_set_.values.size(), IsClassIndexAllowed(0) ? 0 : 1) ABSL_CHECK_EQ(class_index_set_.values.size(),
IsClassIndexAllowed(0) ? 0 : 1)
<< "Only ignore class 0 is allowed"; << "Only ignore class 0 is allowed";
} }
@@ -1379,11 +1381,12 @@ kernel void scoreKernel(
// TODO support better filtering. // TODO support better filtering.
if (class_index_set_.is_allowlist) { if (class_index_set_.is_allowlist) {
CHECK_EQ(class_index_set_.values.size(), ABSL_CHECK_EQ(class_index_set_.values.size(),
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1) IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
<< "Only all classes >= class 0 or >= class 1"; << "Only all classes >= class 0 or >= class 1";
} else { } else {
CHECK_EQ(class_index_set_.values.size(), IsClassIndexAllowed(0) ? 0 : 1) ABSL_CHECK_EQ(class_index_set_.values.size(),
IsClassIndexAllowed(0) ? 0 : 1)
<< "Only ignore class 0 is allowed"; << "Only ignore class 0 is allowed";
} }
@@ -142,7 +142,7 @@ absl::Status TensorsToLandmarksCalculator::Process(CalculatorContext* cc) {
RET_CHECK(input_tensors[0].element_type() == Tensor::ElementType::kFloat32); RET_CHECK(input_tensors[0].element_type() == Tensor::ElementType::kFloat32);
int num_values = input_tensors[0].shape().num_elements(); int num_values = input_tensors[0].shape().num_elements();
const int num_dimensions = num_values / num_landmarks_; const int num_dimensions = num_values / num_landmarks_;
CHECK_GT(num_dimensions, 0); ABSL_CHECK_GT(num_dimensions, 0);
auto view = input_tensors[0].GetCpuReadView(); auto view = input_tensors[0].GetCpuReadView();
auto raw_landmarks = view.buffer<float>(); auto raw_landmarks = view.buffer<float>();
@@ -174,6 +174,9 @@ class TensorsToSegmentationCalculator : public CalculatorBase {
mediapipe::GlCalculatorHelper gpu_helper_; mediapipe::GlCalculatorHelper gpu_helper_;
GLuint upsample_program_; GLuint upsample_program_;
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
int cached_width_ = 0;
int cached_height_ = 0;
std::unique_ptr<tflite::gpu::gl::GlTexture> small_mask_texture_;
std::unique_ptr<GlProgram> mask_program_31_; std::unique_ptr<GlProgram> mask_program_31_;
#else #else
GLuint mask_program_20_; GLuint mask_program_20_;
@@ -264,7 +267,8 @@ absl::Status TensorsToSegmentationCalculator::Process(CalculatorContext* cc) {
{ {
RET_CHECK(!input_tensors.empty()); RET_CHECK(!input_tensors.empty());
RET_CHECK(input_tensors[0].element_type() == Tensor::ElementType::kFloat32); RET_CHECK(input_tensors[0].element_type() == Tensor::ElementType::kFloat32);
ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims)); MP_ASSIGN_OR_RETURN(auto hwc,
GetHwcFromDims(input_tensors[0].shape().dims));
int tensor_channels = std::get<2>(hwc); int tensor_channels = std::get<2>(hwc);
typedef mediapipe::TensorsToSegmentationCalculatorOptions Options; typedef mediapipe::TensorsToSegmentationCalculatorOptions Options;
switch (options_.activation()) { switch (options_.activation()) {
@@ -307,6 +311,7 @@ absl::Status TensorsToSegmentationCalculator::Close(CalculatorContext* cc) {
upsample_program_ = 0; upsample_program_ = 0;
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
mask_program_31_.reset(); mask_program_31_.reset();
small_mask_texture_.reset();
#else #else
if (mask_program_20_) glDeleteProgram(mask_program_20_); if (mask_program_20_) glDeleteProgram(mask_program_20_);
mask_program_20_ = 0; mask_program_20_ = 0;
@@ -326,7 +331,7 @@ absl::Status TensorsToSegmentationCalculator::ProcessCpu(
// Get input streams, and dimensions. // Get input streams, and dimensions.
const auto& input_tensors = const auto& input_tensors =
cc->Inputs().Tag(kTensorsTag).Get<std::vector<Tensor>>(); cc->Inputs().Tag(kTensorsTag).Get<std::vector<Tensor>>();
ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims)); MP_ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims));
auto [tensor_height, tensor_width, tensor_channels] = hwc; auto [tensor_height, tensor_width, tensor_channels] = hwc;
int output_width = tensor_width, output_height = tensor_height; int output_width = tensor_width, output_height = tensor_height;
if (cc->Inputs().HasTag(kOutputSizeTag)) { if (cc->Inputs().HasTag(kOutputSizeTag)) {
@@ -437,7 +442,7 @@ absl::Status TensorsToSegmentationCalculator::ProcessGpu(
// Get input streams, and dimensions. // Get input streams, and dimensions.
const auto& input_tensors = const auto& input_tensors =
cc->Inputs().Tag(kTensorsTag).Get<std::vector<Tensor>>(); cc->Inputs().Tag(kTensorsTag).Get<std::vector<Tensor>>();
ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims)); MP_ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims));
auto [tensor_height, tensor_width, tensor_channels] = hwc; auto [tensor_height, tensor_width, tensor_channels] = hwc;
int output_width = tensor_width, output_height = tensor_height; int output_width = tensor_width, output_height = tensor_height;
if (cc->Inputs().HasTag(kOutputSizeTag)) { if (cc->Inputs().HasTag(kOutputSizeTag)) {
@@ -448,21 +453,24 @@ absl::Status TensorsToSegmentationCalculator::ProcessGpu(
} }
// Create initial working mask texture. // Create initial working mask texture.
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #if !(MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31)
tflite::gpu::gl::GlTexture small_mask_texture;
#else
mediapipe::GlTexture small_mask_texture; mediapipe::GlTexture small_mask_texture;
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
// Run shader, process mask tensor. // Run shader, process mask tensor.
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
{ {
MP_RETURN_IF_ERROR(CreateReadWriteRgbaImageTexture( // Only recreate if the size has changed. See b/297809673 for more details.
tflite::gpu::DataType::UINT8, // GL_RGBA8 if (tensor_width != cached_width_ || tensor_height != cached_height_) {
{tensor_width, tensor_height}, &small_mask_texture)); MP_RETURN_IF_ERROR(CreateReadWriteRgbaImageTexture(
tflite::gpu::DataType::UINT8, // GL_RGBA8
{tensor_width, tensor_height}, small_mask_texture_.get()));
cached_width_ = tensor_width;
cached_height_ = tensor_height;
}
const int output_index = 0; const int output_index = 0;
glBindImageTexture(output_index, small_mask_texture.id(), 0, GL_FALSE, 0, glBindImageTexture(output_index, small_mask_texture_->id(), 0, GL_FALSE, 0,
GL_WRITE_ONLY, GL_RGBA8); GL_WRITE_ONLY, GL_RGBA8);
auto read_view = input_tensors[0].GetOpenGlBufferReadView(); auto read_view = input_tensors[0].GetOpenGlBufferReadView();
@@ -547,7 +555,7 @@ absl::Status TensorsToSegmentationCalculator::ProcessGpu(
gpu_helper_.BindFramebuffer(output_texture); gpu_helper_.BindFramebuffer(output_texture);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
glBindTexture(GL_TEXTURE_2D, small_mask_texture.id()); glBindTexture(GL_TEXTURE_2D, small_mask_texture_->id());
#else #else
glBindTexture(GL_TEXTURE_2D, small_mask_texture.name()); glBindTexture(GL_TEXTURE_2D, small_mask_texture.name());
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 #endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
@@ -854,6 +862,7 @@ void main() {
mask_program_31_ = absl::make_unique<GlProgram>(); mask_program_31_ = absl::make_unique<GlProgram>();
MP_RETURN_IF_ERROR(GlProgram::CreateWithShader(shader_without_previous, MP_RETURN_IF_ERROR(GlProgram::CreateWithShader(shader_without_previous,
mask_program_31_.get())); mask_program_31_.get()));
small_mask_texture_ = absl::make_unique<tflite::gpu::gl::GlTexture>();
#elif MEDIAPIPE_METAL_ENABLED #elif MEDIAPIPE_METAL_ENABLED
id<MTLDevice> device = metal_helper_.mtlDevice; id<MTLDevice> device = metal_helper_.mtlDevice;
NSString* library_source = NSString* library_source =
@@ -61,9 +61,10 @@ RunUniversalSentenceEncoderPreprocessorCalculator(absl::string_view text) {
std::string model_buffer = std::string model_buffer =
tasks::core::LoadBinaryContent(kTestModelPath.data()); tasks::core::LoadBinaryContent(kTestModelPath.data());
ASSIGN_OR_RETURN(std::unique_ptr<ModelMetadataExtractor> metadata_extractor, MP_ASSIGN_OR_RETURN(
ModelMetadataExtractor::CreateFromModelBuffer( std::unique_ptr<ModelMetadataExtractor> metadata_extractor,
model_buffer.data(), model_buffer.size())); ModelMetadataExtractor::CreateFromModelBuffer(model_buffer.data(),
model_buffer.size()));
// Run the graph. // Run the graph.
CalculatorGraph graph; CalculatorGraph graph;
MP_RETURN_IF_ERROR(graph.Initialize( MP_RETURN_IF_ERROR(graph.Initialize(
+30 -8
View File
@@ -13,6 +13,7 @@
# limitations under the License. # limitations under the License.
# #
# Placeholder: load py_proto_library
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library", "mediapipe_proto_library") load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library", "mediapipe_proto_library")
licenses(["notice"]) licenses(["notice"])
@@ -314,6 +315,7 @@ cc_library(
"//mediapipe/framework/formats:time_series_header_cc_proto", "//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
] + select({ ] + select({
"//conditions:default": [ "//conditions:default": [
"@org_tensorflow//tensorflow/core:framework", "@org_tensorflow//tensorflow/core:framework",
@@ -366,18 +368,18 @@ cc_library(
name = "pack_media_sequence_calculator", name = "pack_media_sequence_calculator",
srcs = ["pack_media_sequence_calculator.cc"], srcs = ["pack_media_sequence_calculator.cc"],
deps = [ deps = [
":pack_media_sequence_calculator_cc_proto",
"//mediapipe/calculators/image:opencv_image_encoder_calculator_cc_proto", "//mediapipe/calculators/image:opencv_image_encoder_calculator_cc_proto",
"//mediapipe/calculators/tensorflow:pack_media_sequence_calculator_cc_proto",
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:detection_cc_proto", "//mediapipe/framework/formats:detection_cc_proto",
"//mediapipe/framework/formats:location", "//mediapipe/framework/formats:location",
"//mediapipe/framework/formats:location_opencv", "//mediapipe/framework/formats:location_opencv",
"//mediapipe/framework/port:opencv_imgcodecs", "//mediapipe/framework/port:opencv_imgcodecs",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/util/sequence:media_sequence", "//mediapipe/util/sequence:media_sequence",
"//mediapipe/util/sequence:media_sequence_util", "//mediapipe/util/sequence:media_sequence_util",
"@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/core:protos_all_cc", "@org_tensorflow//tensorflow/core:protos_all_cc",
], ],
@@ -429,7 +431,7 @@ cc_library(
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/tool:status_util", "//mediapipe/framework/tool:status_util",
"@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/log:check", "@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization", "@com_google_absl//absl/synchronization",
@@ -488,10 +490,10 @@ cc_library(
"//mediapipe/calculators/tensorflow:tensorflow_session_from_frozen_graph_calculator_cc_proto", "//mediapipe/calculators/tensorflow:tensorflow_session_from_frozen_graph_calculator_cc_proto",
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/deps:clock", "//mediapipe/framework/deps:clock",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/tool:status_util", "//mediapipe/framework/tool:status_util",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:protos_all_cc", "@org_tensorflow//tensorflow/core:protos_all_cc",
] + select({ ] + select({
"//conditions:default": [ "//conditions:default": [
@@ -519,10 +521,10 @@ cc_library(
":tensorflow_session_from_frozen_graph_generator_cc_proto", ":tensorflow_session_from_frozen_graph_generator_cc_proto",
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/deps:clock", "//mediapipe/framework/deps:clock",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/tool:status_util", "//mediapipe/framework/tool:status_util",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:protos_all_cc", "@org_tensorflow//tensorflow/core:protos_all_cc",
] + select({ ] + select({
"//conditions:default": [ "//conditions:default": [
@@ -555,6 +557,7 @@ cc_library(
"//mediapipe/framework/deps:file_path", "//mediapipe/framework/deps:file_path",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/cc/saved_model:constants", "@org_tensorflow//tensorflow/cc/saved_model:constants",
"@org_tensorflow//tensorflow/cc/saved_model:loader_lite", "@org_tensorflow//tensorflow/cc/saved_model:loader_lite",
@@ -632,6 +635,7 @@ cc_library(
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/tool:status_util", "//mediapipe/framework/tool:status_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/status", "@com_google_absl//absl/status",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/cc/saved_model:constants", "@org_tensorflow//tensorflow/cc/saved_model:constants",
@@ -653,6 +657,7 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:framework", "@org_tensorflow//tensorflow/core:framework",
], ],
alwayslink = 1, alwayslink = 1,
@@ -667,6 +672,7 @@ cc_library(
"//mediapipe/framework/formats:image_frame", "//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
"@org_tensorflow//tensorflow/core:framework", "@org_tensorflow//tensorflow/core:framework",
], ],
alwayslink = 1, alwayslink = 1,
@@ -682,6 +688,7 @@ cc_library(
"//mediapipe/framework/formats:time_series_header_cc_proto", "//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
] + select({ ] + select({
"//conditions:default": [ "//conditions:default": [
"@org_tensorflow//tensorflow/core:framework", "@org_tensorflow//tensorflow/core:framework",
@@ -716,6 +723,7 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@org_tensorflow//tensorflow/core/platform:bfloat16",
] + select({ ] + select({
"//conditions:default": [ "//conditions:default": [
"@org_tensorflow//tensorflow/core:framework", "@org_tensorflow//tensorflow/core:framework",
@@ -778,6 +786,7 @@ cc_library(
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/util:audio_decoder_cc_proto", "//mediapipe/util:audio_decoder_cc_proto",
"//mediapipe/util/sequence:media_sequence", "//mediapipe/util/sequence:media_sequence",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/core:protos_all_cc", "@org_tensorflow//tensorflow/core:protos_all_cc",
], ],
@@ -792,6 +801,8 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:framework", "@org_tensorflow//tensorflow/core:framework",
], ],
alwayslink = 1, alwayslink = 1,
@@ -805,6 +816,7 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:framework", "@org_tensorflow//tensorflow/core:framework",
], ],
alwayslink = 1, alwayslink = 1,
@@ -818,6 +830,7 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:framework", "@org_tensorflow//tensorflow/core:framework",
], ],
alwayslink = 1, alwayslink = 1,
@@ -831,6 +844,8 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework:packet", "//mediapipe/framework:packet",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:protos_all_cc", "@org_tensorflow//tensorflow/core:protos_all_cc",
], ],
alwayslink = 1, alwayslink = 1,
@@ -925,21 +940,24 @@ cc_test(
srcs = ["pack_media_sequence_calculator_test.cc"], srcs = ["pack_media_sequence_calculator_test.cc"],
deps = [ deps = [
":pack_media_sequence_calculator", ":pack_media_sequence_calculator",
":pack_media_sequence_calculator_cc_proto",
"//mediapipe/calculators/image:opencv_image_encoder_calculator_cc_proto", "//mediapipe/calculators/image:opencv_image_encoder_calculator_cc_proto",
"//mediapipe/calculators/tensorflow:pack_media_sequence_calculator_cc_proto",
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework:calculator_runner", "//mediapipe/framework:calculator_runner",
"//mediapipe/framework:packet",
"//mediapipe/framework:timestamp", "//mediapipe/framework:timestamp",
"//mediapipe/framework/formats:detection_cc_proto", "//mediapipe/framework/formats:detection_cc_proto",
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/formats:location", "//mediapipe/framework/formats:location",
"//mediapipe/framework/formats:location_opencv", "//mediapipe/framework/formats:location_opencv",
"//mediapipe/framework/port:gtest_main", "//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:opencv_imgcodecs", "//mediapipe/framework/port:opencv_imgcodecs",
"//mediapipe/util/sequence:media_sequence", "//mediapipe/util/sequence:media_sequence",
"@com_google_absl//absl/container:flat_hash_map", "//mediapipe/util/sequence:media_sequence_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
"@org_tensorflow//tensorflow/core:protos_all_cc", "@org_tensorflow//tensorflow/core:protos_all_cc",
], ],
) )
@@ -1122,6 +1140,7 @@ cc_test(
"//mediapipe/util:packet_test_util", "//mediapipe/util:packet_test_util",
"@org_tensorflow//tensorflow/core:framework", "@org_tensorflow//tensorflow/core:framework",
"@org_tensorflow//tensorflow/core:protos_all_cc", "@org_tensorflow//tensorflow/core:protos_all_cc",
"@org_tensorflow//tensorflow/core/platform:bfloat16",
], ],
) )
@@ -1167,6 +1186,7 @@ cc_test(
"//mediapipe/framework/port:rectangle", "//mediapipe/framework/port:rectangle",
"//mediapipe/util:audio_decoder_cc_proto", "//mediapipe/util:audio_decoder_cc_proto",
"//mediapipe/util/sequence:media_sequence", "//mediapipe/util/sequence:media_sequence",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/core:protos_all_cc", "@org_tensorflow//tensorflow/core:protos_all_cc",
@@ -1248,6 +1268,8 @@ cc_test(
"//mediapipe/framework/tool:sink", "//mediapipe/framework/tool:sink",
"//mediapipe/framework/tool:validate_type", "//mediapipe/framework/tool:validate_type",
"@com_google_absl//absl/flags:flag", "@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
] + select({ ] + select({
"//conditions:default": [ "//conditions:default": [
"@org_tensorflow//tensorflow/core:direct_session", "@org_tensorflow//tensorflow/core:direct_session",
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/tensorflow/matrix_to_tensor_calculator_options.pb.h" #include "mediapipe/calculators/tensorflow/matrix_to_tensor_calculator_options.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/matrix.h" #include "mediapipe/framework/formats/matrix.h"
@@ -28,7 +29,7 @@ namespace mediapipe {
namespace { namespace {
absl::Status FillTimeSeriesHeaderIfValid(const Packet& header_packet, absl::Status FillTimeSeriesHeaderIfValid(const Packet& header_packet,
TimeSeriesHeader* header) { TimeSeriesHeader* header) {
CHECK(header); ABSL_CHECK(header);
if (header_packet.IsEmpty()) { if (header_packet.IsEmpty()) {
return absl::UnknownError("No header found."); return absl::UnknownError("No header found.");
} }
@@ -151,7 +151,7 @@ class ObjectDetectionTensorsToDetectionsCalculator : public CalculatorBase {
tf::Tensor input_num_detections_tensor = tf::Tensor input_num_detections_tensor =
tf::Tensor(tf::DT_FLOAT, tf::TensorShape({0})); tf::Tensor(tf::DT_FLOAT, tf::TensorShape({0}));
if (cc->Inputs().HasTag(kClasses)) { if (cc->Inputs().HasTag(kClasses)) {
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
input_num_detections_tensor, input_num_detections_tensor,
MaybeSqueezeDims(kNumDetections, MaybeSqueezeDims(kNumDetections,
cc->Inputs().Tag(kNumDetections).Get<tf::Tensor>())); cc->Inputs().Tag(kNumDetections).Get<tf::Tensor>()));
@@ -160,12 +160,12 @@ class ObjectDetectionTensorsToDetectionsCalculator : public CalculatorBase {
RET_CHECK_EQ(input_num_detections_tensor.dtype(), tf::DT_FLOAT); RET_CHECK_EQ(input_num_detections_tensor.dtype(), tf::DT_FLOAT);
} }
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
auto input_boxes_tensor, auto input_boxes_tensor,
MaybeSqueezeDims(kBoxes, cc->Inputs().Tag(kBoxes).Get<tf::Tensor>())); MaybeSqueezeDims(kBoxes, cc->Inputs().Tag(kBoxes).Get<tf::Tensor>()));
RET_CHECK_EQ(input_boxes_tensor.dtype(), tf::DT_FLOAT); RET_CHECK_EQ(input_boxes_tensor.dtype(), tf::DT_FLOAT);
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
auto input_scores_tensor, auto input_scores_tensor,
MaybeSqueezeDims(kScores, cc->Inputs().Tag(kScores).Get<tf::Tensor>())); MaybeSqueezeDims(kScores, cc->Inputs().Tag(kScores).Get<tf::Tensor>()));
RET_CHECK_EQ(input_scores_tensor.dtype(), tf::DT_FLOAT); RET_CHECK_EQ(input_scores_tensor.dtype(), tf::DT_FLOAT);
@@ -173,7 +173,7 @@ class ObjectDetectionTensorsToDetectionsCalculator : public CalculatorBase {
tf::Tensor input_classes_tensor = tf::Tensor input_classes_tensor =
tf::Tensor(tf::DT_FLOAT, tf::TensorShape({0})); tf::Tensor(tf::DT_FLOAT, tf::TensorShape({0}));
if (cc->Inputs().HasTag(kClasses)) { if (cc->Inputs().HasTag(kClasses)) {
ASSIGN_OR_RETURN( MP_ASSIGN_OR_RETURN(
input_classes_tensor, input_classes_tensor,
MaybeSqueezeDims(kClasses, MaybeSqueezeDims(kClasses,
cc->Inputs().Tag(kClasses).Get<tf::Tensor>())); cc->Inputs().Tag(kClasses).Get<tf::Tensor>()));
@@ -12,21 +12,23 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <cstdint>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/strings/match.h" #include "absl/strings/match.h"
#include "absl/strings/strip.h"
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h" #include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
#include "mediapipe/calculators/tensorflow/pack_media_sequence_calculator.pb.h" #include "mediapipe/calculators/tensorflow/pack_media_sequence_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/detection.pb.h" #include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/location.h" #include "mediapipe/framework/formats/location.h"
#include "mediapipe/framework/formats/location_opencv.h" #include "mediapipe/framework/formats/location_opencv.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h" #include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
#include "mediapipe/framework/port/ret_check.h" #include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/util/sequence/media_sequence.h" #include "mediapipe/util/sequence/media_sequence.h"
#include "mediapipe/util/sequence/media_sequence_util.h" #include "mediapipe/util/sequence/media_sequence_util.h"
#include "tensorflow/core/example/example.pb.h" #include "tensorflow/core/example/example.pb.h"
@@ -36,7 +38,11 @@ namespace mediapipe {
const char kSequenceExampleTag[] = "SEQUENCE_EXAMPLE"; const char kSequenceExampleTag[] = "SEQUENCE_EXAMPLE";
const char kImageTag[] = "IMAGE"; const char kImageTag[] = "IMAGE";
const char kImageLabelPrefixTag[] = "IMAGE_LABEL_";
const char kClipLabelPrefixTag[] = "CLIP_LABEL_";
const char kFloatContextFeaturePrefixTag[] = "FLOAT_CONTEXT_FEATURE_"; const char kFloatContextFeaturePrefixTag[] = "FLOAT_CONTEXT_FEATURE_";
const char kIntsContextFeaturePrefixTag[] = "INTS_CONTEXT_FEATURE_";
const char kBytesContextFeaturePrefixTag[] = "BYTES_CONTEXT_FEATURE_";
const char kFloatFeaturePrefixTag[] = "FLOAT_FEATURE_"; const char kFloatFeaturePrefixTag[] = "FLOAT_FEATURE_";
const char kIntFeaturePrefixTag[] = "INT_FEATURE_"; const char kIntFeaturePrefixTag[] = "INT_FEATURE_";
const char kBytesFeaturePrefixTag[] = "BYTES_FEATURE_"; const char kBytesFeaturePrefixTag[] = "BYTES_FEATURE_";
@@ -44,6 +50,7 @@ const char kForwardFlowEncodedTag[] = "FORWARD_FLOW_ENCODED";
const char kBBoxTag[] = "BBOX"; const char kBBoxTag[] = "BBOX";
const char kKeypointsTag[] = "KEYPOINTS"; const char kKeypointsTag[] = "KEYPOINTS";
const char kSegmentationMaskTag[] = "CLASS_SEGMENTATION"; const char kSegmentationMaskTag[] = "CLASS_SEGMENTATION";
const char kClipMediaIdTag[] = "CLIP_MEDIA_ID";
namespace tf = ::tensorflow; namespace tf = ::tensorflow;
namespace mpms = mediapipe::mediasequence; namespace mpms = mediapipe::mediasequence;
@@ -55,16 +62,24 @@ namespace mpms = mediapipe::mediasequence;
// context features can be supplied verbatim in the calculator's options. The // context features can be supplied verbatim in the calculator's options. The
// SequenceExample will conform to the description in media_sequence.h. // SequenceExample will conform to the description in media_sequence.h.
// //
// The supported input stream tags are "IMAGE", which stores the encoded // The supported input stream tags are:
// images from the OpenCVImageEncoderCalculator, "FORWARD_FLOW_ENCODED", which // * "IMAGE", which stores the encoded images from the
// stores the encoded optical flow from the same calculator, "BBOX" which stores // OpenCVImageEncoderCalculator,
// bounding boxes from vector<Detections>, and streams with the // * "IMAGE_LABEL", which stores whole image labels from Detection,
// "FLOAT_FEATURE_${NAME}" pattern, which stores the values from vector<float>'s // * "FORWARD_FLOW_ENCODED", which stores the encoded optical flow from the same
// associated with the name ${NAME}. "KEYPOINTS" stores a map of 2D keypoints // calculator,
// from flat_hash_map<string, vector<pair<float, float>>>. "IMAGE_${NAME}", // * "BBOX" which stores bounding boxes from vector<Detections>,
// "BBOX_${NAME}", and "KEYPOINTS_${NAME}" will also store prefixed versions of // * streams with the "FLOAT_FEATURE_${NAME}" pattern, which stores the values
// each stream, which allows for multiple image streams to be included. However, // from vector<float>'s associated with the name ${NAME},
// the default names are suppored by more tools. // * "KEYPOINTS" stores a map of 2D keypoints from flat_hash_map<string,
// vector<pair<float, float>>>,
// * "CLIP_MEDIA_ID", which stores the clip's media ID as a string.
// * "CLIP_LABEL_${NAME}" which stores sparse feature labels, ID and scores in
// mediapipe::Detection. In the input Detection, the score field is required,
// and label and label_id are optional but at least one of them should be set.
// "IMAGE_${NAME}", "BBOX_${NAME}", and "KEYPOINTS_${NAME}" will also store
// prefixed versions of each stream, which allows for multiple image streams to
// be included. However, the default names are suppored by more tools.
// //
// Example config: // Example config:
// node { // node {
@@ -100,6 +115,9 @@ class PackMediaSequenceCalculator : public CalculatorBase {
static absl::Status GetContract(CalculatorContract* cc) { static absl::Status GetContract(CalculatorContract* cc) {
RET_CHECK(cc->InputSidePackets().HasTag(kSequenceExampleTag)); RET_CHECK(cc->InputSidePackets().HasTag(kSequenceExampleTag));
cc->InputSidePackets().Tag(kSequenceExampleTag).Set<tf::SequenceExample>(); cc->InputSidePackets().Tag(kSequenceExampleTag).Set<tf::SequenceExample>();
if (cc->InputSidePackets().HasTag(kClipMediaIdTag)) {
cc->InputSidePackets().Tag(kClipMediaIdTag).Set<std::string>();
}
if (cc->Inputs().HasTag(kForwardFlowEncodedTag)) { if (cc->Inputs().HasTag(kForwardFlowEncodedTag)) {
cc->Inputs() cc->Inputs()
@@ -112,6 +130,10 @@ class PackMediaSequenceCalculator : public CalculatorBase {
for (const auto& tag : cc->Inputs().GetTags()) { for (const auto& tag : cc->Inputs().GetTags()) {
if (absl::StartsWith(tag, kImageTag)) { if (absl::StartsWith(tag, kImageTag)) {
if (absl::StartsWith(tag, kImageLabelPrefixTag)) {
cc->Inputs().Tag(tag).Set<Detection>();
continue;
}
std::string key = ""; std::string key = "";
if (tag != kImageTag) { if (tag != kImageTag) {
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1; int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
@@ -150,9 +172,18 @@ class PackMediaSequenceCalculator : public CalculatorBase {
} }
cc->Inputs().Tag(tag).Set<std::vector<Detection>>(); cc->Inputs().Tag(tag).Set<std::vector<Detection>>();
} }
if (absl::StartsWith(tag, kClipLabelPrefixTag)) {
cc->Inputs().Tag(tag).Set<Detection>();
}
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag)) { if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag)) {
cc->Inputs().Tag(tag).Set<std::vector<float>>(); cc->Inputs().Tag(tag).Set<std::vector<float>>();
} }
if (absl::StartsWith(tag, kIntsContextFeaturePrefixTag)) {
cc->Inputs().Tag(tag).Set<std::vector<int64_t>>();
}
if (absl::StartsWith(tag, kBytesContextFeaturePrefixTag)) {
cc->Inputs().Tag(tag).Set<std::vector<std::string>>();
}
if (absl::StartsWith(tag, kFloatFeaturePrefixTag)) { if (absl::StartsWith(tag, kFloatFeaturePrefixTag)) {
cc->Inputs().Tag(tag).Set<std::vector<float>>(); cc->Inputs().Tag(tag).Set<std::vector<float>>();
} }
@@ -184,6 +215,11 @@ class PackMediaSequenceCalculator : public CalculatorBase {
cc->InputSidePackets() cc->InputSidePackets()
.Tag(kSequenceExampleTag) .Tag(kSequenceExampleTag)
.Get<tf::SequenceExample>()); .Get<tf::SequenceExample>());
if (cc->InputSidePackets().HasTag(kClipMediaIdTag) &&
!cc->InputSidePackets().Tag(kClipMediaIdTag).IsEmpty()) {
clip_media_id_ =
cc->InputSidePackets().Tag(kClipMediaIdTag).Get<std::string>();
}
const auto& context_features = const auto& context_features =
cc->Options<PackMediaSequenceCalculatorOptions>().context_feature_map(); cc->Options<PackMediaSequenceCalculatorOptions>().context_feature_map();
@@ -197,8 +233,19 @@ class PackMediaSequenceCalculator : public CalculatorBase {
replace_keypoints_ = false; replace_keypoints_ = false;
if (cc->Options<PackMediaSequenceCalculatorOptions>() if (cc->Options<PackMediaSequenceCalculatorOptions>()
.replace_data_instead_of_append()) { .replace_data_instead_of_append()) {
// Clear the existing values under the same key.
for (const auto& tag : cc->Inputs().GetTags()) { for (const auto& tag : cc->Inputs().GetTags()) {
if (absl::StartsWith(tag, kImageTag)) { if (absl::StartsWith(tag, kImageTag)) {
if (absl::StartsWith(tag, kImageLabelPrefixTag)) {
std::string key =
std::string(absl::StripPrefix(tag, kImageLabelPrefixTag));
mpms::ClearImageLabelString(key, sequence_.get());
mpms::ClearImageLabelConfidence(key, sequence_.get());
if (!key.empty() || mpms::HasImageEncoded(*sequence_)) {
mpms::ClearImageTimestamp(key, sequence_.get());
}
continue;
}
std::string key = ""; std::string key = "";
if (tag != kImageTag) { if (tag != kImageTag) {
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1; int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
@@ -227,12 +274,41 @@ class PackMediaSequenceCalculator : public CalculatorBase {
mpms::ClearBBoxNumRegions(key, sequence_.get()); mpms::ClearBBoxNumRegions(key, sequence_.get());
mpms::ClearBBoxLabelString(key, sequence_.get()); mpms::ClearBBoxLabelString(key, sequence_.get());
mpms::ClearBBoxLabelIndex(key, sequence_.get()); mpms::ClearBBoxLabelIndex(key, sequence_.get());
mpms::ClearBBoxLabelConfidence(key, sequence_.get());
mpms::ClearBBoxClassString(key, sequence_.get()); mpms::ClearBBoxClassString(key, sequence_.get());
mpms::ClearBBoxClassIndex(key, sequence_.get()); mpms::ClearBBoxClassIndex(key, sequence_.get());
mpms::ClearBBoxTrackString(key, sequence_.get()); mpms::ClearBBoxTrackString(key, sequence_.get());
mpms::ClearBBoxTrackIndex(key, sequence_.get()); mpms::ClearBBoxTrackIndex(key, sequence_.get());
mpms::ClearUnmodifiedBBoxTimestamp(key, sequence_.get()); mpms::ClearUnmodifiedBBoxTimestamp(key, sequence_.get());
} }
if (absl::StartsWith(tag, kClipLabelPrefixTag)) {
const std::string& key = tag.substr(
sizeof(kClipLabelPrefixTag) / sizeof(*kClipLabelPrefixTag) - 1);
mpms::ClearClipLabelIndex(key, sequence_.get());
mpms::ClearClipLabelString(key, sequence_.get());
mpms::ClearClipLabelConfidence(key, sequence_.get());
}
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag)) {
const std::string& key =
tag.substr(sizeof(kFloatContextFeaturePrefixTag) /
sizeof(*kFloatContextFeaturePrefixTag) -
1);
mpms::ClearContextFeatureFloats(key, sequence_.get());
}
if (absl::StartsWith(tag, kIntsContextFeaturePrefixTag)) {
const std::string& key =
tag.substr(sizeof(kIntsContextFeaturePrefixTag) /
sizeof(*kIntsContextFeaturePrefixTag) -
1);
mpms::ClearContextFeatureInts(key, sequence_.get());
}
if (absl::StartsWith(tag, kBytesContextFeaturePrefixTag)) {
const std::string& key =
tag.substr(sizeof(kBytesContextFeaturePrefixTag) /
sizeof(*kBytesContextFeaturePrefixTag) -
1);
mpms::ClearContextFeatureBytes(key, sequence_.get());
}
if (absl::StartsWith(tag, kFloatFeaturePrefixTag)) { if (absl::StartsWith(tag, kFloatFeaturePrefixTag)) {
std::string key = tag.substr(sizeof(kFloatFeaturePrefixTag) / std::string key = tag.substr(sizeof(kFloatFeaturePrefixTag) /
sizeof(*kFloatFeaturePrefixTag) - sizeof(*kFloatFeaturePrefixTag) -
@@ -343,6 +419,34 @@ class PackMediaSequenceCalculator : public CalculatorBase {
if (absl::StartsWith(tag, kImageTag) && if (absl::StartsWith(tag, kImageTag) &&
!cc->Inputs().Tag(tag).IsEmpty()) { !cc->Inputs().Tag(tag).IsEmpty()) {
std::string key = ""; std::string key = "";
if (absl::StartsWith(tag, kImageLabelPrefixTag)) {
std::string key =
std::string(absl::StripPrefix(tag, kImageLabelPrefixTag));
const auto& detection = cc->Inputs().Tag(tag).Get<Detection>();
if (detection.label().empty()) continue;
RET_CHECK(detection.label_size() == detection.score_size())
<< "Wrong image label data format: " << detection.label_size()
<< " vs " << detection.score_size();
if (!detection.label_id().empty()) {
RET_CHECK(detection.label_id_size() == detection.label_size())
<< "Wrong image label ID format: " << detection.label_id_size()
<< " vs " << detection.label_size();
}
std::vector<std::string> labels(detection.label().begin(),
detection.label().end());
std::vector<float> confidences(detection.score().begin(),
detection.score().end());
std::vector<int32_t> ids(detection.label_id().begin(),
detection.label_id().end());
if (!key.empty() || mpms::HasImageEncoded(*sequence_)) {
mpms::AddImageTimestamp(key, cc->InputTimestamp().Value(),
sequence_.get());
}
mpms::AddImageLabelString(key, labels, sequence_.get());
mpms::AddImageLabelConfidence(key, confidences, sequence_.get());
if (!ids.empty()) mpms::AddImageLabelIndex(key, ids, sequence_.get());
continue;
}
if (tag != kImageTag) { if (tag != kImageTag) {
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1; int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
if (tag[tag_length] == '_') { if (tag[tag_length] == '_') {
@@ -393,6 +497,7 @@ class PackMediaSequenceCalculator : public CalculatorBase {
mpms::ClearBBoxNumRegions(prefix, sequence_.get()); mpms::ClearBBoxNumRegions(prefix, sequence_.get());
mpms::ClearBBoxLabelString(prefix, sequence_.get()); mpms::ClearBBoxLabelString(prefix, sequence_.get());
mpms::ClearBBoxLabelIndex(prefix, sequence_.get()); mpms::ClearBBoxLabelIndex(prefix, sequence_.get());
mpms::ClearBBoxLabelConfidence(prefix, sequence_.get());
mpms::ClearBBoxClassString(prefix, sequence_.get()); mpms::ClearBBoxClassString(prefix, sequence_.get());
mpms::ClearBBoxClassIndex(prefix, sequence_.get()); mpms::ClearBBoxClassIndex(prefix, sequence_.get());
mpms::ClearBBoxTrackString(prefix, sequence_.get()); mpms::ClearBBoxTrackString(prefix, sequence_.get());
@@ -405,6 +510,46 @@ class PackMediaSequenceCalculator : public CalculatorBase {
} }
replace_keypoints_ = false; replace_keypoints_ = false;
} }
if (absl::StartsWith(tag, kClipLabelPrefixTag) &&
!cc->Inputs().Tag(tag).IsEmpty()) {
const std::string& key = tag.substr(
sizeof(kClipLabelPrefixTag) / sizeof(*kClipLabelPrefixTag) - 1);
const Detection& detection = cc->Inputs().Tag(tag).Get<Detection>();
if (detection.score().empty()) {
continue;
}
if (detection.label().empty() && detection.label_id().empty()) {
return absl::InvalidArgumentError(
"detection.label and detection.label_id can't be both empty");
}
// Allow empty label (for indexed feature inputs), but if label is not
// empty, it should have the same size as the score field.
if (!detection.label().empty()) {
if (detection.label().size() != detection.score().size()) {
return absl::InvalidArgumentError(
"Different size of detection.label and detection.score");
}
}
// Allow empty label_ids, but if label_ids is not empty, it should have
// the same size as the score field.
if (!detection.label_id().empty()) {
if (detection.label_id().size() != detection.score().size()) {
return absl::InvalidArgumentError(
"Different size of detection.label_id and detection.score");
}
}
for (int i = 0; i < detection.score().size(); ++i) {
if (!detection.label_id().empty()) {
mpms::AddClipLabelIndex(key, detection.label_id(i),
sequence_.get());
}
if (!detection.label().empty()) {
mpms::AddClipLabelString(key, detection.label(i), sequence_.get());
}
mpms::AddClipLabelConfidence(key, detection.score(i),
sequence_.get());
}
}
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag) && if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag) &&
!cc->Inputs().Tag(tag).IsEmpty()) { !cc->Inputs().Tag(tag).IsEmpty()) {
std::string key = std::string key =
@@ -412,9 +557,36 @@ class PackMediaSequenceCalculator : public CalculatorBase {
sizeof(*kFloatContextFeaturePrefixTag) - sizeof(*kFloatContextFeaturePrefixTag) -
1); 1);
RET_CHECK_EQ(cc->InputTimestamp(), Timestamp::PostStream()); RET_CHECK_EQ(cc->InputTimestamp(), Timestamp::PostStream());
mpms::SetContextFeatureFloats( for (const auto& value :
key, cc->Inputs().Tag(tag).Get<std::vector<float>>(), cc->Inputs().Tag(tag).Get<std::vector<float>>()) {
sequence_.get()); mpms::AddContextFeatureFloats(key, value, sequence_.get());
}
}
if (absl::StartsWith(tag, kIntsContextFeaturePrefixTag) &&
!cc->Inputs().Tag(tag).IsEmpty()) {
const std::string& key =
tag.substr(sizeof(kIntsContextFeaturePrefixTag) /
sizeof(*kIntsContextFeaturePrefixTag) -
1);
// To ensure only one packet is provided for this tag.
RET_CHECK_EQ(cc->InputTimestamp(), Timestamp::PostStream());
for (const auto& value :
cc->Inputs().Tag(tag).Get<std::vector<int64_t>>()) {
mpms::AddContextFeatureInts(key, value, sequence_.get());
}
}
if (absl::StartsWith(tag, kBytesContextFeaturePrefixTag) &&
!cc->Inputs().Tag(tag).IsEmpty()) {
const std::string& key =
tag.substr(sizeof(kBytesContextFeaturePrefixTag) /
sizeof(*kBytesContextFeaturePrefixTag) -
1);
// To ensure only one packet is provided for this tag.
RET_CHECK_EQ(cc->InputTimestamp(), Timestamp::PostStream());
for (const auto& value :
cc->Inputs().Tag(tag).Get<std::vector<std::string>>()) {
mpms::AddContextFeatureBytes(key, value, sequence_.get());
}
} }
if (absl::StartsWith(tag, kFloatFeaturePrefixTag) && if (absl::StartsWith(tag, kFloatFeaturePrefixTag) &&
!cc->Inputs().Tag(tag).IsEmpty()) { !cc->Inputs().Tag(tag).IsEmpty()) {
@@ -460,6 +632,7 @@ class PackMediaSequenceCalculator : public CalculatorBase {
} }
std::vector<Location> predicted_locations; std::vector<Location> predicted_locations;
std::vector<std::string> predicted_class_strings; std::vector<std::string> predicted_class_strings;
std::vector<float> predicted_class_confidences;
std::vector<int> predicted_label_ids; std::vector<int> predicted_label_ids;
for (auto& detection : for (auto& detection :
cc->Inputs().Tag(tag).Get<std::vector<Detection>>()) { cc->Inputs().Tag(tag).Get<std::vector<Detection>>()) {
@@ -488,6 +661,9 @@ class PackMediaSequenceCalculator : public CalculatorBase {
if (detection.label_id_size() > 0) { if (detection.label_id_size() > 0) {
predicted_label_ids.push_back(detection.label_id(0)); predicted_label_ids.push_back(detection.label_id(0));
} }
if (detection.score_size() > 0) {
predicted_class_confidences.push_back(detection.score(0));
}
} }
} }
if (!predicted_locations.empty()) { if (!predicted_locations.empty()) {
@@ -501,6 +677,10 @@ class PackMediaSequenceCalculator : public CalculatorBase {
if (!predicted_label_ids.empty()) { if (!predicted_label_ids.empty()) {
mpms::AddBBoxLabelIndex(key, predicted_label_ids, sequence_.get()); mpms::AddBBoxLabelIndex(key, predicted_label_ids, sequence_.get());
} }
if (!predicted_class_confidences.empty()) {
mpms::AddBBoxLabelConfidence(key, predicted_class_confidences,
sequence_.get());
}
} }
} }
} }
@@ -548,10 +728,14 @@ class PackMediaSequenceCalculator : public CalculatorBase {
} }
} }
} }
if (clip_media_id_.has_value()) {
mpms::SetClipMediaId(*clip_media_id_, sequence_.get());
}
return absl::OkStatus(); return absl::OkStatus();
} }
std::unique_ptr<tf::SequenceExample> sequence_; std::unique_ptr<tf::SequenceExample> sequence_;
std::optional<std::string> clip_media_id_ = std::nullopt;
std::map<std::string, bool> features_present_; std::map<std::string, bool> features_present_;
bool replace_keypoints_; bool replace_keypoints_;
}; };
@@ -12,27 +12,32 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <algorithm> #include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "absl/container/flat_hash_map.h" #include "absl/log/absl_check.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/strings/numbers.h" #include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h" #include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
#include "mediapipe/calculators/tensorflow/pack_media_sequence_calculator.pb.h" #include "mediapipe/calculators/tensorflow/pack_media_sequence_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h" #include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/formats/detection.pb.h" #include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/location.h" #include "mediapipe/framework/formats/location.h"
#include "mediapipe/framework/formats/location_opencv.h" #include "mediapipe/framework/formats/location_opencv.h"
#include "mediapipe/framework/port/gmock.h" #include "mediapipe/framework/packet.h"
#include "mediapipe/framework/port/gtest.h"
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h" #include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
#include "mediapipe/framework/port/status_matchers.h" #include "mediapipe/framework/port/status_matchers.h"
#include "mediapipe/framework/timestamp.h" #include "mediapipe/framework/timestamp.h"
#include "mediapipe/util/sequence/media_sequence.h" #include "mediapipe/util/sequence/media_sequence.h"
#include "mediapipe/util/sequence/media_sequence_util.h"
#include "tensorflow/core/example/example.pb.h" #include "tensorflow/core/example/example.pb.h"
#include "tensorflow/core/example/feature.pb.h" #include "tensorflow/core/example/feature.pb.h"
#include "testing/base/public/gmock.h"
#include "testing/base/public/gunit.h"
namespace mediapipe { namespace mediapipe {
namespace { namespace {
@@ -54,13 +59,23 @@ constexpr char kBytesFeatureTestTag[] = "BYTES_FEATURE_TEST";
constexpr char kForwardFlowEncodedTag[] = "FORWARD_FLOW_ENCODED"; constexpr char kForwardFlowEncodedTag[] = "FORWARD_FLOW_ENCODED";
constexpr char kFloatContextFeatureOtherTag[] = "FLOAT_CONTEXT_FEATURE_OTHER"; constexpr char kFloatContextFeatureOtherTag[] = "FLOAT_CONTEXT_FEATURE_OTHER";
constexpr char kFloatContextFeatureTestTag[] = "FLOAT_CONTEXT_FEATURE_TEST"; constexpr char kFloatContextFeatureTestTag[] = "FLOAT_CONTEXT_FEATURE_TEST";
constexpr char kIntsContextFeatureTestTag[] = "INTS_CONTEXT_FEATURE_TEST";
constexpr char kIntsContextFeatureOtherTag[] = "INTS_CONTEXT_FEATURE_OTHER";
constexpr char kBytesContextFeatureTestTag[] = "BYTES_CONTEXT_FEATURE_TEST";
constexpr char kBytesContextFeatureOtherTag[] = "BYTES_CONTEXT_FEATURE_OTHER";
constexpr char kFloatFeatureOtherTag[] = "FLOAT_FEATURE_OTHER"; constexpr char kFloatFeatureOtherTag[] = "FLOAT_FEATURE_OTHER";
constexpr char kFloatFeatureTestTag[] = "FLOAT_FEATURE_TEST"; constexpr char kFloatFeatureTestTag[] = "FLOAT_FEATURE_TEST";
constexpr char kIntFeatureOtherTag[] = "INT_FEATURE_OTHER"; constexpr char kIntFeatureOtherTag[] = "INT_FEATURE_OTHER";
constexpr char kIntFeatureTestTag[] = "INT_FEATURE_TEST"; constexpr char kIntFeatureTestTag[] = "INT_FEATURE_TEST";
constexpr char kImageLabelTestTag[] = "IMAGE_LABEL_TEST";
constexpr char kImageLabelOtherTag[] = "IMAGE_LABEL_OTHER";
constexpr char kImagePrefixTag[] = "IMAGE_PREFIX"; constexpr char kImagePrefixTag[] = "IMAGE_PREFIX";
constexpr char kSequenceExampleTag[] = "SEQUENCE_EXAMPLE"; constexpr char kSequenceExampleTag[] = "SEQUENCE_EXAMPLE";
constexpr char kImageTag[] = "IMAGE"; constexpr char kImageTag[] = "IMAGE";
constexpr char kClipMediaIdTag[] = "CLIP_MEDIA_ID";
constexpr char kClipLabelTestTag[] = "CLIP_LABEL_TEST";
constexpr char kClipLabelOtherTag[] = "CLIP_LABEL_OTHER";
constexpr char kClipLabelAnotherTag[] = "CLIP_LABEL_ANOTHER";
class PackMediaSequenceCalculatorTest : public ::testing::Test { class PackMediaSequenceCalculatorTest : public ::testing::Test {
protected: protected:
@@ -68,10 +83,14 @@ class PackMediaSequenceCalculatorTest : public ::testing::Test {
const tf::Features& features, const tf::Features& features,
const bool output_only_if_all_present, const bool output_only_if_all_present,
const bool replace_instead_of_append, const bool replace_instead_of_append,
const bool output_as_zero_timestamp = false) { const bool output_as_zero_timestamp = false,
const std::vector<std::string>& input_side_packets = {
"SEQUENCE_EXAMPLE:input_sequence"}) {
CalculatorGraphConfig::Node config; CalculatorGraphConfig::Node config;
config.set_calculator("PackMediaSequenceCalculator"); config.set_calculator("PackMediaSequenceCalculator");
config.add_input_side_packet("SEQUENCE_EXAMPLE:input_sequence"); for (const std::string& side_packet : input_side_packets) {
config.add_input_side_packet(side_packet);
}
config.add_output_stream("SEQUENCE_EXAMPLE:output_sequence"); config.add_output_stream("SEQUENCE_EXAMPLE:output_sequence");
for (const std::string& stream : input_streams) { for (const std::string& stream : input_streams) {
config.add_input_stream(stream); config.add_input_stream(stream);
@@ -313,6 +332,76 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoBytesLists) {
} }
} }
TEST_F(PackMediaSequenceCalculatorTest, PacksTwoImageLabels) {
SetUpCalculator(
{"IMAGE_LABEL_TEST:test_labels", "IMAGE_LABEL_OTHER:test_labels2"}, {},
false, true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
int num_timesteps = 2;
for (int i = 0; i < num_timesteps; ++i) {
Detection detection1;
detection1.add_label(absl::StrCat("foo", 2 << i));
detection1.add_label_id(i);
detection1.add_score(0.1 * i);
detection1.add_label(absl::StrCat("foo", 2 << i));
detection1.add_label_id(i);
detection1.add_score(0.1 * i);
auto label_ptr1 = ::absl::make_unique<Detection>(detection1);
runner_->MutableInputs()
->Tag(kImageLabelTestTag)
.packets.push_back(Adopt(label_ptr1.release()).At(Timestamp(i)));
Detection detection2;
detection2.add_label(absl::StrCat("bar", 2 << i));
detection2.add_score(0.2 * i);
detection2.add_label(absl::StrCat("bar", 2 << i));
detection2.add_score(0.2 * i);
auto label_ptr2 = ::absl::make_unique<Detection>(detection2);
runner_->MutableInputs()
->Tag(kImageLabelOtherTag)
.packets.push_back(Adopt(label_ptr2.release()).At(Timestamp(i)));
}
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_EQ(num_timesteps,
mpms::GetImageTimestampSize("TEST", output_sequence));
ASSERT_EQ(num_timesteps,
mpms::GetImageLabelStringSize("TEST", output_sequence));
ASSERT_EQ(num_timesteps,
mpms::GetImageLabelConfidenceSize("TEST", output_sequence));
ASSERT_EQ(num_timesteps,
mpms::GetImageTimestampSize("OTHER", output_sequence));
ASSERT_EQ(num_timesteps,
mpms::GetImageLabelStringSize("OTHER", output_sequence));
ASSERT_EQ(num_timesteps,
mpms::GetImageLabelConfidenceSize("OTHER", output_sequence));
for (int i = 0; i < num_timesteps; ++i) {
ASSERT_EQ(i, mpms::GetImageTimestampAt("TEST", output_sequence, i));
ASSERT_THAT(mpms::GetImageLabelStringAt("TEST", output_sequence, i),
::testing::ElementsAreArray(
std::vector<std::string>(2, absl::StrCat("foo", 2 << i))));
ASSERT_THAT(mpms::GetImageLabelIndexAt("TEST", output_sequence, i),
::testing::ElementsAreArray(std::vector<int32_t>(2, i)));
ASSERT_THAT(mpms::GetImageLabelConfidenceAt("TEST", output_sequence, i),
::testing::ElementsAreArray(std::vector<float>(2, 0.1 * i)));
ASSERT_EQ(i, mpms::GetImageTimestampAt("OTHER", output_sequence, i));
ASSERT_THAT(mpms::GetImageLabelStringAt("OTHER", output_sequence, i),
::testing::ElementsAreArray(
std::vector<std::string>(2, absl::StrCat("bar", 2 << i))));
ASSERT_THAT(mpms::GetImageLabelConfidenceAt("OTHER", output_sequence, i),
::testing::ElementsAreArray(std::vector<float>(2, 0.2 * i)));
}
}
TEST_F(PackMediaSequenceCalculatorTest, OutputAsZeroTimestamp) { TEST_F(PackMediaSequenceCalculatorTest, OutputAsZeroTimestamp) {
SetUpCalculator({"FLOAT_FEATURE_TEST:test"}, {}, false, true, true); SetUpCalculator({"FLOAT_FEATURE_TEST:test"}, {}, false, true, true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>(); auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
@@ -368,6 +457,315 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoContextFloatLists) {
testing::ElementsAre(4, 4)); testing::ElementsAre(4, 4));
} }
TEST_F(PackMediaSequenceCalculatorTest, ReplaceTwoContextFloatLists) {
SetUpCalculator(
/*input_streams=*/{"FLOAT_CONTEXT_FEATURE_TEST:test",
"FLOAT_CONTEXT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
auto input_sequence = std::make_unique<tf::SequenceExample>();
mpms::SetContextFeatureFloats("TEST", {2, 3}, input_sequence.get());
mpms::SetContextFeatureFloats("OTHER", {2, 4}, input_sequence.get());
const std::vector<float> vf_1 = {5, 6};
runner_->MutableInputs()
->Tag(kFloatContextFeatureTestTag)
.packets.push_back(
MakePacket<std::vector<float>>(vf_1).At(Timestamp::PostStream()));
const std::vector<float> vf_2 = {7, 8};
runner_->MutableInputs()
->Tag(kFloatContextFeatureOtherTag)
.packets.push_back(
MakePacket<std::vector<float>>(vf_2).At(Timestamp::PostStream()));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(mpms::GetContextFeatureFloats("TEST", output_sequence),
testing::ElementsAre(5, 6));
ASSERT_THAT(mpms::GetContextFeatureFloats("OTHER", output_sequence),
testing::ElementsAre(7, 8));
}
TEST_F(PackMediaSequenceCalculatorTest, AppendTwoContextFloatLists) {
SetUpCalculator(
/*input_streams=*/{"FLOAT_CONTEXT_FEATURE_TEST:test",
"FLOAT_CONTEXT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/false);
auto input_sequence = std::make_unique<tf::SequenceExample>();
mpms::SetContextFeatureFloats("TEST", {2, 3}, input_sequence.get());
mpms::SetContextFeatureFloats("OTHER", {2, 4}, input_sequence.get());
const std::vector<float> vf_1 = {5, 6};
runner_->MutableInputs()
->Tag(kFloatContextFeatureTestTag)
.packets.push_back(
MakePacket<std::vector<float>>(vf_1).At(Timestamp::PostStream()));
const std::vector<float> vf_2 = {7, 8};
runner_->MutableInputs()
->Tag(kFloatContextFeatureOtherTag)
.packets.push_back(
MakePacket<std::vector<float>>(vf_2).At(Timestamp::PostStream()));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
EXPECT_THAT(mpms::GetContextFeatureFloats("TEST", output_sequence),
testing::ElementsAre(2, 3, 5, 6));
EXPECT_THAT(mpms::GetContextFeatureFloats("OTHER", output_sequence),
testing::ElementsAre(2, 4, 7, 8));
}
TEST_F(PackMediaSequenceCalculatorTest, PackTwoContextIntLists) {
SetUpCalculator(
/*input_streams=*/{"INTS_CONTEXT_FEATURE_TEST:test",
"INTS_CONTEXT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
auto input_sequence = absl::make_unique<tf::SequenceExample>();
const std::vector<int64_t> vi_1 = {2, 3};
runner_->MutableInputs()
->Tag(kIntsContextFeatureTestTag)
.packets.push_back(
MakePacket<std::vector<int64_t>>(vi_1).At(Timestamp::PostStream()));
const std::vector<int64_t> vi_2 = {2, 4};
runner_->MutableInputs()
->Tag(kIntsContextFeatureOtherTag)
.packets.push_back(
MakePacket<std::vector<int64_t>>(vi_2).At(Timestamp::PostStream()));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(mpms::GetContextFeatureInts("TEST", output_sequence),
testing::ElementsAre(2, 3));
ASSERT_THAT(mpms::GetContextFeatureInts("OTHER", output_sequence),
testing::ElementsAre(2, 4));
}
TEST_F(PackMediaSequenceCalculatorTest, ReplaceTwoContextIntLists) {
SetUpCalculator(
/*input_streams=*/{"INTS_CONTEXT_FEATURE_TEST:test",
"INTS_CONTEXT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
auto input_sequence = absl::make_unique<tf::SequenceExample>();
mpms::SetContextFeatureInts("TEST", {2, 3}, input_sequence.get());
mpms::SetContextFeatureInts("OTHER", {2, 4}, input_sequence.get());
const std::vector<int64_t> vi_1 = {5, 6};
runner_->MutableInputs()
->Tag(kIntsContextFeatureTestTag)
.packets.push_back(
MakePacket<std::vector<int64_t>>(vi_1).At(Timestamp::PostStream()));
const std::vector<int64_t> vi_2 = {7, 8};
runner_->MutableInputs()
->Tag(kIntsContextFeatureOtherTag)
.packets.push_back(
MakePacket<std::vector<int64_t>>(vi_2).At(Timestamp::PostStream()));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(mpms::GetContextFeatureInts("TEST", output_sequence),
testing::ElementsAre(5, 6));
ASSERT_THAT(mpms::GetContextFeatureInts("OTHER", output_sequence),
testing::ElementsAre(7, 8));
}
TEST_F(PackMediaSequenceCalculatorTest, AppendTwoContextIntLists) {
SetUpCalculator(
/*input_streams=*/{"INTS_CONTEXT_FEATURE_TEST:test",
"INTS_CONTEXT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/false);
auto input_sequence = absl::make_unique<tf::SequenceExample>();
mpms::SetContextFeatureInts("TEST", {2, 3}, input_sequence.get());
mpms::SetContextFeatureInts("OTHER", {2, 4}, input_sequence.get());
const std::vector<int64_t> vi_1 = {5, 6};
runner_->MutableInputs()
->Tag(kIntsContextFeatureTestTag)
.packets.push_back(
MakePacket<std::vector<int64_t>>(vi_1).At(Timestamp::PostStream()));
const std::vector<int64_t> vi_2 = {7, 8};
runner_->MutableInputs()
->Tag(kIntsContextFeatureOtherTag)
.packets.push_back(
MakePacket<std::vector<int64_t>>(vi_2).At(Timestamp::PostStream()));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(mpms::GetContextFeatureInts("TEST", output_sequence),
testing::ElementsAre(2, 3, 5, 6));
ASSERT_THAT(mpms::GetContextFeatureInts("OTHER", output_sequence),
testing::ElementsAre(2, 4, 7, 8));
}
TEST_F(PackMediaSequenceCalculatorTest, PackTwoContextByteLists) {
SetUpCalculator(
/*input_streams=*/{"BYTES_CONTEXT_FEATURE_TEST:test",
"BYTES_CONTEXT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
auto input_sequence = absl::make_unique<tf::SequenceExample>();
const std::vector<std::string> vb_1 = {"value_1", "value_2"};
runner_->MutableInputs()
->Tag(kBytesContextFeatureTestTag)
.packets.push_back(MakePacket<std::vector<std::string>>(vb_1).At(
Timestamp::PostStream()));
const std::vector<std::string> vb_2 = {"value_3", "value_4"};
runner_->MutableInputs()
->Tag(kBytesContextFeatureOtherTag)
.packets.push_back(MakePacket<std::vector<std::string>>(vb_2).At(
Timestamp::PostStream()));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(mpms::GetContextFeatureBytes("TEST", output_sequence),
testing::ElementsAre("value_1", "value_2"));
ASSERT_THAT(mpms::GetContextFeatureBytes("OTHER", output_sequence),
testing::ElementsAre("value_3", "value_4"));
}
TEST_F(PackMediaSequenceCalculatorTest, ReplaceTwoContextByteLists) {
SetUpCalculator(
/*input_streams=*/{"BYTES_CONTEXT_FEATURE_TEST:test",
"BYTES_CONTEXT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
auto input_sequence = absl::make_unique<tf::SequenceExample>();
mpms::SetContextFeatureBytes("TEST", {"existing_value_1", "existing_value_2"},
input_sequence.get());
mpms::SetContextFeatureBytes(
"OTHER", {"existing_value_3", "existing_value_4"}, input_sequence.get());
const std::vector<std::string> vb_1 = {"value_1", "value_2"};
runner_->MutableInputs()
->Tag(kBytesContextFeatureTestTag)
.packets.push_back(MakePacket<std::vector<std::string>>(vb_1).At(
Timestamp::PostStream()));
const std::vector<std::string> vb_2 = {"value_3", "value_4"};
runner_->MutableInputs()
->Tag(kBytesContextFeatureOtherTag)
.packets.push_back(MakePacket<std::vector<std::string>>(vb_2).At(
Timestamp::PostStream()));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(mpms::GetContextFeatureBytes("TEST", output_sequence),
testing::ElementsAre("value_1", "value_2"));
ASSERT_THAT(mpms::GetContextFeatureBytes("OTHER", output_sequence),
testing::ElementsAre("value_3", "value_4"));
}
TEST_F(PackMediaSequenceCalculatorTest, AppendTwoContextByteLists) {
SetUpCalculator(
/*input_streams=*/{"BYTES_CONTEXT_FEATURE_TEST:test",
"BYTES_CONTEXT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/false);
auto input_sequence = absl::make_unique<tf::SequenceExample>();
mpms::SetContextFeatureBytes("TEST", {"existing_value_1", "existing_value_2"},
input_sequence.get());
mpms::SetContextFeatureBytes(
"OTHER", {"existing_value_3", "existing_value_4"}, input_sequence.get());
const std::vector<std::string> vb_1 = {"value_1", "value_2"};
runner_->MutableInputs()
->Tag(kBytesContextFeatureTestTag)
.packets.push_back(MakePacket<std::vector<std::string>>(vb_1).At(
Timestamp::PostStream()));
const std::vector<std::string> vb_2 = {"value_3", "value_4"};
runner_->MutableInputs()
->Tag(kBytesContextFeatureOtherTag)
.packets.push_back(MakePacket<std::vector<std::string>>(vb_2).At(
Timestamp::PostStream()));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(mpms::GetContextFeatureBytes("TEST", output_sequence),
testing::ElementsAre("existing_value_1", "existing_value_2",
"value_1", "value_2"));
ASSERT_THAT(mpms::GetContextFeatureBytes("OTHER", output_sequence),
testing::ElementsAre("existing_value_3", "existing_value_4",
"value_3", "value_4"));
}
TEST_F(PackMediaSequenceCalculatorTest, PacksAdditionalContext) { TEST_F(PackMediaSequenceCalculatorTest, PacksAdditionalContext) {
tf::Features context; tf::Features context;
(*context.mutable_feature())["TEST"].mutable_bytes_list()->add_value("YES"); (*context.mutable_feature())["TEST"].mutable_bytes_list()->add_value("YES");
@@ -529,6 +927,10 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoBBoxDetections) {
auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i); auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i);
ASSERT_EQ(0, class_indices[0]); ASSERT_EQ(0, class_indices[0]);
ASSERT_EQ(1, class_indices[1]); ASSERT_EQ(1, class_indices[1]);
auto class_scores =
mpms::GetPredictedBBoxLabelConfidenceAt(output_sequence, i);
ASSERT_FLOAT_EQ(0.5, class_scores[0]);
ASSERT_FLOAT_EQ(0.75, class_scores[1]);
} }
} }
@@ -671,6 +1073,10 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksBBoxWithImages) {
auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i); auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i);
ASSERT_EQ(0, class_indices[0]); ASSERT_EQ(0, class_indices[0]);
ASSERT_EQ(1, class_indices[1]); ASSERT_EQ(1, class_indices[1]);
auto class_scores =
mpms::GetPredictedBBoxLabelConfidenceAt(output_sequence, i);
ASSERT_FLOAT_EQ(0.5, class_scores[0]);
ASSERT_FLOAT_EQ(0.75, class_scores[1]);
} }
} }
@@ -761,6 +1167,456 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoMaskDetections) {
testing::ElementsAreArray(::std::vector<std::string>({"mask"}))); testing::ElementsAreArray(::std::vector<std::string>({"mask"})));
} }
TEST_F(PackMediaSequenceCalculatorTest, PackThreeClipLabels) {
SetUpCalculator(
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2",
"CLIP_LABEL_ANOTHER:test3"},
/*features=*/{}, /*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
Detection detection_1;
detection_1.add_label("label_1");
detection_1.add_label("label_2");
detection_1.add_label_id(1);
detection_1.add_label_id(2);
detection_1.add_score(0.1);
detection_1.add_score(0.2);
runner_->MutableInputs()
->Tag(kClipLabelTestTag)
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
// No label ID for detection_2.
Detection detection_2;
detection_2.add_label("label_3");
detection_2.add_label("label_4");
detection_2.add_score(0.3);
detection_2.add_score(0.4);
runner_->MutableInputs()
->Tag(kClipLabelOtherTag)
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
// No label for detection_3.
Detection detection_3;
detection_3.add_label_id(3);
detection_3.add_label_id(4);
detection_3.add_score(0.3);
detection_3.add_score(0.4);
runner_->MutableInputs()
->Tag(kClipLabelAnotherTag)
.packets.push_back(MakePacket<Detection>(detection_3).At(Timestamp(3)));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(mpms::GetClipLabelString("TEST", output_sequence),
testing::ElementsAre("label_1", "label_2"));
ASSERT_THAT(mpms::GetClipLabelIndex("TEST", output_sequence),
testing::ElementsAre(1, 2));
ASSERT_THAT(mpms::GetClipLabelConfidence("TEST", output_sequence),
testing::ElementsAre(0.1, 0.2));
ASSERT_THAT(mpms::GetClipLabelString("OTHER", output_sequence),
testing::ElementsAre("label_3", "label_4"));
ASSERT_FALSE(mpms::HasClipLabelIndex("OTHER", output_sequence));
ASSERT_THAT(mpms::GetClipLabelConfidence("OTHER", output_sequence),
testing::ElementsAre(0.3, 0.4));
ASSERT_FALSE(mpms::HasClipLabelString("ANOTHER", output_sequence));
ASSERT_THAT(mpms::GetClipLabelIndex("ANOTHER", output_sequence),
testing::ElementsAre(3, 4));
ASSERT_THAT(mpms::GetClipLabelConfidence("ANOTHER", output_sequence),
testing::ElementsAre(0.3, 0.4));
}
TEST_F(PackMediaSequenceCalculatorTest, PackTwoClipLabels_EmptyScore) {
SetUpCalculator(
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
/*features=*/{}, /*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
// No score in detection_1. detection_1 is ignored.
Detection detection_1;
detection_1.add_label("label_1");
detection_1.add_label("label_2");
runner_->MutableInputs()
->Tag(kClipLabelTestTag)
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
Detection detection_2;
detection_2.add_label("label_3");
detection_2.add_label("label_4");
detection_2.add_score(0.3);
detection_2.add_score(0.4);
runner_->MutableInputs()
->Tag(kClipLabelOtherTag)
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_FALSE(mpms::HasClipLabelString("TEST", output_sequence));
ASSERT_FALSE(mpms::HasClipLabelIndex("TEST", output_sequence));
ASSERT_FALSE(mpms::HasClipLabelConfidence("TEST", output_sequence));
ASSERT_THAT(mpms::GetClipLabelString("OTHER", output_sequence),
testing::ElementsAre("label_3", "label_4"));
ASSERT_FALSE(mpms::HasClipLabelIndex("OTHER", output_sequence));
ASSERT_THAT(mpms::GetClipLabelConfidence("OTHER", output_sequence),
testing::ElementsAre(0.3, 0.4));
}
TEST_F(PackMediaSequenceCalculatorTest, PackTwoClipLabels_NoLabelOrLabelIndex) {
SetUpCalculator(
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
/*features=*/{}, /*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
// No label or label_index in detection_1.
Detection detection_1;
detection_1.add_score(0.1);
runner_->MutableInputs()
->Tag(kClipLabelTestTag)
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
Detection detection_2;
detection_2.add_label("label_3");
detection_2.add_label("label_4");
detection_2.add_score(0.3);
detection_2.add_score(0.4);
runner_->MutableInputs()
->Tag(kClipLabelOtherTag)
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
ASSERT_THAT(
runner_->Run(),
testing::status::StatusIs(
absl::StatusCode::kInvalidArgument,
testing::HasSubstr(
"detection.label and detection.label_id can't be both empty")));
}
TEST_F(PackMediaSequenceCalculatorTest,
PackTwoClipLabels_DifferentLabelScoreSize) {
SetUpCalculator(
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
/*features=*/{}, /*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
// 2 labels and 1 score in detection_1.
Detection detection_1;
detection_1.add_label("label_1");
detection_1.add_label("label_2");
detection_1.add_score(0.1);
runner_->MutableInputs()
->Tag(kClipLabelTestTag)
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
Detection detection_2;
detection_2.add_label("label_3");
detection_2.add_label("label_4");
detection_2.add_score(0.3);
detection_2.add_score(0.4);
runner_->MutableInputs()
->Tag(kClipLabelOtherTag)
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
ASSERT_THAT(
runner_->Run(),
testing::status::StatusIs(
absl::StatusCode::kInvalidArgument,
testing::HasSubstr(
"Different size of detection.label and detection.score")));
}
TEST_F(PackMediaSequenceCalculatorTest,
PackTwoClipLabels_DifferentLabelIdSize) {
SetUpCalculator(
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
/*features=*/{}, /*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
// 2 scores and 1 label_id in detection_1.
Detection detection_1;
detection_1.add_label("label_1");
detection_1.add_label("label_2");
detection_1.add_label_id(1);
detection_1.add_score(0.1);
detection_1.add_score(0.2);
runner_->MutableInputs()
->Tag(kClipLabelTestTag)
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
Detection detection_2;
detection_2.add_label("label_3");
detection_2.add_label("label_4");
detection_2.add_score(0.3);
detection_2.add_score(0.4);
runner_->MutableInputs()
->Tag(kClipLabelOtherTag)
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
ASSERT_THAT(
runner_->Run(),
testing::status::StatusIs(
absl::StatusCode::kInvalidArgument,
testing::HasSubstr(
"Different size of detection.label_id and detection.score")));
}
TEST_F(PackMediaSequenceCalculatorTest, ReplaceTwoClipLabels) {
// Replace existing clip/label/string and clip/label/confidence values for
// the prefixes.
SetUpCalculator(
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
/*features=*/{}, /*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
mpms::SetClipLabelString("TEST", {"old_label_1", "old_label_2"},
input_sequence.get());
mpms::SetClipLabelConfidence("TEST", {0.1, 0.2}, input_sequence.get());
mpms::SetClipLabelString("OTHER", {"old_label_3", "old_label_4"},
input_sequence.get());
mpms::SetClipLabelConfidence("OTHER", {0.3, 0.4}, input_sequence.get());
Detection detection_1;
detection_1.add_label("label_1");
detection_1.add_label("label_2");
detection_1.add_label_id(1);
detection_1.add_label_id(2);
detection_1.add_score(0.9);
detection_1.add_score(0.8);
runner_->MutableInputs()
->Tag(kClipLabelTestTag)
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
Detection detection_2;
detection_2.add_label("label_3");
detection_2.add_label("label_4");
detection_2.add_label_id(3);
detection_2.add_label_id(4);
detection_2.add_score(0.7);
detection_2.add_score(0.6);
runner_->MutableInputs()
->Tag(kClipLabelOtherTag)
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(mpms::GetClipLabelString("TEST", output_sequence),
testing::ElementsAre("label_1", "label_2"));
ASSERT_THAT(mpms::GetClipLabelIndex("TEST", output_sequence),
testing::ElementsAre(1, 2));
ASSERT_THAT(mpms::GetClipLabelConfidence("TEST", output_sequence),
testing::ElementsAre(0.9, 0.8));
ASSERT_THAT(mpms::GetClipLabelString("OTHER", output_sequence),
testing::ElementsAre("label_3", "label_4"));
ASSERT_THAT(mpms::GetClipLabelIndex("OTHER", output_sequence),
testing::ElementsAre(3, 4));
ASSERT_THAT(mpms::GetClipLabelConfidence("OTHER", output_sequence),
testing::ElementsAre(0.7, 0.6));
}
TEST_F(PackMediaSequenceCalculatorTest, AppendTwoClipLabels) {
// Append to the existing clip/label/string and clip/label/confidence values
// for the prefixes.
SetUpCalculator(
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
/*features=*/{}, /*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/false);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
mpms::SetClipLabelString("TEST", {"old_label_1", "old_label_2"},
input_sequence.get());
mpms::SetClipLabelIndex("TEST", {1, 2}, input_sequence.get());
mpms::SetClipLabelConfidence("TEST", {0.1, 0.2}, input_sequence.get());
mpms::SetClipLabelString("OTHER", {"old_label_3", "old_label_4"},
input_sequence.get());
mpms::SetClipLabelIndex("OTHER", {3, 4}, input_sequence.get());
mpms::SetClipLabelConfidence("OTHER", {0.3, 0.4}, input_sequence.get());
Detection detection_1;
detection_1.add_label("label_1");
detection_1.add_label("label_2");
detection_1.add_label_id(9);
detection_1.add_label_id(8);
detection_1.add_score(0.9);
detection_1.add_score(0.8);
runner_->MutableInputs()
->Tag(kClipLabelTestTag)
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
Detection detection_2;
detection_2.add_label("label_3");
detection_2.add_label("label_4");
detection_2.add_label_id(7);
detection_2.add_label_id(6);
detection_2.add_score(0.7);
detection_2.add_score(0.6);
runner_->MutableInputs()
->Tag(kClipLabelOtherTag)
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_THAT(
mpms::GetClipLabelString("TEST", output_sequence),
testing::ElementsAre("old_label_1", "old_label_2", "label_1", "label_2"));
ASSERT_THAT(mpms::GetClipLabelIndex("TEST", output_sequence),
testing::ElementsAre(1, 2, 9, 8));
ASSERT_THAT(mpms::GetClipLabelConfidence("TEST", output_sequence),
testing::ElementsAre(0.1, 0.2, 0.9, 0.8));
ASSERT_THAT(
mpms::GetClipLabelString("OTHER", output_sequence),
testing::ElementsAre("old_label_3", "old_label_4", "label_3", "label_4"));
ASSERT_THAT(mpms::GetClipLabelIndex("OTHER", output_sequence),
testing::ElementsAre(3, 4, 7, 6));
ASSERT_THAT(mpms::GetClipLabelConfidence("OTHER", output_sequence),
testing::ElementsAre(0.3, 0.4, 0.7, 0.6));
}
TEST_F(PackMediaSequenceCalculatorTest,
DifferentClipLabelScoreAndConfidenceSize) {
SetUpCalculator(
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
/*features=*/{}, /*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
Detection detection_1;
// 2 labels and 1 score.
detection_1.add_label("label_1");
detection_1.add_label("label_2");
detection_1.add_score(0.1);
runner_->MutableInputs()
->Tag(kClipLabelTestTag)
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
Detection detection_2;
detection_2.add_label("label_3");
detection_2.add_label("label_4");
detection_2.add_score(0.3);
detection_2.add_score(0.4);
runner_->MutableInputs()
->Tag(kClipLabelOtherTag)
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
ASSERT_THAT(runner_->Run(),
testing::status::StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST_F(PackMediaSequenceCalculatorTest, AddClipMediaId) {
SetUpCalculator(
/*input_streams=*/{"FLOAT_FEATURE_TEST:test",
"FLOAT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/true,
/*output_as_zero_timestamp=*/false, /*input_side_packets=*/
{"SEQUENCE_EXAMPLE:input_sequence", "CLIP_MEDIA_ID:video_id"});
auto input_sequence = absl::make_unique<tf::SequenceExample>();
const std::string test_video_id = "test_video_id";
int num_timesteps = 2;
for (int i = 0; i < num_timesteps; ++i) {
auto vf_ptr = ::absl::make_unique<std::vector<float>>(2, 2 << i);
runner_->MutableInputs()
->Tag(kFloatFeatureTestTag)
.packets.push_back(Adopt(vf_ptr.release()).At(Timestamp(i)));
vf_ptr = ::absl::make_unique<std::vector<float>>(2, 2 << i);
runner_->MutableInputs()
->Tag(kFloatFeatureOtherTag)
.packets.push_back(Adopt(vf_ptr.release()).At(Timestamp(i)));
}
runner_->MutableSidePackets()->Tag(kClipMediaIdTag) =
MakePacket<std::string>(test_video_id);
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_EQ(test_video_id, mpms::GetClipMediaId(output_sequence));
}
TEST_F(PackMediaSequenceCalculatorTest, ReplaceClipMediaId) {
SetUpCalculator(
/*input_streams=*/{"FLOAT_FEATURE_TEST:test",
"FLOAT_FEATURE_OTHER:test2"},
/*features=*/{},
/*output_only_if_all_present=*/false,
/*replace_instead_of_append=*/true,
/*output_as_zero_timestamp=*/false, /*input_side_packets=*/
{"SEQUENCE_EXAMPLE:input_sequence", "CLIP_MEDIA_ID:video_id"});
auto input_sequence = absl::make_unique<tf::SequenceExample>();
const std::string existing_video_id = "existing_video_id";
mpms::SetClipMediaId(existing_video_id, input_sequence.get());
const std::string test_video_id = "test_video_id";
int num_timesteps = 2;
for (int i = 0; i < num_timesteps; ++i) {
auto vf_ptr = ::absl::make_unique<std::vector<float>>(2, 2 << i);
runner_->MutableInputs()
->Tag(kFloatFeatureTestTag)
.packets.push_back(Adopt(vf_ptr.release()).At(Timestamp(i)));
vf_ptr = ::absl::make_unique<std::vector<float>>(2, 2 << i);
runner_->MutableInputs()
->Tag(kFloatFeatureOtherTag)
.packets.push_back(Adopt(vf_ptr.release()).At(Timestamp(i)));
}
runner_->MutableSidePackets()->Tag(kClipMediaIdTag) =
MakePacket<std::string>(test_video_id).At(Timestamp(0));
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
Adopt(input_sequence.release());
MP_ASSERT_OK(runner_->Run());
const std::vector<Packet>& output_packets =
runner_->Outputs().Tag(kSequenceExampleTag).packets;
ASSERT_EQ(1, output_packets.size());
const tf::SequenceExample& output_sequence =
output_packets[0].Get<tf::SequenceExample>();
ASSERT_EQ(test_video_id, mpms::GetClipMediaId(output_sequence));
}
TEST_F(PackMediaSequenceCalculatorTest, MissingStreamOK) { TEST_F(PackMediaSequenceCalculatorTest, MissingStreamOK) {
SetUpCalculator( SetUpCalculator(
{"FORWARD_FLOW_ENCODED:flow", "FLOAT_FEATURE_I3D_FLOW:feature"}, {}, {"FORWARD_FLOW_ENCODED:flow", "FLOAT_FEATURE_I3D_FLOW:feature"}, {},
@@ -1065,6 +1921,7 @@ TEST_F(PackMediaSequenceCalculatorTest, TestOverwritingAndReconciling) {
mpms::AddBBoxNumRegions(-1, input_sequence.get()); mpms::AddBBoxNumRegions(-1, input_sequence.get());
mpms::AddBBoxLabelString({"anything"}, input_sequence.get()); mpms::AddBBoxLabelString({"anything"}, input_sequence.get());
mpms::AddBBoxLabelIndex({-1}, input_sequence.get()); mpms::AddBBoxLabelIndex({-1}, input_sequence.get());
mpms::AddBBoxLabelConfidence({-1}, input_sequence.get());
mpms::AddBBoxClassString({"anything"}, input_sequence.get()); mpms::AddBBoxClassString({"anything"}, input_sequence.get());
mpms::AddBBoxClassIndex({-1}, input_sequence.get()); mpms::AddBBoxClassIndex({-1}, input_sequence.get());
mpms::AddBBoxTrackString({"anything"}, input_sequence.get()); mpms::AddBBoxTrackString({"anything"}, input_sequence.get());
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/tensorflow/tensor_squeeze_dimensions_calculator.pb.h" #include "mediapipe/calculators/tensorflow/tensor_squeeze_dimensions_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/ret_check.h" #include "mediapipe/framework/port/ret_check.h"
@@ -99,10 +100,11 @@ class TensorSqueezeDimensionsCalculator : public CalculatorBase {
} }
} }
if (remove_dims_.empty()) { if (remove_dims_.empty()) {
LOG(ERROR) << "TensorSqueezeDimensionsCalculator is squeezing input with " ABSL_LOG(ERROR)
"no single-dimensions. Calculator will be a no-op."; << "TensorSqueezeDimensionsCalculator is squeezing input with "
LOG(ERROR) << "Input to TensorSqueezeDimensionsCalculator has shape " "no single-dimensions. Calculator will be a no-op.";
<< tensor_shape.DebugString(); ABSL_LOG(ERROR) << "Input to TensorSqueezeDimensionsCalculator has shape "
<< tensor_shape.DebugString();
} }
} }
}; };
@@ -14,6 +14,7 @@
#include <iostream> #include <iostream>
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/tensorflow/tensor_to_image_frame_calculator.pb.h" #include "mediapipe/calculators/tensorflow/tensor_to_image_frame_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame.h" #include "mediapipe/framework/formats/image_frame.h"
@@ -99,7 +100,7 @@ absl::Status TensorToImageFrameCalculator::Process(CalculatorContext* cc) {
const tf::Tensor& input_tensor = cc->Inputs().Tag(kTensor).Get<tf::Tensor>(); const tf::Tensor& input_tensor = cc->Inputs().Tag(kTensor).Get<tf::Tensor>();
int32_t depth = 1; int32_t depth = 1;
if (input_tensor.dims() != 2) { // Depth is 1 for 2D tensors. if (input_tensor.dims() != 2) { // Depth is 1 for 2D tensors.
CHECK(3 == input_tensor.dims()) ABSL_CHECK(3 == input_tensor.dims())
<< "Only 2 or 3-D Tensors can be converted to frames. Instead got: " << "Only 2 or 3-D Tensors can be converted to frames. Instead got: "
<< input_tensor.dims(); << input_tensor.dims();
depth = input_tensor.dim_size(2); depth = input_tensor.dim_size(2);

Some files were not shown because too many files have changed in this diff Show More