Compare commits

..
557 Commits
Author SHA1 Message Date
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
Sebastian SchmidtandCopybara-Service d392f8ad98 Ensure that -std=c++14/17 is the first argument passed to Glog
PiperOrigin-RevId: 552509553
2023-07-31 09:47:32 -07:00
Sebastian SchmidtandCopybara-Service 81cf7fa173 Updat WASM binaries for 0.10.3 release
PiperOrigin-RevId: 551975834
2023-07-28 16:17:30 -07:00
MediaPipe TeamandCopybara-Service 8e313b4b0c Fix typo in model maker requirements.txt
PiperOrigin-RevId: 551973577
2023-07-28 16:07:12 -07:00
Sebastian SchmidtandCopybara-Service b4bcfab4f5 Remove extra letter from text classifier API
PiperOrigin-RevId: 551942087
2023-07-28 13:56:56 -07:00
Sebastian SchmidtandCopybara-Service 8ab9185c1d Use C+++ 17 for Glog only on Windows
PiperOrigin-RevId: 551928369
2023-07-28 12:58:42 -07:00
MediaPipe TeamandCopybara-Service 3f7752561b No public description
PiperOrigin-RevId: 551914786
2023-07-28 12:05:38 -07:00
MediaPipe TeamandCopybara-Service 9edb059d9f No public description
PiperOrigin-RevId: 551868738
2023-07-28 09:09:39 -07:00
MediaPipe TeamandCopybara-Service 7db0c1944b Internal change
PiperOrigin-RevId: 551789915
2023-07-28 02:29:52 -07:00
MediaPipe TeamandCopybara-Service db9a72a5df Internal Changes
PiperOrigin-RevId: 551674542
2023-07-27 16:35:35 -07:00
MediaPipe TeamandCopybara-Service 5c007558f8 internal change.
PiperOrigin-RevId: 551645248
2023-07-27 14:45:18 -07:00
Sebastian SchmidtandCopybara-Service 4d5c6bd33a Internal
PiperOrigin-RevId: 551625147
2023-07-27 13:33:14 -07:00
Sebastian SchmidtandCopybara-Service fdea10d230 Add C Headers for Text Classifier
PiperOrigin-RevId: 551618765
2023-07-27 13:09:49 -07:00
MediaPipe TeamandCopybara-Service 5b31f1e3e9 Update glog to latest commit
PiperOrigin-RevId: 551601991
2023-07-27 12:07:20 -07:00
Sebastian SchmidtandCopybara-Service 7d9cb4ee67 No public description
PiperOrigin-RevId: 551586945
2023-07-27 11:17:54 -07:00
MediaPipe TeamandCopybara-Service f3f9e71ccb No public description
PiperOrigin-RevId: 551549511
2023-07-27 09:15:46 -07:00
MediaPipe TeamandCopybara-Service 6de275834d internal change.
PiperOrigin-RevId: 551366789
2023-07-26 17:59:06 -07:00
Sebastian SchmidtandCopybara-Service c9d79a0076 Rollback of "Fix duplicate condition error in :resource_util"
PiperOrigin-RevId: 551332734
2023-07-26 15:31:51 -07:00
Sebastian SchmidtandCopybara-Service dad46e1e90 Update glog to 0.6
PiperOrigin-RevId: 551330044
2023-07-26 15:20:34 -07:00
Sebastian SchmidtandCopybara-Service f156397e8f Fix Android build with any Protos
PiperOrigin-RevId: 551325541
2023-07-26 15:04:38 -07:00
MediaPipe TeamandCopybara-Service fa5c1b03d2 No public description
PiperOrigin-RevId: 551277242
2023-07-26 12:08:33 -07:00
Sebastian SchmidtandCopybara-Service 87b925795d Update glog to 0.6
PiperOrigin-RevId: 551269455
2023-07-26 11:41:24 -07:00
Sebastian SchmidtandCopybara-Service 750f498b14 Internal
PiperOrigin-RevId: 551247471
2023-07-26 10:33:19 -07:00
Prianka Liz Kariat d2a86341bd Added refactored iOS vision task runner sources 2023-07-26 20:02:00 +05:30
MediaPipe TeamandCopybara-Service 1f6851c577 C++ Image segmenter add output size parameters.
PiperOrigin-RevId: 550995124
2023-07-25 14:22:11 -07:00
MediaPipe TeamandCopybara-Service bd7888cc0c 1. Move evaluation onto GPU/TPU hardware if available.
2. Move desired_precision and desired_recall from evaluate to hyperparameters so recall@precision metrics will be reported for both training and evaluation. This also fixes a bug where recompiling the model with the previously initialized metric objects would not properly reset the metric states.
3. Remove redundant label_names from create_... class methods in text_classifier. This information is already provided by the datasets.
4. Change loss function to FocalLoss.
5. Re-enable text_classifier unit tests using ExBert
6. Add input names to avoid flaky auto-assigned input names.

PiperOrigin-RevId: 550992146
2023-07-25 14:12:26 -07:00
MediaPipe TeamandCopybara-Service 85c3fed70a Add class weights to core hyperparameters and classifier library.
PiperOrigin-RevId: 550962843
2023-07-25 12:29:46 -07:00
MediaPipe TeamandCopybara-Service 62538a9496 No public description
PiperOrigin-RevId: 550954023
2023-07-25 11:57:08 -07:00
MediaPipe TeamandCopybara-Service 113c9b30c2 No public description
PiperOrigin-RevId: 550616150
2023-07-24 11:09:31 -07:00
Copybara-Service 66cceddb5e Merge pull request #4639 from priankakariatyml:ios-image-segmenter-container-utils
PiperOrigin-RevId: 550608973
2023-07-24 10:46:56 -07:00
Prianka Liz Kariat 72c62f7d5d Added iOS Image Segmenter Header 2023-07-24 20:38:16 +05:30
MediaPipe TeamandCopybara-Service 25b01784de Fix documentation
PiperOrigin-RevId: 549968822
2023-07-21 09:33:48 -07:00
MediaPipe TeamandCopybara-Service 9af637b125 Java API add visibility and presence for landmarks.
PiperOrigin-RevId: 549709256
2023-07-20 12:42:01 -07:00
Copybara-Service 236a36e39a Merge pull request #4629 from priankakariatyml:ios-vision-library-fixes
PiperOrigin-RevId: 549659874
2023-07-20 09:52:11 -07:00
Prianka Liz Kariat 540f4f7fe6 Fixed swift name of iOS face landmarker delegate 2023-07-20 15:57:37 +05:30
Prianka Liz Kariat 3198ccf6a5 Added missing headers in ios vision framework build 2023-07-20 15:57:16 +05:30
Steven HicksonandCopybara-Service e47af74b15 Adding support for 2 things in tensors_to_image_calculator:
1) 1 channel support for conversion after inference.
2) multitask support by allowing for different tensor outputs.

PiperOrigin-RevId: 549412331
2023-07-19 13:41:46 -07:00
MediaPipe TeamandCopybara-Service 085840388b Move waitOnCpu and waitOnGpu out of the synchronized block, which can cause deadlock.
PiperOrigin-RevId: 549217916
2023-07-18 23:42:01 -07:00
MediaPipe TeamandCopybara-Service 4e72fcf0cb Replace CHECK with RET_CHECK in GetContract() implementation from six calculators.
PiperOrigin-RevId: 549158984
2023-07-18 17:38:44 -07:00
MediaPipe TeamandCopybara-Service 4c60fe7365 add pose landmarks connections in C++ API
PiperOrigin-RevId: 549108310
2023-07-18 14:21:02 -07:00
MediaPipe TeamandCopybara-Service 9b00582f21 add hand landmarks connections in C++ API.
PiperOrigin-RevId: 549108307
2023-07-18 14:16:27 -07:00
MediaPipe TeamandCopybara-Service cb915858fa Internal change
PiperOrigin-RevId: 549052451
2023-07-18 11:01:37 -07:00
Jiuqiang TangandCopybara-Service 0c01187cf5 Internal change
PiperOrigin-RevId: 548886447
2023-07-17 21:57:24 -07:00
MediaPipe TeamandCopybara-Service ef12ce8575 Internal change
PiperOrigin-RevId: 548821518
2023-07-17 15:56:05 -07:00
MediaPipe TeamandCopybara-Service f1f9f80cd9 Internal change
PiperOrigin-RevId: 548746432
2023-07-17 11:18:00 -07:00
MediaPipe TeamandCopybara-Service 17bc1a5ab5 Internal change
PiperOrigin-RevId: 548196034
2023-07-14 12:39:45 -07:00
MediaPipe TeamandCopybara-Service 2fae07375c Discard outdated packets earlier in MuxInputStreamHandler.
In our pipeline, a deadlock is detected because the packets in deselected
data streams get piled up. In the current implementation, those packets only get
removed in FillInputSet(), but we should also do that in GetNodeReadiness().

PiperOrigin-RevId: 548051369
2023-07-14 01:12:14 -07:00
MediaPipe TeamandCopybara-Service 723e91cec1 Generalize non-define registration with MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE
PiperOrigin-RevId: 547929982
2023-07-13 14:52:37 -07:00
MediaPipe TeamandCopybara-Service c2c67c20fa Internal change
PiperOrigin-RevId: 547924907
2023-07-13 14:37:40 -07:00
Sebastian SchmidtandCopybara-Service 327feb42d1 Support WASM asset loading for MediaPipe Task Web
PiperOrigin-RevId: 547882566
2023-07-13 12:26:59 -07:00
MediaPipe TeamandCopybara-Service 8b59567cb7 Add proto3 Any proto support for Java task api
PiperOrigin-RevId: 547836041
2023-07-13 10:10:17 -07:00
MediaPipe TeamandCopybara-Service e37bedd344 Fix Halide BUILD rules
PiperOrigin-RevId: 547755467
2023-07-13 04:47:34 -07:00
MediaPipe TeamandCopybara-Service 251c5421f6 Internal change
PiperOrigin-RevId: 547735699
2023-07-13 02:53:16 -07:00
MediaPipe TeamandCopybara-Service 450c933cb5 MEDIAPIPE_NODE/SUBGRAPH_IMPLEMENTATION to use common define for registration
PiperOrigin-RevId: 547669538
2023-07-12 20:10:15 -07:00
MediaPipe TeamandCopybara-Service cc2aa4f4cc InferenceCalculatorAdvancedGL save cache in Open().
PiperOrigin-RevId: 547652481
2023-07-12 18:09:51 -07:00
MediaPipe TeamandCopybara-Service a2cd3e7f95 Internal change
PiperOrigin-RevId: 547614484
2023-07-12 15:17:40 -07:00
MediaPipe TeamandCopybara-Service 37b68714b8 Internal change
PiperOrigin-RevId: 547424721
2023-07-12 01:32:51 -07:00
MediaPipe TeamandCopybara-Service 3e93cbc838 Internal change
PiperOrigin-RevId: 547404737
2023-07-12 00:04:40 -07:00
Yilei YangandCopybara-Service 917af2ce6b Internal change
PiperOrigin-RevId: 547346939
2023-07-11 17:52:07 -07:00
Sebastian SchmidtandCopybara-Service f2f49b9fc8 Add angle to BoundingBox
PiperOrigin-RevId: 547321781
2023-07-11 16:00:35 -07:00
MediaPipe TeamandCopybara-Service aabf61f28d Internal Change
PiperOrigin-RevId: 547299595
2023-07-11 14:35:18 -07:00
MediaPipe TeamandCopybara-Service 56bc019819 Model Maker allow core dataset library to handle datasets with unknown sizes.
PiperOrigin-RevId: 547268411
2023-07-11 12:47:37 -07:00
MediaPipe TeamandCopybara-Service 4788fddde9 Internal Change
PiperOrigin-RevId: 547265380
2023-07-11 12:34:32 -07:00
MediaPipe TeamandCopybara-Service e4ec4d2526 Internal change
PiperOrigin-RevId: 547258228
2023-07-11 12:05:58 -07:00
MediaPipe TeamandCopybara-Service bf6561ce91 add symmetric color style option
PiperOrigin-RevId: 547069284
2023-07-10 21:41:01 -07:00
MediaPipe TeamandCopybara-Service 0bde987a38 Removed internal dependency on OpenCV 3.x, migrating it to OpenCV 4.x
PiperOrigin-RevId: 546945166
2023-07-10 12:17:54 -07:00
Copybara-Service df3f4167ae Merge pull request #4600 from priankakariatyml:ios-orientation-fix
PiperOrigin-RevId: 546358930
2023-07-07 12:56:39 -07:00
Sebastian SchmidtandCopybara-Service 03bc9d64f2 Update glog to 0.6
PiperOrigin-RevId: 546349096
2023-07-07 12:22:13 -07:00
MediaPipe TeamandCopybara-Service d45b15ef84 Add face landmarks connections for C++.
PiperOrigin-RevId: 546345842
2023-07-07 12:08:09 -07:00
Sebastian SchmidtandCopybara-Service 1614c5a542 Update WASM files for 0.10.2 release
PiperOrigin-RevId: 546332490
2023-07-07 11:20:13 -07:00
Prianka Liz Kariat cae10ea115 Updated documentation of MPImage 2023-07-07 22:03:15 +05:30
Prianka Liz Kariat 7556a3f1b4 Changed left and right image orientation angles to match iOS UIImageOrientation 2023-07-07 19:57:44 +05:30
MediaPipe TeamandCopybara-Service cb1035a9ee Internal change
PiperOrigin-RevId: 546090489
2023-07-06 14:24:31 -07:00
Yoni Ben-MeshulamandCopybara-Service 0a198d1f6a Fix a typo in proto doc.
PiperOrigin-RevId: 546049240
2023-07-06 14:20:09 -07:00
MediaPipe TeamandCopybara-Service 15ee1210e5 Internal change
PiperOrigin-RevId: 546035969
2023-07-06 10:58:20 -07:00
Copybara-Service a851863e9c Merge pull request #4590 from priankakariatyml:ios-image-segmenter-container-utils
PiperOrigin-RevId: 546018332
2023-07-06 09:57:59 -07:00
Prianka Liz Kariat 823d5b39af Fixed typo 2023-07-06 18:46:01 +05:30
Sebastian SchmidtandCopybara-Service 9861b3c8a8 Fix bounds calculation in RefineLandmarksFromHeatMapCalculator
Fixes https://github.com/google/mediapipe/issues/4414

PiperOrigin-RevId: 545794151
2023-07-05 14:58:36 -07:00
MediaPipe TeamandCopybara-Service 74f484d96d Internal change
PiperOrigin-RevId: 545658434
2023-07-05 07:09:40 -07:00
MediaPipe TeamandCopybara-Service dbe8e40124 Internal change
PiperOrigin-RevId: 545045282
2023-07-03 10:04:19 -07:00
Prianka Liz Kariat 9b7e233fe3 Added Image Segmenter Result Helpers 2023-07-03 20:48:29 +05:30
Prianka Liz Kariat cebb0a2c2e Added iOS Image Segmenter Options Helpers 2023-07-03 20:48:15 +05:30
MediaPipe TeamandCopybara-Service 7ba21e9a9a Revert Add location info in registry (debug mode only)
PiperOrigin-RevId: 544842663
2023-07-01 01:11:02 -07:00
MediaPipe TeamandCopybara-Service 422556c4a3 Internal change
PiperOrigin-RevId: 544663494
2023-06-30 08:34:32 -07:00
Jiuqiang TangandCopybara-Service 6c7aa8a0d6 Internal change
PiperOrigin-RevId: 544563029
2023-06-29 23:05:37 -07:00
MediaPipe TeamandCopybara-Service 687075e5b8 Add gpu to cpu fallback for tensors_to_detections_calculator.
PiperOrigin-RevId: 544480883
2023-06-29 15:36:33 -07:00
MediaPipe TeamandCopybara-Service 0ea54b1461 Add delegate options to base options for java API. and add unit tset for BaseOptions.
PiperOrigin-RevId: 544458644
2023-06-29 14:13:46 -07:00
MediaPipe TeamandCopybara-Service e15d5a797b Do not send PreviousLoopback output packets to closed streams
PiperOrigin-RevId: 544449979
2023-06-29 13:44:56 -07:00
MediaPipe TeamandCopybara-Service 52cea59d41 Add keys for the context that better match the featurelist for text.
PiperOrigin-RevId: 544430289
2023-06-29 12:29:49 -07:00
MediaPipe TeamandCopybara-Service 0bb4ee8941 Add MobileNetV2_I320 and MobileNetMultiHWAVG_I384 to support larger input image sizes.
PiperOrigin-RevId: 544393692
2023-06-29 10:24:52 -07:00
MediaPipe TeamandCopybara-Service 8278dbc38f Exposes OpenCV photo lib.
PiperOrigin-RevId: 544092832
2023-06-28 10:22:07 -07:00
MediaPipe TeamandCopybara-Service 1ee55d1f1b Support ExBert training and option to select between AdamW and LAMB optimizers for BertClassifier
PiperOrigin-RevId: 543905014
2023-06-27 18:05:15 -07:00
MediaPipe TeamandCopybara-Service bed624f3b6 Shows the recently added warning when WaitUntilIdle is called with source nodes only once. Otherwise, it is very spammy as it's shown every frame. Moreover, display the names of the sources, so the warning is more actionable.
PiperOrigin-RevId: 543676454
2023-06-27 02:03:04 -07:00
MediaPipe TeamandCopybara-Service c8c5f3d062 Internal change
PiperOrigin-RevId: 543602625
2023-06-26 18:57:21 -07:00
MediaPipe TeamandCopybara-Service 9de1b2577f Internal update
PiperOrigin-RevId: 543508346
2023-06-26 12:26:51 -07:00
MediaPipe TeamandCopybara-Service 570880190b Internal change for proto library outputs.
PiperOrigin-RevId: 543368974
2023-06-26 01:52:50 -07:00
Copybara-Service 5d19a46956 Merge pull request #4561 from priankakariatyml:ios-segmentation-mask
PiperOrigin-RevId: 543295371
2023-06-25 17:37:35 -07:00
Copybara-Service 80a02f8f38 Merge pull request #4566 from priankakariatyml:ios-image-segmenter-containers
PiperOrigin-RevId: 542931120
2023-06-23 12:42:56 -07:00
Copybara-Service 0093f2040b Merge pull request #4567 from priankakariatyml:ios-running-mode-copy-fix
PiperOrigin-RevId: 542930036
2023-06-23 12:38:34 -07:00
Prianka Liz Kariat 3d79d58286 Updated variable name 2023-06-23 20:18:41 +05:30
Prianka Liz Kariat bfb68491af Added copying of running mode in NSCopying implementation in iOS tasks 2023-06-23 20:13:29 +05:30
Prianka Liz Kariat 5dce8f283d Updated image segmenter delegate method to be required 2023-06-23 20:10:42 +05:30
Prianka Liz Kariat 7623c5a941 Added iOS Image Segmenter Options 2023-06-23 20:09:18 +05:30
Prianka Liz Kariat 7fe365489d Added iOS Image Segmenter Result 2023-06-23 20:09:05 +05:30
MediaPipe TeamandCopybara-Service a8899da45a Fix -Wsign-compare warning in api2/builder.h
PiperOrigin-RevId: 542673286
2023-06-22 14:49:23 -07:00
MediaPipe TeamandCopybara-Service 4e862995ba Fix typo
PiperOrigin-RevId: 542660548
2023-06-22 14:02:16 -07:00
MediaPipe TeamandCopybara-Service 2f5fc16a38 Fix timestamp computation when copying within first block.
When computing the last copied sample's timestamp, first_block_offset_ needs to be taken into account.

PiperOrigin-RevId: 542643291
2023-06-22 13:03:36 -07:00
Jiuqiang TangandCopybara-Service 98d493f37a Add MatrixData as a packet option for ConstantSidePacketCalculatorOptions.
PiperOrigin-RevId: 542616847
2023-06-22 11:28:07 -07:00
MediaPipe TeamandCopybara-Service ba7e0e0e50 Add a face alignment preprocessor to face stylizer.
PiperOrigin-RevId: 542559764
2023-06-22 07:59:52 -07:00
Prianka Liz Kariat 7f39153ff3 Added MPPMask Tests 2023-06-22 17:44:07 +05:30
MediaPipe TeamandCopybara-Service 825e3a8af0 Speed up TimeSeriesFramerCalculator.
Currently, TimeSeriesFramerCalculator constructs a distinct Matrix object for every input sample, which is inefficient. This CL revises buffering to keep each input packet's worth of samples as one grouped Matrix. A benchmark is added, showing a speed up of about 20x.

```
name                               old      new
BM_TimeSeriesFramerCalculator  48.45ms   2.26ms
```

PiperOrigin-RevId: 542462618
2023-06-21 23:03:54 -07:00
MediaPipe TeamandCopybara-Service 0d2548cd65 Internal change
PiperOrigin-RevId: 542392817
2023-06-21 16:23:43 -07:00
MediaPipe TeamandCopybara-Service c86d80a031 Internal Changes
PiperOrigin-RevId: 542387813
2023-06-21 16:02:54 -07:00
MediaPipe TeamandCopybara-Service 895c685df6 1. Model maker core classifier change _metric_function field to _metric_functions in order to support having multiple metrics.
2. Add SparsePrecision, SparseRecall, BinarySparsePrecisionAtRecall, and BinarySparseRecallAtPrecision to the shared metrics library.
3. Add SparsePrecision, SparseRecall to text classifier, and have the option to evaluate the model with BinarySparsePrecisionAtRecall and BinarySparseRecallAtPrecision

PiperOrigin-RevId: 542376451
2023-06-21 15:19:29 -07:00
MediaPipe TeamandCopybara-Service 7edb6b8fcb add concatenate image vector calculator
PiperOrigin-RevId: 542084345
2023-06-20 16:40:11 -07:00
MediaPipe TeamandCopybara-Service 0b6ff84e3c update face drawing function.
PiperOrigin-RevId: 542083042
2023-06-20 16:34:27 -07:00
Sebastian SchmidtandCopybara-Service ef6aeb8828 Allow passing of HParams to MediaPipe training docker
PiperOrigin-RevId: 542052304
2023-06-20 14:39:38 -07:00
MediaPipe TeamandCopybara-Service 86bc764b6e This will fix typos in tasks internal files.
PiperOrigin-RevId: 541945726
2023-06-20 09:18:01 -07:00
Copybara-Service bd3a8d885d Merge pull request #4538 from priankakariatyml:ios-segmentation-mask
PiperOrigin-RevId: 541944396
2023-06-20 09:12:53 -07:00
MediaPipe TeamandCopybara-Service 35c79b755e update face drawing function.
PiperOrigin-RevId: 541055040
2023-06-16 17:46:11 -07:00
MediaPipe TeamandCopybara-Service 80208079d2 Use GFile for internal file systems.
PiperOrigin-RevId: 541041972
2023-06-16 16:45:56 -07:00
Copybara-Service 41215a3878 Merge pull request #4541 from priankakariatyml:ios-hand-landmarker-tests
PiperOrigin-RevId: 540995916
2023-06-16 14:07:49 -07:00
Sebastian SchmidtandCopybara-Service c5b1edd709 Add "exports" field definitions to package.json
Fixes https://github.com/google/mediapipe/issues/4547

PiperOrigin-RevId: 540977469
2023-06-16 13:14:09 -07:00
Prianka Liz Kariat d12dd88f51 Fixed implementation of init methods in MPPMask 2023-06-16 20:00:30 +05:30
Prianka Liz Kariat 4ab1a5de1b Reverted changes to iOS tasks deployment target 2023-06-16 19:59:59 +05:30
Prianka Liz Kariat fec2fc77e0 Revert "Revert "Updated init method implementations in MPPMask""
This reverts commit 52f6b8d899.
2023-06-16 19:56:32 +05:30
Prianka Liz Kariat 52f6b8d899 Revert "Updated init method implementations in MPPMask"
This reverts commit 83486ed01b.
2023-06-16 19:56:23 +05:30
Prianka Liz Kariat 83486ed01b Updated init method implementations in MPPMask 2023-06-16 19:56:04 +05:30
MediaPipe TeamandCopybara-Service 6f065bc405 Update Tensorflow dependency in MediaPipe
PiperOrigin-RevId: 540619536
2023-06-15 10:23:20 -07:00
Sebastian SchmidtandCopybara-Service e73ea23261 Internal change
PiperOrigin-RevId: 540603621
2023-06-15 09:26:01 -07:00
Prianka Liz Kariat 1f77fa9de4 Removed generic methods for alloc and memcpy from MPPMask 2023-06-15 16:07:56 +05:30
Prianka Liz Kariat 327547ec2b Updated variable names in MPPMask 2023-06-15 14:16:34 +05:30
Prianka Liz Kariat 9d0fed89ff Fixed documentation in MPPMask 2023-06-15 14:11:08 +05:30
Prianka Liz Kariat aa1ab18000 Updated documentation in MPPMask 2023-06-15 14:09:22 +05:30
Prianka Liz Kariat a7f555fcc2 Fixed float calculations in MPPMask 2023-06-15 14:07:33 +05:30
Prianka Liz Kariat c8f85ac060 Updated signature of initializer in MPPMask 2023-06-15 14:06:52 +05:30
MediaPipe TeamandCopybara-Service 2e48a0bce0 Remove designated initializers
PiperOrigin-RevId: 540471772
2023-06-14 22:17:20 -07:00
MediaPipe TeamandCopybara-Service e02d70f8e5 internal change
PiperOrigin-RevId: 540404812
2023-06-14 16:00:00 -07:00
Copybara-Service a2d4566845 Merge pull request #4542 from priankakariatyml:ios-hand-landmarker-updates
PiperOrigin-RevId: 540393678
2023-06-14 15:16:14 -07:00
MediaPipe TeamandCopybara-Service 4776ecf402 Internal change
PiperOrigin-RevId: 540361672
2023-06-14 13:23:36 -07:00
MediaPipe TeamandCopybara-Service a1be5f3e72 Add a test case for "summary packet" to test failing upstream calculator
PiperOrigin-RevId: 540331486
2023-06-14 11:34:17 -07:00
MediaPipe TeamandCopybara-Service 66a29bf371 Internal change
PiperOrigin-RevId: 540327302
2023-06-14 11:23:51 -07:00
Prianka Liz Kariat 9ed7acc0a3 Updated hand connections in iOS hand landmarker to class properties. 2023-06-14 15:59:54 +05:30
Prianka Liz Kariat 94a9464750 Fixed formatting in MPPHandLandmarkerTests.m 2023-06-14 15:52:26 +05:30
Prianka Liz Kariat 0ae27fad37 Updated iOS hand landmarker tests 2023-06-14 15:51:41 +05:30
Prianka Liz Kariat dffca9e3b5 Updated protobuf helper method name in iOS Gesture Recognizer Helpers 2023-06-14 15:51:06 +05:30
Prianka Liz Kariat 086798e677 Merge branch 'master' into ios-hand-landmarker-tests 2023-06-14 15:35:02 +05:30
Prianka Liz Kariat 43e51c1094 Added live stream mode tests for iOS Hand Landmarker 2023-06-14 15:34:32 +05:30
Yuqi LiandCopybara-Service eaeca82b76 Internal change
PiperOrigin-RevId: 540134258
2023-06-13 18:41:30 -07:00
MediaPipe TeamandCopybara-Service 3742bc8c1b Add metadata for all PREFIX/image... prefixes.
PiperOrigin-RevId: 540117214
2023-06-13 17:12:17 -07:00
MediaPipe TeamandCopybara-Service 02d55dfb0a Modify the TensorToImageFrameCalculator to support normalized outputs.
PiperOrigin-RevId: 540104988
2023-06-13 16:20:42 -07:00
MediaPipe TeamandCopybara-Service b97d11fa76 Internal MediaPipe Tasks change
PiperOrigin-RevId: 540083633
2023-06-13 15:05:04 -07:00
Copybara-Service 6cf7148f3b Merge pull request #4534 from priankakariatyml:ios-hand-landmarker-tests
PiperOrigin-RevId: 540030514
2023-06-13 11:58:26 -07:00
Prianka Liz Kariat 2cdb291e54 Removed core video import 2023-06-13 22:29:15 +05:30
Prianka Liz Kariat dddbcc4449 Updated data types of width and height 2023-06-13 22:28:09 +05:30
MediaPipe TeamandCopybara-Service e468bee584 Deprecate GraphStatus()
PiperOrigin-RevId: 539992850
2023-06-13 09:54:22 -07:00
Prianka Liz Kariat 5e2bb0e1db Updated documentation of MPPMask 2023-06-13 22:19:40 +05:30
Prianka Liz Kariat de9acdfa68 Added iOS segmentation mask 2023-06-13 22:17:41 +05:30
MediaPipe TeamandCopybara-Service b19b80e10f Add support for int64 constant side package value.
PiperOrigin-RevId: 539893314
2023-06-13 01:53:13 -07:00
MediaPipe TeamandCopybara-Service 96cc0fd07b Internal change
PiperOrigin-RevId: 539719443
2023-06-12 11:53:48 -07:00
MediaPipe TeamandCopybara-Service fe0d1b1e83 Internal change
PiperOrigin-RevId: 539675912
2023-06-12 09:28:26 -07:00
Sebastian SchmidtandCopybara-Service 8a2ec518de Use .mjs for ESM Modules and use .cjs for CommonJS
PiperOrigin-RevId: 539664711
2023-06-12 08:45:01 -07:00
Prianka Liz Kariat baa79046b9 Added iOS Objective C hand landmarker tests 2023-06-12 19:56:34 +05:30
Prianka Liz Kariat eff56045e4 Added hand landmarker protobuf utils 2023-06-12 19:56:20 +05:30
MediaPipe TeamandCopybara-Service ac4f60a793 Annotate in model input scale for InteractiveSegmenter
PiperOrigin-RevId: 539245617
2023-06-09 21:13:20 -07:00
MediaPipe TeamandCopybara-Service 1d4a205c2e Internal change
PiperOrigin-RevId: 539220863
2023-06-09 18:06:50 -07:00
MediaPipe TeamandCopybara-Service 53f0736bf0 Add an option to disable explicit CPU sync for ExternalTextureRenderer
PiperOrigin-RevId: 539166965
2023-06-09 13:42:14 -07:00
Sebastian SchmidtandCopybara-Service 67c5d8d224 Add FaceLandmarker constants for iOS
PiperOrigin-RevId: 539160195
2023-06-09 13:15:26 -07:00
Copybara-Service fb47218e10 Merge pull request #4526 from priankakariatyml:ios-hand-landmarker-implementation
PiperOrigin-RevId: 539145005
2023-06-09 12:12:42 -07:00
Prianka Liz Kariat f528fa5de2 Updated constant names in MPPHandLandmarkConnections 2023-06-09 17:30:23 +05:30
Copybara-Service 4c4a1d93b2 Merge pull request #4523 from priankakariatyml:ios-gesture-recognizer-add-tests
PiperOrigin-RevId: 538848389
2023-06-08 11:48:18 -07:00
Prianka Liz Kariat f63c00b3c6 Added hand landmarker implementation file and hand landmarker connections 2023-06-08 18:09:42 +05:30
MediaPipe TeamandCopybara-Service 943445fba8 Update base audio/vision tasks api to suuport proto3 graph options.
PiperOrigin-RevId: 538661975
2023-06-07 20:04:33 -07:00
Sebastian SchmidtandCopybara-Service a7cd7b9a32 Add CommonJS bundle for MediaPipe Tasks
Fixes https://github.com/google/mediapipe/issues/4398

PiperOrigin-RevId: 538539711
2023-06-07 11:12:37 -07:00
Ilya TokarandCopybara-Service 489e927410 Fix tests to work with arch haswell/sandybridge.
PiperOrigin-RevId: 538538356
2023-06-07 11:07:49 -07:00
Prianka Liz Kariat 10144a805a Added more tests to MPPGestureRecognizerTests.mm 2023-06-07 18:45:37 +05:30
Prianka Liz Kariat 8a5b443b86 Fixed typos in method names 2023-06-07 18:44:54 +05:30
MediaPipe TeamandCopybara-Service 4b0f3cacae Internal change
PiperOrigin-RevId: 538313290
2023-06-06 15:52:55 -07:00
Sebastian SchmidtandCopybara-Service d6f34f6aef Log the Bazel build
PiperOrigin-RevId: 538308030
2023-06-06 15:31:33 -07:00
Sebastian SchmidtandCopybara-Service 4a123445c4 Update rules_foreign_cc
Fixes https://github.com/google/mediapipe/issues/4365

PiperOrigin-RevId: 538301543
2023-06-06 15:08:00 -07:00
Sebastian SchmidtandCopybara-Service d063ed2c1e Rename MPPFaceLandmarker.m to MPPFaceLandmarker.mm
PiperOrigin-RevId: 538281740
2023-06-06 13:52:23 -07:00
Copybara-Service c71673d712 Merge pull request #4495 from priankakariatyml:ios-gesture-recognizer-tests
PiperOrigin-RevId: 538259988
2023-06-06 12:31:10 -07:00
Copybara-Service 70e00b4dbe Merge pull request #4497 from priankakariatyml:ios-hand-landmarker-utils
PiperOrigin-RevId: 538238944
2023-06-06 11:17:45 -07:00
Fergus HendersonandCopybara-Service 709eb812cc Internal change
PiperOrigin-RevId: 538215311
2023-06-06 10:00:52 -07:00
MediaPipe TeamandCopybara-Service 37290f0224 Port StreamToSidePacketCalculator to api2
PiperOrigin-RevId: 538109898
2023-06-06 01:34:43 -07:00
MediaPipe TeamandCopybara-Service ab72fccca7 Internal change
PiperOrigin-RevId: 537928827
2023-06-05 11:14:28 -07:00
Prianka Liz Kariat d256a3e670 Updated dictionary to generics in iOS gesture recognizer tests 2023-06-05 21:13:04 +05:30
Prianka Liz Kariat f213e0a6f3 Fixed typos 2023-06-05 13:47:11 +05:30
Prianka Liz Kariat 1496b7c2d4 Updated MPPGestureRecognizer tests to use generics 2023-06-05 13:40:56 +05:30
Prianka Liz Kariat 32195e6a83 Updated MPPGestureRecognizerTests to use generics for file path dicts 2023-06-05 13:39:44 +05:30
Prianka Liz Kariat e1d8854388 Merge branch 'master' into ios-gesture-recognizer-tests 2023-06-05 13:27:44 +05:30
Prianka Liz Kariat db0da30f18 Updated comments 2023-06-05 13:26:17 +05:30
Prianka Liz Kariat 56a035cb1b Updated method names in MPPGestureRecognizer 2023-06-05 13:21:39 +05:30
Prianka Liz Kariat 0c2a7bee09 Update iOS Gesture Recognizer error assertion 2023-06-05 13:19:39 +05:30
MediaPipe TeamandCopybara-Service cbf1d97429 Internal change
PiperOrigin-RevId: 537613648
2023-06-03 20:19:16 -07:00
Sebastian SchmidtandCopybara-Service 549e09cace Add FaceLandmarker iOS Live Stream API
PiperOrigin-RevId: 537434786
2023-06-02 16:22:20 -07:00
Sebastian SchmidtandCopybara-Service ace56b502a Add FaceLandmarker iOS API
PiperOrigin-RevId: 537424705
2023-06-02 15:35:48 -07:00
Sebastian SchmidtandCopybara-Service 5f50ac371f Internal
PiperOrigin-RevId: 537420663
2023-06-02 15:15:44 -07:00
Sebastian SchmidtandCopybara-Service 91a3c54d55 Internal change
PiperOrigin-RevId: 537405687
2023-06-02 14:12:35 -07:00
MediaPipe TeamandCopybara-Service b69f93fca6 Internal change
PiperOrigin-RevId: 537381138
2023-06-02 12:31:55 -07:00
Copybara-Service 09bad328ad Merge pull request #4485 from priankakariatyml:ios-delegate-fixes
PiperOrigin-RevId: 537369166
2023-06-02 11:49:18 -07:00
MediaPipe TeamandCopybara-Service 280bd320b4 Fix more OSS warnings and build errors
-Wc++98-compat-extra-semi
* in type_map.h

-Winconsistent-missing-override
* in gl_texture_buffer.h

-Wdeprecated-declarations
* usage of (absl) Status in
  * status_util.cc
  * api2/packet.h
  * output_stream_shard.cc

-Wimplicit-const-int-float-conversion
* Adds a static_cast to handle the precision loss when converting from large ints to floating point

ANNOTATE_THREAD_NAME
* explicitly uses ABSL_ANNOTATE_THREAD_NAME instead. This is useful in Chromium's build where there are multiple ANNOTATE_THREAD_NAME symbols

Also ran clang-format over all of each edited file

PiperOrigin-RevId: 537351290
2023-06-02 10:46:42 -07:00
MediaPipe TeamandCopybara-Service 9045a74ba3 Internal change
PiperOrigin-RevId: 537175065
2023-06-01 17:48:03 -07:00
Joe FernandezandCopybara-Service a6e63fa320 Adding redirects for old pages and updating pages for upgraded legacy solutions
PiperOrigin-RevId: 537145433
2023-06-01 15:31:42 -07:00
MediaPipe TeamandCopybara-Service 15aff443b1 Internal change
PiperOrigin-RevId: 537089863
2023-06-01 12:00:44 -07:00
Sebastian SchmidtandCopybara-Service 194a301dd8 Update WASM files for 0.10.1 release
PiperOrigin-RevId: 537078723
2023-06-01 11:22:40 -07:00
Prianka Liz Kariat 9356dfcd46 Updated MPPHandLandmarker.h to return the hand connections via class mathods 2023-06-01 16:53:32 +05:30
Prianka Liz Kariat e2f899e151 Updated documentation in MPPHandLandmarkResult+Helpers.h 2023-06-01 16:44:57 +05:30
Prianka Liz Kariat 961afc8928 Updated documentation in MPPHandLandmarkerResult Helpers 2023-06-01 16:43:33 +05:30
Paul WankadiaandCopybara-Service f21ee4c197 Update MediaPipe to RE2 release 2023-06-01.
Note that RE2 has taken a dependency on Abseil, so the `main` branch
should be used from now on. The `abseil` branch will go away soon...

PiperOrigin-RevId: 536829679
2023-05-31 14:52:24 -07:00
Prianka Liz Kariat 77bb5e7202 Fixed import in iOS gesture recognizer test utils 2023-05-31 20:53:36 +05:30
Prianka Liz Kariat ebeffc27eb Renamed iOS gesture recognizer protobuf utils 2023-05-31 20:51:43 +05:30
Prianka Liz Kariat 4326c97c95 Added MPPHandLandmark 2023-05-31 20:44:35 +05:30
Prianka Liz Kariat 0c33601510 Added MPPHandLandmarker 2023-05-31 20:44:25 +05:30
Prianka Liz Kariat ad499c170a Added MPPConnection 2023-05-31 20:43:24 +05:30
Prianka Liz Kariat 71f2f8f43b Added MPPHandLandmarkerResult Helpers 2023-05-31 20:42:49 +05:30
Prianka Liz Kariat 955489d71d Removed a test from iOS ObjC Gesture Recognizer tests 2023-05-31 20:39:01 +05:30
Prianka Liz Kariat e3b03866dc Removed unwanted import from MPPImageClassifier.h 2023-05-31 20:35:12 +05:30
Prianka Liz Kariat f77e685ff9 Removed unwanted header import from MPPGestureRecognizer.h 2023-05-31 20:34:02 +05:30
Prianka Liz Kariat c87e21206a Removed few test from MPPGestureRecognizerTests.m 2023-05-31 11:53:41 +05:30
Prianka Liz Kariat 365956807d Added gesture_recognizer.task to vision tasks test data 2023-05-31 11:52:29 +05:30
Prianka Liz Kariat 9546596b5a Updated variable name in MPPGestureRecognizerTests.m 2023-05-31 11:51:00 +05:30
Prianka Liz Kariat f3f664300c Added convenience method for creating results for tests in MPPGestureRecognizerResult Helpers 2023-05-31 11:50:39 +05:30
Prianka Liz Kariat 84560f3e7d Added more recognize tests to iOS Gesture Recognizer Objective C tests 2023-05-31 11:36:29 +05:30
Prianka Liz Kariat 1e77468eec Added iOS Gesture Recognizer ObjC Test for simple recognition 2023-05-31 11:29:37 +05:30
Prianka Liz Kariat 746f466c3a Added iOS Gesture Recognizer Protobuf utils 2023-05-31 11:28:50 +05:30
Sebastian SchmidtandCopybara-Service d76b48ec8b Add MP_DISABLE_GPU to .so target
PiperOrigin-RevId: 536537732
2023-05-30 16:18:02 -07:00
Copybara-Service 32e48dd2d9 Merge pull request #4486 from priankakariatyml:ios-gesture-recognizer-impl
PiperOrigin-RevId: 536516003
2023-05-30 14:53:04 -07:00
Sebastian SchmidtandCopybara-Service b7c940ef8a Internal change
PiperOrigin-RevId: 536499053
2023-05-30 13:51:06 -07:00
MediaPipe TeamandCopybara-Service 01cfb92e35 Add MultiLandmarksSmoothingCalculator
PiperOrigin-RevId: 536490704
2023-05-30 13:20:55 -07:00
MediaPipe TeamandCopybara-Service c73027926f Add MultiLandmarksSmoothingCalculator
PiperOrigin-RevId: 536478601
2023-05-30 12:37:05 -07:00
MediaPipe TeamandCopybara-Service a432559123 Port LandmarksSmoothingCalculator to api2
PiperOrigin-RevId: 536474279
2023-05-30 12:20:23 -07:00
Sebastian SchmidtandCopybara-Service 96357b1910 Internal change
PiperOrigin-RevId: 536457269
2023-05-30 11:21:17 -07:00
MediaPipe TeamandCopybara-Service 056881f4a9 Only apply face landmarks smoothing for stream mode (VIDEO and LIVE_STREAM).
PiperOrigin-RevId: 536455842
2023-05-30 11:16:43 -07:00
Prianka Liz Kariat aa7308498b Fixed typo 2023-05-30 23:38:04 +05:30
Copybara-Service fabde5f129 Merge pull request #4467 from priankakariatyml:ios-hand-landmarker-containers
PiperOrigin-RevId: 536447484
2023-05-30 10:49:22 -07:00
Copybara-Service 21eeac9fd7 Merge pull request #4464 from priankakariatyml:ios-gesture-recognizer-updates
PiperOrigin-RevId: 536421680
2023-05-30 09:24:06 -07:00
Prianka Liz Kariat b154dde19f Added iOS Gesture Recognizer implementation 2023-05-29 22:47:17 +05:30
Prianka Liz Kariat 6073d693d0 Added a method in iOS Object Detector to process packets for callbacks 2023-05-29 22:38:22 +05:30
Prianka Liz Kariat 250b11f5d1 Added a method in iOS image classifier to process result for the callback 2023-05-29 22:37:59 +05:30
MediaPipe TeamandCopybara-Service 759e9fd56e Reorganize the face stylizer test data.
PiperOrigin-RevId: 536074239
2023-05-28 19:28:14 -07:00
MediaPipe TeamandCopybara-Service 2e2b4d183e add “users” group to visibility
PiperOrigin-RevId: 536022725
2023-05-28 10:49:31 -07:00
MediaPipe TeamandCopybara-Service d4c7ed2217 Internal change
PiperOrigin-RevId: 535751178
2023-05-26 17:26:29 -07:00
Sebastian SchmidtandCopybara-Service fddc3facf0 Add FaceLandmarker Result API
PiperOrigin-RevId: 535735431
2023-05-26 16:04:47 -07:00
MediaPipe TeamandCopybara-Service e483b31fcf Internal change
PiperOrigin-RevId: 535636593
2023-05-26 09:23:37 -07:00
Prianka Liz Kariat 41d0f89fd1 Updated variable names in MPPHandLandmarkerOptionsHelpers 2023-05-26 21:06:29 +05:30
Prianka Liz Kariat 2428ba49a3 Fixed typo in MPPHandLandmarkerOptions 2023-05-26 21:02:14 +05:30
Prianka Liz Kariat 881c6e2eef Fixed typo in MPPHandLandmarkerResult 2023-05-26 21:00:59 +05:30
Prianka Liz Kariat bec7aeec22 Fixed typo in MPPHandLandmarkerOptions 2023-05-26 20:59:13 +05:30
Prianka Liz Kariat ff064e536c Added new line 2023-05-26 20:57:32 +05:30
Prianka Liz Kariat b442367fc9 Fixed formatting 2023-05-26 20:57:13 +05:30
Prianka Liz Kariat 23d97292a6 Updated face detector to use new methods from vision task runner 2023-05-26 18:49:24 +05:30
Prianka Liz Kariat 6fabc35ce7 Removed gesture recognizer implementation 2023-05-26 18:49:08 +05:30
Prianka Liz Kariat ddf4d3fbd3 Added iOS hand landmarker options helpers 2023-05-26 10:58:30 +05:30
Prianka Liz Kariat 5ad7c9fd89 Added iOS hand landmarker options 2023-05-26 10:58:12 +05:30
Prianka Liz Kariat f124cad095 Added iOS hand landmarker result 2023-05-26 10:57:58 +05:30
Copybara-Service f4337356fe Merge pull request #4465 from priankakariatyml:ios-landmark-test-cpp-utils
PiperOrigin-RevId: 535441782
2023-05-25 17:26:30 -07:00
MediaPipe TeamandCopybara-Service e2cb327060 Give an example of the expected protoType syntax
PiperOrigin-RevId: 535413303
2023-05-25 15:47:15 -07:00
MediaPipe TeamandCopybara-Service e8f2541cbd Internal update
PiperOrigin-RevId: 535376471
2023-05-25 14:03:43 -07:00
Jiuqiang TangandCopybara-Service 169bdf15b4 Make an option for adjusting the face alignment output image size, and add a "transformation_matrix" output stream of the face stylizer graph.
PiperOrigin-RevId: 535319310
2023-05-25 11:21:06 -07:00
MediaPipe TeamandCopybara-Service ea314ba455 Fix license typos.
PiperOrigin-RevId: 535309354
2023-05-25 10:53:37 -07:00
Sebastian SchmidtandCopybara-Service c7703bfb21 Add FaceLandmarkerOptions API
PiperOrigin-RevId: 535292669
2023-05-25 10:05:08 -07:00
Prianka Liz Kariat 1ec4ae44a5 Added C++ utils for parsing protos from text files for iOS tests. 2023-05-25 20:53:07 +05:30
Prianka Liz Kariat 52f3333cc1 Added MPPGesture Recognizer implementation 2023-05-25 20:44:16 +05:30
Prianka Liz Kariat e6fd39b3ee Updated the vision task runner to split the method that creates normalized rect based on ROI 2023-05-25 20:43:51 +05:30
Prianka Liz Kariat 9483ac4651 Updated iOS gesture recognizer results to initialize hand gestures with a default index 2023-05-25 20:42:24 +05:30
Khanh LeVietandCopybara-Service 952021f497 Remove unused MediaPipe Tasks Android sample
PiperOrigin-RevId: 535259478
2023-05-25 08:05:39 -07:00
MediaPipe TeamandCopybara-Service 3ac903787a Internal change
PiperOrigin-RevId: 535162357
2023-05-25 01:49:30 -07:00
Copybara-Service 034caf3d87 Merge pull request #4430 from kinaryml:python-gpu-support
PiperOrigin-RevId: 535133616
2023-05-24 23:53:00 -07:00
Sebastian SchmidtandCopybara-Service 1baf72e46b Internal change
PiperOrigin-RevId: 535131938
2023-05-24 23:45:16 -07:00
MediaPipe TeamandCopybara-Service 7800d238e9 add needed enum type for choose fuse pipeline.
PiperOrigin-RevId: 535076733
2023-05-24 20:17:54 -07:00
MediaPipe TeamandCopybara-Service c8ee09796b Internal change
PiperOrigin-RevId: 534959867
2023-05-24 13:26:53 -07:00
Copybara-Service b84e6f97dd Merge pull request #4456 from priankakariatyml:ios-code-review-fixes
PiperOrigin-RevId: 534957807
2023-05-24 13:22:31 -07:00
Sebastian SchmidtandCopybara-Service a7b81c7d10 Change "numberOfHands" property name to "numHands".
PiperOrigin-RevId: 534927982
2023-05-24 11:54:47 -07:00
Jiuqiang TangandCopybara-Service 7facc925ba Allow FaceStylizerGraph to miss base options.
Fix the color issue when the graph is running on gpu and "face alignment only" mode.

PiperOrigin-RevId: 534912498
2023-05-24 11:14:30 -07:00
Sebastian SchmidtandCopybara-Service acfaf3f1b6 Add unit test for FaceDetector iOS
PiperOrigin-RevId: 534874603
2023-05-24 09:40:08 -07:00
Sebastian SchmidtandCopybara-Service d9f316e12a Rename ObjectDetctionResult to ObjectDetectorResult
PiperOrigin-RevId: 534858600
2023-05-24 09:00:00 -07:00
Sebastian SchmidtandCopybara-Service 2017fcc9ab Add FaceDetector iOS API
PiperOrigin-RevId: 534858193
2023-05-24 08:55:03 -07:00
Prianka Liz Kariat 1aa44abcab Revert "Added support to set delegates in MPPBaseOptions"
This reverts commit 1e1693d9aa.
2023-05-24 20:25:45 +05:30
Prianka Liz Kariat 8f1a56f3c2 Fixed typos 2023-05-24 20:24:41 +05:30
Prianka Liz Kariat 1e1693d9aa Added support to set delegates in MPPBaseOptions 2023-05-24 20:24:34 +05:30
Prianka Liz Kariat e2e90dcac6 Merge branch 'master' into ios-code-review-fixes 2023-05-24 19:57:46 +05:30
Prianka Liz Kariat 69017381af Updated MPPObjectDetectorResult Helpers to return empty result instead of nil 2023-05-24 19:57:38 +05:30
MediaPipe TeamandCopybara-Service bc035d9146 This will fix the multiple typos in the tasks files.
PiperOrigin-RevId: 534679277
2023-05-23 21:49:34 -07:00
MediaPipe TeamandCopybara-Service 201b2d739d Fix c++98-compat-extra-semi warnings
PiperOrigin-RevId: 534624086
2023-05-23 18:03:29 -07:00
MediaPipe TeamandCopybara-Service 3dcfca3a73 Fix deprecated usages
* In status_builder.h to use absl::Status directly
* In type_map.h to use kTypeId.hash_code() directly

PiperOrigin-RevId: 534622923
2023-05-23 17:58:58 -07:00
Sebastian SchmidtandCopybara-Service e8ee934bf9 Use empty keypoint array for Detection if no keypoints are detected
PiperOrigin-RevId: 534572162
2023-05-23 15:10:00 -07:00
Copybara-Service 1523cc48a1 Merge pull request #4447 from priankakariatyml:ios-code-review-fixes
PiperOrigin-RevId: 534526451
2023-05-23 12:55:35 -07:00
Sebastian SchmidtandCopybara-Service 1fe78180c8 Add quality scores to Segmenter tasks
PiperOrigin-RevId: 534497957
2023-05-23 11:37:26 -07:00
Prianka Liz Kariat 3eb97ae1ff Updated Image classifier result to return empty results if packet can't be validated. 2023-05-23 20:54:42 +05:30
Prianka Liz Kariat fda001b666 Updated error tests to use XCTAssertEqualObjects 2023-05-23 19:31:14 +05:30
Sebastian SchmidtandCopybara-Service 87f525c76b Internal change
PiperOrigin-RevId: 534264040
2023-05-22 20:01:41 -07:00
Sebastian SchmidtandCopybara-Service 51730ec25c Add iOS support for MPMask
PiperOrigin-RevId: 534155657
2023-05-22 13:00:05 -07:00
MediaPipe TeamandCopybara-Service 102cffdf4c Add some helpful error messages in case GL texture creation fails.
PiperOrigin-RevId: 534029187
2023-05-22 05:03:51 -07:00
Sebastian SchmidtandCopybara-Service 7c28c5d58f Fix rendering of MPMask and MPImage clone
PiperOrigin-RevId: 533551170
2023-05-19 14:26:18 -07:00
Copybara-Service a6457d87b2 Merge pull request #4433 from priankakariatyml:ios-remove-delegate
PiperOrigin-RevId: 533472159
2023-05-19 09:24:26 -07:00
Copybara-Service 9044d62f61 Merge pull request #4422 from priankakariatyml:ios-gesture-recognizer-files
PiperOrigin-RevId: 533471803
2023-05-19 09:19:20 -07:00
Prianka Liz Kariat f219829b1d Removed support for Delegates from iOS 2023-05-19 17:42:57 +05:30
MediaPipe TeamandCopybara-Service 937a6b1422 Internal change
PiperOrigin-RevId: 533327411
2023-05-18 20:19:42 -07:00
MediaPipe TeamandCopybara-Service c248525eeb internal update
PiperOrigin-RevId: 533197055
2023-05-18 11:39:35 -07:00
MediaPipe TeamandCopybara-Service a1755044ea Internal change
PiperOrigin-RevId: 533187060
2023-05-18 11:10:42 -07:00
MediaPipe TeamandCopybara-Service 03b901a443 Internal change
PiperOrigin-RevId: 533150010
2023-05-18 09:16:35 -07:00
Kinar RandGitHub b5148c8ce3 Update setup.py 2023-05-18 18:32:45 +05:30
Kinar RandGitHub 01fdeaf1e1 Update Dockerfile 2023-05-18 18:29:22 +05:30
Kinar RandGitHub 6100f0e76e Update base_options.py 2023-05-18 18:09:39 +05:30
Kinar RandGitHub f63baaf8d2 Update BUILD 2023-05-18 18:08:04 +05:30
Kinar RandGitHub b5072c59e7 Update BUILD 2023-05-18 15:41:08 +05:30
Kinar RandGitHub 14dba421c4 Update BUILD 2023-05-18 13:23:44 +05:30
Kinar RandGitHub 620ff3508a Update BUILD 2023-05-18 12:51:08 +05:30
Kinar RandGitHub 126df20658 Included CPU binary graphs in setup.py 2023-05-18 11:00:12 +05:30
Prianka Liz Kariat bb5fcc2d64 Fixed Typos 2023-05-18 10:00:31 +05:30
Prianka Liz Kariat e905a9fe39 Removed roi methods from MPPGestureRecognizer 2023-05-18 09:52:23 +05:30
Rachel HornungandCopybara-Service 25458138a9 #MediaPipe Add ConcatenateStringVectorCalculator.
PiperOrigin-RevId: 532956844
2023-05-17 17:11:20 -07:00
MediaPipe TeamandCopybara-Service 02230f65d1 Internal change
PiperOrigin-RevId: 532934867
2023-05-17 15:54:32 -07:00
Sebastian SchmidtandCopybara-Service 1fb98f5ebd Don't double build ARM64 arch on M1 Macs
PiperOrigin-RevId: 532934646
2023-05-17 15:50:05 -07:00
Sebastian SchmidtandCopybara-Service a4d0e68bee Internal change
PiperOrigin-RevId: 532890317
2023-05-17 13:37:25 -07:00
Prianka Liz Kariat dc7c018b39 Added clearing of all graph options protos in MPPGestureRecognizerOptions Helpers 2023-05-17 22:03:10 +05:30
Prianka Liz Kariat d6d5a94845 Reverted copy of gesture recognizer result containers 2023-05-17 21:59:26 +05:30
Prianka Liz Kariat 36b7514b19 Removed srcs in MPPGestureRecognizer target 2023-05-17 21:56:31 +05:30
Prianka Liz Kariat dcb0414d4b Added MPPGestureRecognizer header 2023-05-17 21:53:25 +05:30
Prianka Liz Kariat 501b4bbc7b Added MPPGestureRecognizerResultHelpers 2023-05-17 21:52:05 +05:30
Prianka Liz Kariat ebd1545506 Added MPPGestureRecognizerOptionsHelpers 2023-05-17 21:51:40 +05:30
Prianka Liz Kariat a4c280310b Added delegates in iOS gesture recognizer options 2023-05-17 21:50:53 +05:30
Prianka Liz Kariat ae2901459d Updated property types in MPPGestureRecognizerResult 2023-05-17 21:50:11 +05:30
kinaryml 45addac249 Testing MediaPipe Python with GPU support 2023-05-17 10:55:40 +05:30
vrabaudandCopybara-Service 4f8520af10 Internal change
PiperOrigin-RevId: 532611846
2023-05-16 16:48:54 -07:00
MediaPipe TeamandCopybara-Service 5af496201b internal updating of flatbuffers
PiperOrigin-RevId: 532601578
2023-05-16 16:08:39 -07:00
MediaPipe TeamandCopybara-Service 609a57f167 Internal change
PiperOrigin-RevId: 532597768
2023-05-16 15:56:25 -07:00
Copybara-Service 7eb5cab22d Merge pull request #4397 from priankakariatyml:ios-remove-opencv-dep
PiperOrigin-RevId: 532553181
2023-05-16 13:15:53 -07:00
Sebastian SchmidtandCopybara-Service 024f782cd9 Warn users that do not invoke "close()"
PiperOrigin-RevId: 532507235
2023-05-16 10:50:38 -07:00
Sebastian SchmidtandCopybara-Service d53fbf2aeb Update links in README.md
PiperOrigin-RevId: 532506851
2023-05-16 10:45:30 -07:00
Sebastian SchmidtandCopybara-Service 8bf6c63e92 Write TFLite model to Wasm file system
PiperOrigin-RevId: 532482502
2023-05-16 09:25:44 -07:00
MediaPipe TeamandCopybara-Service d7fa4b95b5 Internal change.
PiperOrigin-RevId: 532474319
2023-05-16 08:56:30 -07:00
MediaPipe TeamandCopybara-Service e0eef9791e Internal change
PiperOrigin-RevId: 532113907
2023-05-15 08:06:33 -07:00
MediaPipe TeamandCopybara-Service fc9538533c Improve loop calculator documentation and add additional specializations
The documentation is confusing since it was unclear where e.g. BeginLoopWithIterableCalculator comes from. Also, input_to_loop_body wasn't connected to anything. loop_internal_ts is more confusing than helpful. This CL cleans up the docs. It also adds specializations for CPU image and GPU texture buffers to be used for the recompose effect.

PiperOrigin-RevId: 532083714
2023-05-15 05:58:58 -07:00
MediaPipe TeamandCopybara-Service 12ba644393 Internal change
PiperOrigin-RevId: 531582116
2023-05-12 12:57:28 -07:00
Copybara-Service c7ba201e6a Merge pull request #4372 from priankakariatyml:ios-image-classifier-async-fixes
PiperOrigin-RevId: 531517080
2023-05-12 08:50:14 -07:00
Copybara-Service 785f549130 Merge pull request #4401 from priankakariatyml:ios-typo-fixes
PiperOrigin-RevId: 531223233
2023-05-11 09:26:08 -07:00
Prianka Liz Kariat 4c32ff493e Fixed typo in MPPObjectDetectorOptions 2023-05-11 14:04:40 +05:30
Prianka Liz Kariat 419701c615 Removed opencv dependency from MPPVIsionTaskRunner 2023-05-10 13:09:44 +05:30
Prianka Liz Kariat 4a192a6d87 Updated formatting in MPPImageClassifier 2023-05-08 16:58:00 +05:30
Prianka Liz Kariat db732e2913 Updated formatting in MPPImageClassifierOptions 2023-05-08 16:57:17 +05:30
Prianka Liz Kariat 443418f6d5 Updated formatting 2023-05-08 16:45:16 +05:30
Prianka Liz Kariat 946042aca1 Reverted addition of flow limiter calculator in image classifier iOS 2023-05-08 16:33:09 +05:30
Prianka Liz Kariat 1865643486 Fixed deps in ios task BUILD file 2023-05-08 16:32:04 +05:30
Prianka Liz Kariat 26810b6b84 Reverted back to using containers and options in BUILD 2023-05-08 16:30:40 +05:30
Prianka Liz Kariat f86188f8e1 Merged with master 2023-05-08 16:24:54 +05:30
Prianka Liz Kariat 330976ce9e Added utils of containers and core to MPPTaskCommon to avoid warnings in xcode 2023-05-04 23:51:41 +05:30
Prianka Liz Kariat 47013d289e Added flow limiter calculator in MediaPipeTasksCommon 2023-05-04 23:19:12 +05:30
Prianka Liz Kariat 3df4f7db64 Updated time out for object detector 2023-05-04 20:00:29 +05:30
Prianka Liz Kariat 08282d9fd7 Updated time out for image classifier async tests 2023-05-04 19:59:39 +05:30
Prianka Liz Kariat 33ae23c53a Increased wait time for image classifier asynchronous tests 2023-05-04 19:51:54 +05:30
Prianka Liz Kariat ddd1515f88 Updated documentation 2023-05-04 19:40:15 +05:30
Prianka Liz Kariat d401439daa Updated formatting 2023-05-04 19:22:11 +05:30
Prianka Liz Kariat 1136d4d515 Updated CVPixelBuffer to support pixel format type of 32RGBA 2023-05-04 18:58:49 +05:30
Prianka Liz Kariat e47bb16544 Added validation of C++ image classification result packet in MPPImageClassifierResult+Helpers.mm 2023-05-04 16:52:58 +05:30
Prianka Liz Kariat ab4b07646c Updated MPPImageClassifier to use delegates instead of completion blocks for callback. 2023-05-04 16:43:18 +05:30
Prianka Liz Kariat 1323a5271c Added method to create unique dispatch queue names in MPPVisionTaskRunner 2023-05-04 16:39:43 +05:30
1031 changed files with 39891 additions and 9439 deletions
@@ -40,18 +40,16 @@ body:
label: Programming Language and version (e.g. C++, Python, Java)
validations:
required: true
- type: textarea
- type: input
id: current_model
attributes:
label: Describe the actual behavior
render: shell
validations:
required: true
- type: textarea
- type: input
id: expected_model
attributes:
label: Describe the expected behaviour
render: shell
validations:
required: true
- type: textarea
@@ -41,18 +41,16 @@ body:
label: Task name (e.g. Image classification, Gesture recognition etc.)
validations:
required: true
- type: textarea
- type: input
id: current_model
attributes:
label: Describe the actual behavior
render: shell
validations:
required: true
- type: textarea
- type: input
id: expected_model
attributes:
label: Describe the expected behaviour
render: shell
validations:
required: true
- type: textarea
@@ -31,18 +31,16 @@ body:
label: URL that shows the problem
validations:
required: false
- type: textarea
- type: input
id: current_model
attributes:
label: Describe the actual behavior
render: shell
validations:
required: false
- type: textarea
- type: input
id: expected_model
attributes:
label: Describe the expected behaviour
render: shell
validations:
required: false
- type: textarea
@@ -28,37 +28,33 @@ body:
- 'No'
validations:
required: false
- type: textarea
- type: input
id: behaviour
attributes:
label: Describe the feature and the current behaviour/state
render: shell
validations:
required: true
- type: textarea
- type: input
id: api_change
attributes:
label: Will this change the current API? How?
render: shell
validations:
required: false
- type: textarea
- type: input
id: benifit
attributes:
label: Who will benefit with this feature?
validations:
required: false
- type: textarea
- type: input
id: use_case
attributes:
label: Please specify the use cases for this feature
render: shell
validations:
required: true
- type: textarea
- type: input
id: info_other
attributes:
label: Any Other info
render: shell
validations:
required: false
@@ -87,14 +87,13 @@ body:
placeholder:
validations:
required: false
- type: textarea
- type: input
id: what-happened
attributes:
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)
placeholder: Tell us what you see!
value: "A bug happened!"
render: shell
validations:
required: true
- type: textarea
@@ -80,18 +80,16 @@ body:
label: Xcode & Tulsi version (if issue is related to building for iOS)
validations:
required: false
- type: textarea
- type: input
id: current_model
attributes:
label: Describe the actual behavior
render: shell
validations:
required: true
- type: textarea
- type: input
id: expected_model
attributes:
label: Describe the expected behaviour
render: shell
validations:
required: true
- type: textarea
@@ -48,18 +48,16 @@ body:
placeholder: e.g. C++, Python, Java
validations:
required: false
- type: textarea
- type: input
id: current_model
attributes:
label: Describe the actual behavior
render: shell
validations:
required: false
- type: textarea
- type: input
id: expected_model
attributes:
label: Describe the expected behaviour
render: shell
validations:
required: false
- type: textarea
+3 -4
View File
@@ -1,17 +1,16 @@
---
layout: default
layout: forward
target: https://developers.google.com/mediapipe
title: Home
nav_order: 1
---
----
**Attention:** *Thanks for your interest in MediaPipe! We have moved to
**Attention:** *We have moved to
[https://developers.google.com/mediapipe](https://developers.google.com/mediapipe)
as the primary developer documentation site for MediaPipe as of April 3, 2023.*
*This notice and web page will be removed on June 1, 2023.*
![MediaPipe](https://developers.google.com/static/mediapipe/images/home/hero_01_1920.png)
**Attention**: MediaPipe Solutions Preview is an early release. [Learn
+23 -23
View File
@@ -45,12 +45,13 @@ http_archive(
)
http_archive(
name = "rules_foreign_cc",
strip_prefix = "rules_foreign_cc-0.1.0",
url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.1.0.zip",
name = "rules_foreign_cc",
sha256 = "2a4d07cd64b0719b39a7c12218a3e507672b82a97b98c6a89d38565894cf7c51",
strip_prefix = "rules_foreign_cc-0.9.0",
url = "https://github.com/bazelbuild/rules_foreign_cc/archive/refs/tags/0.9.0.tar.gz",
)
load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies")
load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies")
rules_foreign_cc_dependencies()
@@ -72,12 +73,9 @@ http_archive(
http_archive(
name = "zlib",
build_file = "@//third_party:zlib.BUILD",
sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1",
strip_prefix = "zlib-1.2.11",
urls = [
"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
],
sha256 = "b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30",
strip_prefix = "zlib-1.2.13",
url = "http://zlib.net/fossils/zlib-1.2.13.tar.gz",
patches = [
"@//third_party:zlib.diff",
],
@@ -156,22 +154,22 @@ http_archive(
# 2020-08-21
http_archive(
name = "com_github_glog_glog",
strip_prefix = "glog-0a2e5931bd5ff22fd3bf8999eb8ce776f159cda6",
sha256 = "58c9b3b6aaa4dd8b836c0fd8f65d0f941441fb95e27212c5eeb9979cfd3592ab",
strip_prefix = "glog-3a0d4d22c5ae0b9a2216988411cfa6bf860cc372",
sha256 = "170d08f80210b82d95563f4723a15095eff1aad1863000e8eeb569c96a98fefb",
urls = [
"https://github.com/google/glog/archive/0a2e5931bd5ff22fd3bf8999eb8ce776f159cda6.zip",
"https://github.com/google/glog/archive/3a0d4d22c5ae0b9a2216988411cfa6bf860cc372.zip",
],
)
http_archive(
name = "com_github_glog_glog_no_gflags",
strip_prefix = "glog-0a2e5931bd5ff22fd3bf8999eb8ce776f159cda6",
sha256 = "58c9b3b6aaa4dd8b836c0fd8f65d0f941441fb95e27212c5eeb9979cfd3592ab",
strip_prefix = "glog-3a0d4d22c5ae0b9a2216988411cfa6bf860cc372",
sha256 = "170d08f80210b82d95563f4723a15095eff1aad1863000e8eeb569c96a98fefb",
build_file = "@//third_party:glog_no_gflags.BUILD",
urls = [
"https://github.com/google/glog/archive/0a2e5931bd5ff22fd3bf8999eb8ce776f159cda6.zip",
"https://github.com/google/glog/archive/3a0d4d22c5ae0b9a2216988411cfa6bf860cc372.zip",
],
patches = [
"@//third_party:com_github_glog_glog_9779e5ea6ef59562b030248947f787d1256132ae.diff",
"@//third_party:com_github_glog_glog.diff",
],
patch_args = [
"-p1",
@@ -266,10 +264,10 @@ http_archive(
http_archive(
name = "com_googlesource_code_re2",
sha256 = "e06b718c129f4019d6e7aa8b7631bee38d3d450dd980246bfaf493eb7db67868",
strip_prefix = "re2-fe4a310131c37f9a7e7f7816fa6ce2a8b27d65a8",
sha256 = "ef516fb84824a597c4d5d0d6d330daedb18363b5a99eda87d027e6bdd9cba299",
strip_prefix = "re2-03da4fc0857c285e3a26782f6bc8931c4c950df4",
urls = [
"https://github.com/google/re2/archive/fe4a310131c37f9a7e7f7816fa6ce2a8b27d65a8.tar.gz",
"https://github.com/google/re2/archive/03da4fc0857c285e3a26782f6bc8931c4c950df4.tar.gz",
],
)
@@ -484,9 +482,10 @@ http_archive(
)
# TensorFlow repo should always go after the other external dependencies.
# TF on 2023-04-12.
_TENSORFLOW_GIT_COMMIT = "d712c0c9e24519cc8cd3720279666720d1000eee"
_TENSORFLOW_SHA256 = "ba98de6ea5f720071246691a1536ecd5e1b1763033e8c82a1e721a06d3dfd4c1"
# TF on 2023-07-26.
_TENSORFLOW_GIT_COMMIT = "e92261fd4cec0b726692081c4d2966b75abf31dd"
# curl -L https://github.com/tensorflow/tensorflow/archive/<TENSORFLOW_GIT_COMMIT>.tar.gz | shasum -a 256
_TENSORFLOW_SHA256 = "478a229bd4ec70a5b568ac23b5ea013d9fca46a47d6c43e30365a0412b9febf4"
http_archive(
name = "org_tensorflow",
urls = [
@@ -494,6 +493,7 @@ http_archive(
],
patches = [
"@//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.
"@//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
`PrintHelloWorld()` function, defined in a [`CalculatorGraphConfig`] proto.
```C++
```c++
absl::Status PrintHelloWorld() {
// Configures a simple graph, which concatenates 2 PassThroughCalculators.
CalculatorGraphConfig config = ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
@@ -126,7 +126,7 @@ as the primary developer documentation site for MediaPipe as of April 3, 2023.*
```c++
mediapipe::Packet 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:
```
MIN_IOS_VERSION = "11.0"
MIN_IOS_VERSION = "12.0"
load(
"@build_bazel_rules_apple//apple:ios.bzl",
+3 -4
View File
@@ -1,17 +1,16 @@
---
layout: default
layout: forward
target: https://developers.google.com/mediapipe
title: Home
nav_order: 1
---
----
**Attention:** *Thanks for your interest in MediaPipe! We have moved to
**Attention:** *We have moved to
[https://developers.google.com/mediapipe](https://developers.google.com/mediapipe)
as the primary developer documentation site for MediaPipe as of April 3, 2023.*
*This notice and web page will be removed on June 1, 2023.*
![MediaPipe](https://developers.google.com/static/mediapipe/images/home/hero_01_1920.png)
**Attention**: MediaPipe Solutions Preview is an early release. [Learn
+2 -2
View File
@@ -20,9 +20,9 @@ nav_order: 1
---
**Attention:** *Thank you for your interest in MediaPipe Solutions.
As of March 1, 2023, this solution is planned to be upgraded to a new MediaPipe
As of May 10, 2023, this solution was upgraded to a new MediaPipe
Solution. For more information, see the
[MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/guide#legacy)
[MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/vision/face_detector)
site.*
----
+2 -2
View File
@@ -20,9 +20,9 @@ nav_order: 2
---
**Attention:** *Thank you for your interest in MediaPipe Solutions.
As of March 1, 2023, this solution is planned to be upgraded to a new MediaPipe
As of May 10, 2023, this solution was upgraded to a new MediaPipe
Solution. For more information, see the
[MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/guide#legacy)
[MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/vision/face_landmarker)
site.*
----
+2 -2
View File
@@ -20,9 +20,9 @@ nav_order: 3
---
**Attention:** *Thank you for your interest in MediaPipe Solutions.
As of March 1, 2023, this solution is planned to be upgraded to a new MediaPipe
As of May 10, 2023, this solution was upgraded to a new MediaPipe
Solution. For more information, see the
[MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/guide#legacy)
[MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/vision/face_landmarker)
site.*
----
+2 -2
View File
@@ -22,9 +22,9 @@ nav_order: 5
---
**Attention:** *Thank you for your interest in MediaPipe Solutions.
As of March 1, 2023, this solution is planned to be upgraded to a new MediaPipe
As of May 10, 2023, this solution was upgraded to a new MediaPipe
Solution. For more information, see the
[MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/vision/pose_landmarker/)
[MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/vision/pose_landmarker)
site.*
----
+1 -1
View File
@@ -21,7 +21,7 @@ nav_order: 1
---
**Attention:** *Thank you for your interest in MediaPipe Solutions.
As of March 1, 2023, this solution is planned to be upgraded to a new MediaPipe
As of May 10, 2023, this solution was upgraded to a new MediaPipe
Solution. For more information, see the
[MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/vision/pose_landmarker/)
site.*
+3 -11
View File
@@ -1,5 +1,6 @@
---
layout: default
layout: forward
target: https://developers.google.com/mediapipe/solutions/guide#legacy
title: MediaPipe Legacy Solutions
nav_order: 3
has_children: true
@@ -13,8 +14,7 @@ has_toc: false
{:toc}
---
**Attention:** *Thank you for your interest in MediaPipe Solutions. We have
ended support for
**Attention:** *We have ended support for
[these MediaPipe Legacy Solutions](https://developers.google.com/mediapipe/solutions/guide#legacy)
as of March 1, 2023. All other
[MediaPipe Legacy Solutions will be upgraded](https://developers.google.com/mediapipe/solutions/guide#legacy)
@@ -25,14 +25,6 @@ be provided on an as-is basis. We encourage you to check out the new MediaPipe
Solutions at:
[https://developers.google.com/mediapipe/solutions](https://developers.google.com/mediapipe/solutions)*
*This notice and web page will be removed on June 1, 2023.*
----
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>
----
MediaPipe offers open source cross-platform, customizable ML solutions for live
+138 -92
View File
@@ -14,81 +14,155 @@
licenses(["notice"]) # Apache 2.0
# Note: yes, these need to use "//external:android/crosstool", not
# @androidndk//:default_crosstool.
load("@mediapipe//mediapipe:platforms.bzl", "config_setting_and_platform")
# Generic Android
config_setting(
name = "android",
values = {"crosstool_top": "//external:android/crosstool"},
constraint_values = [
"@platforms//os:android",
],
visibility = ["//visibility:public"],
)
config_setting(
# Android x86 32-bit.
config_setting_and_platform(
name = "android_x86",
values = {
"crosstool_top": "//external:android/crosstool",
"cpu": "x86",
},
constraint_values = [
"@platforms//os:android",
"@platforms//cpu:x86_32",
],
visibility = ["//visibility:public"],
)
config_setting(
# Android x86 64-bit.
config_setting_and_platform(
name = "android_x86_64",
values = {
"crosstool_top": "//external:android/crosstool",
"cpu": "x86_64",
},
constraint_values = [
"@platforms//os:android",
"@platforms//cpu:x86_64",
],
visibility = ["//visibility:public"],
)
config_setting(
name = "android_armeabi",
values = {
"crosstool_top": "//external:android/crosstool",
"cpu": "armeabi",
},
visibility = ["//visibility:public"],
)
config_setting(
# Android ARMv7.
config_setting_and_platform(
name = "android_arm",
values = {
"crosstool_top": "//external:android/crosstool",
"cpu": "armeabi-v7a",
},
constraint_values = [
"@platforms//os:android",
"@platforms//cpu:armv7",
],
visibility = ["//visibility:public"],
)
config_setting(
# Android ARM64.
config_setting_and_platform(
name = "android_arm64",
values = {
"crosstool_top": "//external:android/crosstool",
"cpu": "arm64-v8a",
},
constraint_values = [
"@platforms//os:android",
"@platforms//cpu:arm64",
],
visibility = ["//visibility:public"],
)
# Note: this cannot just match "apple_platform_type": "macos" because that option
# defaults to "macos" even when building on Linux!
alias(
# Generic MacOS.
config_setting(
name = "macos",
actual = select({
":macos_i386": ":macos_i386",
":macos_x86_64": ":macos_x86_64",
":macos_arm64": ":macos_arm64",
"//conditions:default": ":macos_i386", # Arbitrarily chosen from above.
}),
constraint_values = [
"@platforms//os:macos",
],
visibility = ["//visibility:public"],
)
# Note: this also matches on crosstool_top so that it does not produce ambiguous
# selectors when used together with "android".
# MacOS x86 64-bit.
config_setting_and_platform(
name = "macos_x86_64",
constraint_values = [
"@platforms//os:macos",
"@platforms//cpu:x86_64",
],
visibility = ["//visibility:public"],
)
# MacOS ARM64.
config_setting_and_platform(
name = "macos_arm64",
constraint_values = [
"@platforms//os:macos",
"@platforms//cpu:arm64",
],
visibility = ["//visibility:public"],
)
# Generic iOS.
config_setting(
name = "ios",
values = {
"crosstool_top": "@bazel_tools//tools/cpp:toolchain",
"apple_platform_type": "ios",
},
constraint_values = [
"@platforms//os:ios",
],
visibility = ["//visibility:public"],
)
# iOS device ARM32.
config_setting_and_platform(
name = "ios_armv7",
constraint_values = [
"@platforms//os:ios",
"@platforms//cpu:arm",
],
visibility = ["//visibility:public"],
)
# iOS device ARM64.
config_setting_and_platform(
name = "ios_arm64",
constraint_values = [
"@platforms//os:ios",
"@platforms//cpu:arm64",
],
visibility = ["//visibility:public"],
)
# iOS device ARM64E.
config_setting_and_platform(
name = "ios_arm64e",
constraint_values = [
"@platforms//os:ios",
"@platforms//cpu:arm64e",
],
visibility = ["//visibility:public"],
)
# iOS simulator x86 32-bit.
config_setting_and_platform(
name = "ios_i386",
constraint_values = [
"@platforms//os:ios",
"@platforms//cpu:x86_32",
"@build_bazel_apple_support//constraints:simulator",
],
visibility = ["//visibility:public"],
)
# iOS simulator x86 64-bit.
config_setting_and_platform(
name = "ios_x86_64",
constraint_values = [
"@platforms//os:ios",
"@platforms//cpu:x86_64",
"@build_bazel_apple_support//constraints:simulator",
],
visibility = ["//visibility:public"],
)
# iOS simulator ARM64.
config_setting_and_platform(
name = "ios_sim_arm64",
constraint_values = [
"@platforms//os:ios",
"@platforms//cpu:arm64",
"@build_bazel_apple_support//constraints:simulator",
],
visibility = ["//visibility:public"],
)
@@ -102,52 +176,24 @@ alias(
visibility = ["//visibility:public"],
)
config_setting(
name = "macos_i386",
values = {
"apple_platform_type": "macos",
"cpu": "darwin",
},
visibility = ["//visibility:public"],
)
config_setting(
name = "macos_x86_64",
values = {
"apple_platform_type": "macos",
"cpu": "darwin_x86_64",
},
visibility = ["//visibility:public"],
)
config_setting(
name = "macos_arm64",
values = {
"apple_platform_type": "macos",
"cpu": "darwin_arm64",
},
visibility = ["//visibility:public"],
)
[
config_setting(
name = arch,
values = {"cpu": arch},
visibility = ["//visibility:public"],
)
for arch in [
"ios_i386",
"ios_x86_64",
"ios_armv7",
"ios_arm64",
"ios_arm64e",
"ios_sim_arm64",
]
]
config_setting(
# Windows 64-bit.
config_setting_and_platform(
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(
+24 -4
View File
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# Placeholder: load py_proto_library
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library")
licenses(["notice"])
@@ -145,6 +146,7 @@ cc_library(
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:status",
"//mediapipe/util:time_series_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings",
"@com_google_audio_tools//audio/dsp/mfcc",
"@eigen_archive//:eigen3",
@@ -163,8 +165,9 @@ cc_library(
"//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:logging",
"//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_audio_tools//audio/dsp:resampler",
"@com_google_audio_tools//audio/dsp:resampler_q",
@@ -185,6 +188,7 @@ cc_library(
"//mediapipe/framework/port:core_proto",
"//mediapipe/framework/port:status",
"//mediapipe/util:time_series_util",
"@com_google_absl//absl/log:absl_check",
],
alwayslink = 1,
)
@@ -219,13 +223,12 @@ cc_library(
deps = [
":time_series_framer_calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:timestamp",
"//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/util:time_series_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_audio_tools//audio/dsp:window_functions",
"@eigen_archive//:eigen3",
],
@@ -296,6 +299,7 @@ cc_test(
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:status",
"//mediapipe/util:time_series_test_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_audio_tools//audio/dsp:number_util",
"@eigen_archive//:eigen3",
],
@@ -319,6 +323,21 @@ cc_test(
],
)
cc_binary(
name = "time_series_framer_calculator_benchmark",
srcs = ["time_series_framer_calculator_benchmark.cc"],
deps = [
":time_series_framer_calculator",
":time_series_framer_calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:packet",
"//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:time_series_header_cc_proto",
"@com_google_absl//absl/log:absl_check",
"@com_google_benchmark//:benchmark",
],
)
cc_test(
name = "time_series_framer_calculator_test",
srcs = ["time_series_framer_calculator_test.cc"],
@@ -333,6 +352,7 @@ cc_test(
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:status",
"//mediapipe/util:time_series_test_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_audio_tools//audio/dsp:window_functions",
"@eigen_archive//:eigen3",
],
@@ -23,6 +23,7 @@
#include <vector>
#include "Eigen/Core"
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
@@ -138,7 +139,7 @@ absl::Status FramewiseTransformCalculatorBase::Process(CalculatorContext* cc) {
TransformFrame(input_frame, &output_frame);
// 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],
output_frame.size(), 1);
output->col(frame) = output_frame_map.cast<float>();
@@ -16,6 +16,8 @@
#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"
using audio_dsp::Resampler;
@@ -45,9 +47,9 @@ void CopyVectorToChannel(const std::vector<float>& vec, Matrix* matrix,
if (matrix->cols() == 0) {
matrix->resize(matrix->rows(), vec.size());
} 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) =
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_,
resample_options);
if (!r) {
LOG(ERROR) << "Failed to initialize resampler.";
ABSL_LOG(ERROR) << "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/time_series_header.pb.h"
#include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/util/time_series_util.h"
namespace mediapipe {
@@ -210,6 +210,23 @@ REGISTER_CALCULATOR(SpectrogramCalculator);
// Factor to convert ln(SQUARED_MAGNITUDE) to deciBels = 10.0/ln(10.0).
const float SpectrogramCalculator::kLnSquaredMagnitudeToDb = 4.342944819032518;
namespace {
std::unique_ptr<audio_dsp::WindowFunction> MakeWindowFun(
const SpectrogramCalculatorOptions::WindowType window_type) {
switch (window_type) {
// The cosine window and square root of Hann are equivalent.
case SpectrogramCalculatorOptions::COSINE:
case SpectrogramCalculatorOptions::SQRT_HANN:
return std::make_unique<audio_dsp::CosineWindow>();
case SpectrogramCalculatorOptions::HANN:
return std::make_unique<audio_dsp::HannWindow>();
case SpectrogramCalculatorOptions::HAMMING:
return std::make_unique<audio_dsp::HammingWindow>();
}
return nullptr;
}
} // namespace
absl::Status SpectrogramCalculator::Open(CalculatorContext* cc) {
SpectrogramCalculatorOptions spectrogram_options =
cc->Options<SpectrogramCalculatorOptions>();
@@ -266,28 +283,14 @@ absl::Status SpectrogramCalculator::Open(CalculatorContext* cc) {
output_scale_ = spectrogram_options.output_scale();
std::vector<double> window;
switch (spectrogram_options.window_type()) {
case SpectrogramCalculatorOptions::COSINE:
audio_dsp::CosineWindow().GetPeriodicSamples(frame_duration_samples_,
&window);
break;
case SpectrogramCalculatorOptions::HANN:
audio_dsp::HannWindow().GetPeriodicSamples(frame_duration_samples_,
&window);
break;
case SpectrogramCalculatorOptions::HAMMING:
audio_dsp::HammingWindow().GetPeriodicSamples(frame_duration_samples_,
&window);
break;
case SpectrogramCalculatorOptions::SQRT_HANN: {
audio_dsp::HannWindow().GetPeriodicSamples(frame_duration_samples_,
&window);
absl::c_transform(window, window.begin(),
[](double x) { return std::sqrt(x); });
break;
}
auto window_fun = MakeWindowFun(spectrogram_options.window_type());
if (window_fun == nullptr) {
return absl::Status(absl::StatusCode::kInvalidArgument,
absl::StrCat("Invalid window type ",
spectrogram_options.window_type()));
}
std::vector<double> window;
window_fun->GetPeriodicSamples(frame_duration_samples_, &window);
// Propagate settings down to the actual Spectrogram object.
spectrogram_generators_.clear();
@@ -68,7 +68,7 @@ message SpectrogramCalculatorOptions {
HANN = 0;
HAMMING = 1;
COSINE = 2;
SQRT_HANN = 4;
SQRT_HANN = 4; // Alias of COSINE.
}
optional WindowType window_type = 6 [default = HANN];
@@ -22,6 +22,7 @@
#include <vector>
#include "Eigen/Core"
#include "absl/log/absl_log.h"
#include "audio/dsp/number_util.h"
#include "mediapipe/calculators/audio/spectrogram_calculator.pb.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 Matrix& output_matrix = output.packets[0].Get<Matrix>();
LOG(INFO) << "Output matrix=" << output_matrix.rows() << "x"
<< output_matrix.cols();
LOG(INFO) << "First values=" << output_matrix(0, 0) << ", "
<< output_matrix(1, 0) << ", " << output_matrix(2, 0) << ", "
<< output_matrix(3, 0);
ABSL_LOG(INFO) << "Output matrix=" << output_matrix.rows() << "x"
<< output_matrix.cols();
ABSL_LOG(INFO) << "First values=" << output_matrix(0, 0) << ", "
<< output_matrix(1, 0) << ", " << output_matrix(2, 0) << ", "
<< output_matrix(3, 0);
}
BENCHMARK(BM_ProcessDC);
@@ -18,6 +18,7 @@
#include <memory>
#include <string>
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/audio/stabilized_log_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/matrix.h"
@@ -59,7 +60,7 @@ class StabilizedLogCalculator : public CalculatorBase {
output_scale_ = stabilized_log_calculator_options.output_scale();
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_;
// If the input packets have a header, propagate the header to the output.
@@ -15,19 +15,17 @@
// Defines TimeSeriesFramerCalculator.
#include <math.h>
#include <deque>
#include <memory>
#include <string>
#include <vector>
#include "Eigen/Core"
#include "absl/log/absl_check.h"
#include "audio/dsp/window_functions.h"
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/time_series_header.pb.h"
#include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/timestamp.h"
#include "mediapipe/util/time_series_util.h"
namespace mediapipe {
@@ -88,11 +86,6 @@ class TimeSeriesFramerCalculator : public CalculatorBase {
absl::Status Close(CalculatorContext* cc) override;
private:
// Adds input data to the internal buffer.
void EnqueueInput(CalculatorContext* cc);
// Constructs and emits framed output packets.
void FrameOutput(CalculatorContext* cc);
Timestamp CurrentOutputTimestamp() {
if (use_local_timestamp_) {
return current_timestamp_;
@@ -106,21 +99,13 @@ class TimeSeriesFramerCalculator : public CalculatorBase {
Timestamp::kTimestampUnitsPerSecond);
}
// Returns the timestamp of a sample on a base, which is usually the time
// stamp of a packet.
Timestamp CurrentSampleTimestamp(const Timestamp& timestamp_base,
int64_t number_of_samples) {
return timestamp_base + round(number_of_samples / sample_rate_ *
Timestamp::kTimestampUnitsPerSecond);
}
// The number of input samples to advance after the current output frame is
// emitted.
int next_frame_step_samples() const {
// All numbers are in input samples.
const int64_t current_output_frame_start = static_cast<int64_t>(
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>(
round((cumulative_output_frames_ + 1) * average_frame_step_samples_));
return next_output_frame_start - current_output_frame_start;
@@ -142,61 +127,174 @@ class TimeSeriesFramerCalculator : public CalculatorBase {
Timestamp initial_input_timestamp_;
// The current timestamp is updated along with the incoming packets.
Timestamp current_timestamp_;
int num_channels_;
// Each entry in this deque consists of a single sample, i.e. a
// single column vector, and its timestamp.
std::deque<std::pair<Matrix, Timestamp>> sample_buffer_;
// Samples are buffered in a vector of sample blocks.
class SampleBlockBuffer {
public:
// Initializes the buffer.
void Init(double sample_rate, int num_channels) {
ts_units_per_sample_ = Timestamp::kTimestampUnitsPerSecond / sample_rate;
num_channels_ = num_channels;
num_samples_ = 0;
first_block_offset_ = 0;
}
// Number of channels, equal to the number of rows in each Matrix.
int num_channels() const { return num_channels_; }
// Total number of available samples over all blocks.
int num_samples() const { return num_samples_; }
// Pushes a new block of samples on the back of the buffer with `timestamp`
// being the input timestamp of the packet containing the Matrix.
void Push(const Matrix& samples, Timestamp timestamp);
// Copies `count` samples from the front of the buffer. If there are fewer
// samples than this, the result is zero padded to have `count` samples.
// The timestamp of the last copied sample is written to *last_timestamp.
// This output is used below to update `current_timestamp_`, which is only
// used when `use_local_timestamp` is true.
Matrix CopySamples(int count, Timestamp* last_timestamp) const;
// Drops `count` samples from the front of the buffer. If `count` exceeds
// `num_samples()`, the buffer is emptied. Returns how many samples were
// dropped.
int DropSamples(int count);
private:
struct Block {
// Matrix of num_channels rows by num_samples columns, a block of possibly
// multiple samples.
Matrix samples;
// Timestamp of the first sample in the Block. This comes from the input
// packet's timestamp that contains this Matrix.
Timestamp timestamp;
Block() : timestamp(Timestamp::Unstarted()) {}
Block(const Matrix& samples, Timestamp timestamp)
: samples(samples), timestamp(timestamp) {}
int num_samples() const { return samples.cols(); }
};
std::vector<Block> blocks_;
// Number of timestamp units per sample. Used to compute timestamps as
// nth sample timestamp = base_timestamp + round(ts_units_per_sample_ * n).
double ts_units_per_sample_;
// Number of rows in each Matrix.
int num_channels_;
// The total number of samples over all blocks, equal to
// (sum_i blocks_[i].num_samples()) - first_block_offset_.
int num_samples_;
// The number of samples in the first block that have been discarded. This
// way we can cheaply represent "partially discarding" a block.
int first_block_offset_;
} sample_buffer_;
bool use_window_;
Matrix window_;
Eigen::RowVectorXf window_;
bool use_local_timestamp_;
};
REGISTER_CALCULATOR(TimeSeriesFramerCalculator);
void TimeSeriesFramerCalculator::EnqueueInput(CalculatorContext* cc) {
const Matrix& input_frame = cc->Inputs().Index(0).Get<Matrix>();
for (int i = 0; i < input_frame.cols(); ++i) {
sample_buffer_.emplace_back(std::make_pair(
input_frame.col(i), CurrentSampleTimestamp(cc->InputTimestamp(), i)));
}
void TimeSeriesFramerCalculator::SampleBlockBuffer::Push(const Matrix& samples,
Timestamp timestamp) {
num_samples_ += samples.cols();
blocks_.emplace_back(samples, timestamp);
}
void TimeSeriesFramerCalculator::FrameOutput(CalculatorContext* cc) {
while (sample_buffer_.size() >=
Matrix TimeSeriesFramerCalculator::SampleBlockBuffer::CopySamples(
int count, Timestamp* last_timestamp) const {
Matrix copied(num_channels_, count);
if (!blocks_.empty()) {
int num_copied = 0;
// First block has an offset for samples that have been discarded.
int offset = first_block_offset_;
int n;
Timestamp last_block_ts;
int last_sample_index;
for (auto it = blocks_.begin(); it != blocks_.end() && count > 0; ++it) {
n = std::min(it->num_samples() - offset, count);
// Copy `n` samples from the next block.
copied.middleCols(num_copied, n) = it->samples.middleCols(offset, n);
count -= n;
num_copied += n;
last_block_ts = it->timestamp;
last_sample_index = offset + n - 1;
offset = 0; // No samples have been discarded in subsequent blocks.
}
// Compute the timestamp of the last copied sample.
*last_timestamp =
last_block_ts + std::round(ts_units_per_sample_ * last_sample_index);
}
if (count > 0) {
copied.rightCols(count).setZero(); // Zero pad if needed.
}
return copied;
}
int TimeSeriesFramerCalculator::SampleBlockBuffer::DropSamples(int count) {
if (blocks_.empty()) {
return 0;
}
auto block_it = blocks_.begin();
if (first_block_offset_ + count < block_it->num_samples()) {
// `count` is less than the remaining samples in the first block.
first_block_offset_ += count;
num_samples_ -= count;
return count;
}
int num_samples_dropped = block_it->num_samples() - first_block_offset_;
count -= num_samples_dropped;
first_block_offset_ = 0;
for (++block_it; block_it != blocks_.end(); ++block_it) {
if (block_it->num_samples() > count) {
break;
}
num_samples_dropped += block_it->num_samples();
count -= block_it->num_samples();
}
blocks_.erase(blocks_.begin(), block_it); // Drop whole blocks.
if (!blocks_.empty()) {
first_block_offset_ = count; // Drop part of the next block.
num_samples_dropped += count;
}
num_samples_ -= num_samples_dropped;
return num_samples_dropped;
}
absl::Status TimeSeriesFramerCalculator::Process(CalculatorContext* cc) {
if (initial_input_timestamp_ == Timestamp::Unstarted()) {
initial_input_timestamp_ = cc->InputTimestamp();
current_timestamp_ = initial_input_timestamp_;
}
// Add input data to the internal buffer.
sample_buffer_.Push(cc->Inputs().Index(0).Get<Matrix>(),
cc->InputTimestamp());
// Construct and emit framed output packets.
while (sample_buffer_.num_samples() >=
frame_duration_samples_ + samples_still_to_drop_) {
while (samples_still_to_drop_ > 0) {
sample_buffer_.pop_front();
--samples_still_to_drop_;
}
sample_buffer_.DropSamples(samples_still_to_drop_);
Matrix output_frame = sample_buffer_.CopySamples(frame_duration_samples_,
&current_timestamp_);
const int frame_step_samples = next_frame_step_samples();
std::unique_ptr<Matrix> output_frame(
new Matrix(num_channels_, frame_duration_samples_));
for (int i = 0; i < std::min(frame_step_samples, frame_duration_samples_);
++i) {
output_frame->col(i) = sample_buffer_.front().first;
current_timestamp_ = sample_buffer_.front().second;
sample_buffer_.pop_front();
}
const int frame_overlap_samples =
frame_duration_samples_ - frame_step_samples;
if (frame_overlap_samples > 0) {
for (int i = 0; i < frame_overlap_samples; ++i) {
output_frame->col(i + frame_step_samples) = sample_buffer_[i].first;
current_timestamp_ = sample_buffer_[i].second;
}
} else {
samples_still_to_drop_ = -frame_overlap_samples;
}
samples_still_to_drop_ = frame_step_samples;
if (use_window_) {
*output_frame = (output_frame->array() * window_.array()).matrix();
// Apply the window to each row of output_frame.
output_frame.array().rowwise() *= window_.array();
}
cc->Outputs().Index(0).Add(output_frame.release(),
CurrentOutputTimestamp());
cc->Outputs().Index(0).AddPacket(MakePacket<Matrix>(std::move(output_frame))
.At(CurrentOutputTimestamp()));
++cumulative_output_frames_;
cumulative_completed_samples_ += frame_step_samples;
}
@@ -206,35 +304,18 @@ void TimeSeriesFramerCalculator::FrameOutput(CalculatorContext* cc) {
// fact to enable packet queueing optimizations.
cc->Outputs().Index(0).SetNextTimestampBound(CumulativeOutputTimestamp());
}
}
absl::Status TimeSeriesFramerCalculator::Process(CalculatorContext* cc) {
if (initial_input_timestamp_ == Timestamp::Unstarted()) {
initial_input_timestamp_ = cc->InputTimestamp();
current_timestamp_ = initial_input_timestamp_;
}
EnqueueInput(cc);
FrameOutput(cc);
return absl::OkStatus();
}
absl::Status TimeSeriesFramerCalculator::Close(CalculatorContext* cc) {
while (samples_still_to_drop_ > 0 && !sample_buffer_.empty()) {
sample_buffer_.pop_front();
--samples_still_to_drop_;
}
if (!sample_buffer_.empty() && pad_final_packet_) {
std::unique_ptr<Matrix> output_frame(new Matrix);
output_frame->setZero(num_channels_, frame_duration_samples_);
for (int i = 0; i < sample_buffer_.size(); ++i) {
output_frame->col(i) = sample_buffer_[i].first;
current_timestamp_ = sample_buffer_[i].second;
}
sample_buffer_.DropSamples(samples_still_to_drop_);
cc->Outputs().Index(0).Add(output_frame.release(),
CurrentOutputTimestamp());
if (sample_buffer_.num_samples() > 0 && pad_final_packet_) {
Matrix output_frame = sample_buffer_.CopySamples(frame_duration_samples_,
&current_timestamp_);
cc->Outputs().Index(0).AddPacket(MakePacket<Matrix>(std::move(output_frame))
.At(CurrentOutputTimestamp()));
}
return absl::OkStatus();
@@ -258,7 +339,7 @@ absl::Status TimeSeriesFramerCalculator::Open(CalculatorContext* cc) {
cc->Inputs().Index(0).Header(), &input_header));
sample_rate_ = input_header.sample_rate();
num_channels_ = input_header.num_channels();
sample_buffer_.Init(sample_rate_, input_header.num_channels());
frame_duration_samples_ = time_series_util::SecondsToSamples(
framer_options.frame_duration_seconds(), sample_rate_);
RET_CHECK_GT(frame_duration_samples_, 0)
@@ -312,9 +393,8 @@ absl::Status TimeSeriesFramerCalculator::Open(CalculatorContext* cc) {
}
if (use_window_) {
window_ = Matrix::Ones(num_channels_, 1) *
Eigen::Map<Eigen::MatrixXd>(window_vector.data(), 1,
frame_duration_samples_)
window_ = Eigen::Map<Eigen::RowVectorXd>(window_vector.data(),
frame_duration_samples_)
.cast<float>();
}
use_local_timestamp_ = framer_options.use_local_timestamp();
@@ -0,0 +1,93 @@
// 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.
//
// Benchmark for TimeSeriesFramerCalculator.
#include <memory>
#include <random>
#include <vector>
#include "absl/log/absl_check.h"
#include "benchmark/benchmark.h"
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/time_series_header.pb.h"
#include "mediapipe/framework/packet.h"
using ::mediapipe::Matrix;
void BM_TimeSeriesFramerCalculator(benchmark::State& state) {
constexpr float kSampleRate = 32000.0;
constexpr int kNumChannels = 2;
constexpr int kFrameDurationSeconds = 5.0;
std::mt19937 rng(0 /*seed*/);
// Input around a half second's worth of samples at a time.
std::uniform_int_distribution<int> input_size_dist(15000, 17000);
// Generate a pool of random blocks of samples up front.
std::vector<Matrix> sample_pool;
sample_pool.reserve(20);
for (int i = 0; i < 20; ++i) {
sample_pool.push_back(Matrix::Random(kNumChannels, input_size_dist(rng)));
}
std::uniform_int_distribution<int> pool_index_dist(0, sample_pool.size() - 1);
mediapipe::CalculatorGraphConfig config;
config.add_input_stream("input");
config.add_output_stream("output");
auto* node = config.add_node();
node->set_calculator("TimeSeriesFramerCalculator");
node->add_input_stream("input");
node->add_output_stream("output");
mediapipe::TimeSeriesFramerCalculatorOptions* options =
node->mutable_options()->MutableExtension(
mediapipe::TimeSeriesFramerCalculatorOptions::ext);
options->set_frame_duration_seconds(kFrameDurationSeconds);
for (auto _ : state) {
state.PauseTiming(); // Pause benchmark timing.
// Prepare input packets of random blocks of samples.
std::vector<mediapipe::Packet> input_packets;
input_packets.reserve(32);
float t = 0;
for (int i = 0; i < 32; ++i) {
auto samples =
std::make_unique<Matrix>(sample_pool[pool_index_dist(rng)]);
const int num_samples = samples->cols();
input_packets.push_back(mediapipe::Adopt(samples.release())
.At(mediapipe::Timestamp::FromSeconds(t)));
t += num_samples / kSampleRate;
}
// Initialize graph.
mediapipe::CalculatorGraph graph;
ABSL_CHECK_OK(graph.Initialize(config));
// Prepare input header.
auto header = std::make_unique<mediapipe::TimeSeriesHeader>();
header->set_sample_rate(kSampleRate);
header->set_num_channels(kNumChannels);
state.ResumeTiming(); // Resume benchmark timing.
ABSL_CHECK_OK(graph.StartRun({}, {{"input", Adopt(header.release())}}));
for (auto& packet : input_packets) {
ABSL_CHECK_OK(graph.AddPacketToInputStream("input", packet));
}
ABSL_CHECK(!graph.HasError());
ABSL_CHECK_OK(graph.CloseAllInputStreams());
ABSL_CHECK_OK(graph.WaitUntilIdle());
}
}
BENCHMARK(BM_TimeSeriesFramerCalculator);
BENCHMARK_MAIN();
@@ -19,6 +19,7 @@
#include <vector>
#include "Eigen/Core"
#include "absl/log/absl_log.h"
#include "audio/dsp/window_functions.h"
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
@@ -186,11 +187,12 @@ class TimeSeriesFramerCalculatorTest
const int num_unique_output_samples =
round((output().packets.size() - 1) * frame_step_samples) +
frame_duration_samples;
LOG(INFO) << "packets.size()=" << output().packets.size()
<< " frame_duration_samples=" << frame_duration_samples
<< " frame_step_samples=" << frame_step_samples
<< " num_input_samples_=" << num_input_samples_
<< " num_unique_output_samples=" << num_unique_output_samples;
ABSL_LOG(INFO) << "packets.size()=" << output().packets.size()
<< " frame_duration_samples=" << frame_duration_samples
<< " frame_step_samples=" << frame_step_samples
<< " num_input_samples_=" << num_input_samples_
<< " num_unique_output_samples="
<< num_unique_output_samples;
const int num_padding_samples =
num_unique_output_samples - num_input_samples_;
if (options_.pad_final_packet()) {
+23 -19
View File
@@ -117,6 +117,7 @@ mediapipe_proto_library(
"//mediapipe/framework:calculator_proto",
"//mediapipe/framework/formats:classification_proto",
"//mediapipe/framework/formats:landmark_proto",
"//mediapipe/framework/formats:matrix_data_proto",
"//mediapipe/framework/formats:time_series_header_proto",
],
)
@@ -192,17 +193,19 @@ cc_library(
"//mediapipe/framework:calculator_context",
"//mediapipe/framework:calculator_contract",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:collection_item_id",
"//mediapipe/framework:packet",
"//mediapipe/framework/formats:detection_cc_proto",
"//mediapipe/framework/formats:image",
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:rect_cc_proto",
"//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/gpu:gpu_buffer",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
],
alwayslink = 1,
)
@@ -215,18 +218,18 @@ cc_library(
"//mediapipe/framework:calculator_context",
"//mediapipe/framework:calculator_contract",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:collection_item_id",
"//mediapipe/framework/formats:classification_cc_proto",
"//mediapipe/framework/formats:detection_cc_proto",
"//mediapipe/framework/formats:image",
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:rect_cc_proto",
"//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/gpu:gpu_buffer",
"//mediapipe/util:render_data_cc_proto",
"@com_google_absl//absl/status",
"@org_tensorflow//tensorflow/lite:framework",
],
alwayslink = 1,
@@ -287,6 +290,7 @@ cc_library(
"//mediapipe/framework/api2:node",
"//mediapipe/framework/api2:port",
"//mediapipe/framework/formats:classification_cc_proto",
"//mediapipe/framework/formats:image",
"//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:integral_types",
@@ -295,8 +299,7 @@ cc_library(
"//mediapipe/util:render_data_cc_proto",
"@org_tensorflow//tensorflow/lite:framework",
] + select({
"//mediapipe/gpu:disable_gpu": [],
"//mediapipe:ios": [],
":ios_or_disable_gpu": [],
"//conditions:default": [
"@org_tensorflow//tensorflow/lite/delegates/gpu/gl:gl_buffer",
],
@@ -378,17 +381,6 @@ cc_library(
alwayslink = 1,
)
cc_library(
name = "clip_detection_vector_size_calculator",
srcs = ["clip_detection_vector_size_calculator.cc"],
deps = [
":clip_vector_size_calculator",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:detection_cc_proto",
],
alwayslink = 1,
)
cc_test(
name = "clip_vector_size_calculator_test",
srcs = ["clip_vector_size_calculator_test.cc"],
@@ -590,6 +582,7 @@ cc_library(
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:status",
"//mediapipe/framework/tool:options_util",
"@com_google_absl//absl/log:absl_check",
],
alwayslink = 1,
)
@@ -605,6 +598,7 @@ cc_test(
"//mediapipe/framework/formats:video_stream_header",
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:integral_types",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings",
],
)
@@ -637,6 +631,7 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
],
alwayslink = 1,
)
@@ -784,10 +779,11 @@ cc_library(
"//mediapipe/framework/deps:random",
"//mediapipe/framework/formats:video_stream_header",
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/framework/tool:options_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings",
],
alwayslink = 1,
@@ -843,6 +839,7 @@ cc_test(
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/tool:validate_type",
"@com_google_absl//absl/log:absl_check",
"@eigen_archive//:eigen3",
],
)
@@ -904,6 +901,7 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:classification_cc_proto",
"//mediapipe/framework/formats:detection_cc_proto",
"//mediapipe/framework/formats:image",
"//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:rect_cc_proto",
@@ -1029,6 +1027,7 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/api2:node",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
],
alwayslink = 1,
)
@@ -1067,6 +1066,7 @@ cc_test(
"//mediapipe/framework:calculator_runner",
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:parse_text_proto",
"@com_google_absl//absl/log:absl_log",
],
)
@@ -1113,6 +1113,7 @@ cc_library(
"//mediapipe/framework/api2:node",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
],
alwayslink = 1,
)
@@ -1136,6 +1137,7 @@ cc_library(
deps = [
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:timestamp",
"//mediapipe/framework/api2:node",
"//mediapipe/framework/port:status",
],
alwayslink = 1,
@@ -1164,6 +1166,7 @@ cc_library(
"//mediapipe/framework:collection_item_id",
"//mediapipe/framework/formats:classification_cc_proto",
"//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:matrix_data_cc_proto",
"//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:ret_check",
@@ -1238,6 +1241,7 @@ cc_library(
"//mediapipe/framework/formats:classification_cc_proto",
"//mediapipe/framework/formats:detection_cc_proto",
"//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:rect_cc_proto",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
],
@@ -17,10 +17,13 @@
#include <vector>
#include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/image.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/rect.pb.h"
#include "mediapipe/framework/formats/tensor.h"
#include "mediapipe/gpu/gpu_buffer.h"
namespace mediapipe {
@@ -60,4 +63,22 @@ REGISTER_CALCULATOR(BeginLoopUint64tCalculator);
typedef BeginLoopCalculator<std::vector<Tensor>> BeginLoopTensorCalculator;
REGISTER_CALCULATOR(BeginLoopTensorCalculator);
// A calculator to process std::vector<mediapipe::ImageFrame>.
typedef BeginLoopCalculator<std::vector<ImageFrame>>
BeginLoopImageFrameCalculator;
REGISTER_CALCULATOR(BeginLoopImageFrameCalculator);
// A calculator to process std::vector<mediapipe::GpuBuffer>.
typedef BeginLoopCalculator<std::vector<GpuBuffer>>
BeginLoopGpuBufferCalculator;
REGISTER_CALCULATOR(BeginLoopGpuBufferCalculator);
// A calculator to process std::vector<mediapipe::Image>.
typedef BeginLoopCalculator<std::vector<Image>> BeginLoopImageCalculator;
REGISTER_CALCULATOR(BeginLoopImageCalculator);
// A calculator to process std::vector<float>.
typedef BeginLoopCalculator<std::vector<float>> BeginLoopFloatCalculator;
REGISTER_CALCULATOR(BeginLoopFloatCalculator);
} // namespace mediapipe
@@ -15,47 +15,57 @@
#ifndef MEDIAPIPE_CALCULATORS_CORE_BEGIN_LOOP_CALCULATOR_H_
#define MEDIAPIPE_CALCULATORS_CORE_BEGIN_LOOP_CALCULATOR_H_
#include "absl/status/status.h"
#include "mediapipe/framework/calculator_context.h"
#include "mediapipe/framework/calculator_contract.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/collection_item_id.h"
#include "mediapipe/framework/packet.h"
#include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/status_macros.h"
namespace mediapipe {
// Calculator for implementing loops on iterable collections inside a MediaPipe
// graph.
// graph. Assume InputIterT is an iterable for type InputT, and OutputIterT is
// an iterable for type OutputT, e.g. vector<InputT> and vector<OutputT>.
// First, instantiate specializations in the loop calculators' implementations
// if missing:
// BeginLoopInputTCalculator = BeginLoopCalculator<InputIterT>
// EndLoopOutputTCalculator = EndLoopCalculator<OutputIterT>
// Then, the following graph transforms an item of type InputIterT to an
// OutputIterT by applying InputToOutputConverter to every element:
//
// It is designed to be used like:
//
// node {
// calculator: "BeginLoopWithIterableCalculator"
// input_stream: "ITERABLE:input_iterable" # IterableT @ext_ts
// output_stream: "ITEM:input_element" # ItemT @loop_internal_ts
// output_stream: "BATCH_END:ext_ts" # Timestamp @loop_internal_ts
// node { # Type @timestamp
// calculator: "BeginLoopInputTCalculator"
// input_stream: "ITERABLE:input_iterable" # InputIterT @iterable_ts
// input_stream: "CLONE:extra_input" # ExtraT @extra_ts
// output_stream: "ITEM:input_iterator" # InputT @loop_internal_ts
// output_stream: "CLONE:cloned_extra_input" # ExtraT @loop_internal_ts
// output_stream: "BATCH_END:iterable_ts" # Timestamp @loop_internal_ts
// }
//
// node {
// calculator: "ElementToBlaConverterSubgraph"
// input_stream: "ITEM:input_to_loop_body" # ItemT @loop_internal_ts
// output_stream: "BLA:output_of_loop_body" # ItemU @loop_internal_ts
// calculator: "InputToOutputConverter"
// input_stream: "INPUT:input_iterator" # InputT @loop_internal_ts
// input_stream: "EXTRA:cloned_extra_input" # ExtraT @loop_internal_ts
// output_stream: "OUTPUT:output_iterator" # OutputT @loop_internal_ts
// }
//
// node {
// calculator: "EndLoopWithOutputCalculator"
// input_stream: "ITEM:output_of_loop_body" # ItemU @loop_internal_ts
// input_stream: "BATCH_END:ext_ts" # Timestamp @loop_internal_ts
// output_stream: "ITERABLE:aggregated_result" # IterableU @ext_ts
// calculator: "EndLoopOutputTCalculator"
// input_stream: "ITEM:output_iterator" # OutputT @loop_internal_ts
// input_stream: "BATCH_END:iterable_ts" # Timestamp @loop_internal_ts
// output_stream: "ITERABLE:output_iterable" # OutputIterT @iterable_ts
// }
//
// The resulting 'output_iterable' has the same timestamp as 'input_iterable'.
// The output packets of this calculator are part of the loop body and have
// loop-internal timestamps that are unrelated to the input iterator timestamp.
//
// Input streams tagged with "CLONE" are cloned to the corresponding output
// streams at loop timestamps. This ensures that a MediaPipe graph or sub-graph
// can run multiple times, once per element in the "ITERABLE" for each pakcet
// clone of the packets in the "CLONE" input streams.
// streams at loop-internal timestamps. This ensures that a MediaPipe graph or
// sub-graph can run multiple times, once per element in the "ITERABLE" for each
// packet clone of the packets in the "CLONE" input streams. Think of CLONEd
// inputs as loop-wide constants.
template <typename IterableT>
class BeginLoopCalculator : public CalculatorBase {
using ItemT = typename IterableT::value_type;
@@ -17,6 +17,7 @@
#include <vector>
#include "mediapipe/framework/formats/classification.pb.h"
#include "mediapipe/framework/formats/image.h"
#include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/tensor.h"
#include "mediapipe/framework/port/integral_types.h"
@@ -55,6 +56,10 @@ MEDIAPIPE_REGISTER_NODE(ConcatenateUInt64VectorCalculator);
typedef ConcatenateVectorCalculator<bool> ConcatenateBoolVectorCalculator;
MEDIAPIPE_REGISTER_NODE(ConcatenateBoolVectorCalculator);
typedef ConcatenateVectorCalculator<std::string>
ConcatenateStringVectorCalculator;
MEDIAPIPE_REGISTER_NODE(ConcatenateStringVectorCalculator);
// Example config:
// node {
// calculator: "ConcatenateTfLiteTensorVectorCalculator"
@@ -100,4 +105,7 @@ typedef ConcatenateVectorCalculator<mediapipe::RenderData>
ConcatenateRenderDataVectorCalculator;
MEDIAPIPE_REGISTER_NODE(ConcatenateRenderDataVectorCalculator);
typedef ConcatenateVectorCalculator<mediapipe::Image>
ConcatenateImageVectorCalculator;
MEDIAPIPE_REGISTER_NODE(ConcatenateImageVectorCalculator);
} // namespace mediapipe
@@ -30,13 +30,15 @@ namespace mediapipe {
typedef ConcatenateVectorCalculator<int> TestConcatenateIntVectorCalculator;
MEDIAPIPE_REGISTER_NODE(TestConcatenateIntVectorCalculator);
void AddInputVector(int index, const std::vector<int>& input, int64_t timestamp,
template <typename T>
void AddInputVector(int index, const std::vector<T>& input, int64_t timestamp,
CalculatorRunner* runner) {
runner->MutableInputs()->Index(index).packets.push_back(
MakePacket<std::vector<int>>(input).At(Timestamp(timestamp)));
MakePacket<std::vector<T>>(input).At(Timestamp(timestamp)));
}
void AddInputVectors(const std::vector<std::vector<int>>& inputs,
template <typename T>
void AddInputVectors(const std::vector<std::vector<T>>& inputs,
int64_t timestamp, CalculatorRunner* runner) {
for (int i = 0; i < inputs.size(); ++i) {
AddInputVector(i, inputs[i], timestamp, runner);
@@ -382,6 +384,23 @@ TEST(ConcatenateFloatVectorCalculatorTest, OneEmptyStreamNoOutput) {
EXPECT_EQ(0, outputs.size());
}
TEST(ConcatenateStringVectorCalculatorTest, OneTimestamp) {
CalculatorRunner runner("ConcatenateStringVectorCalculator",
/*options_string=*/"", /*num_inputs=*/3,
/*num_outputs=*/1, /*num_side_packets=*/0);
std::vector<std::vector<std::string>> inputs = {
{"a", "b"}, {"c"}, {"d", "e", "f"}};
AddInputVectors(inputs, /*timestamp=*/1, &runner);
MP_ASSERT_OK(runner.Run());
const std::vector<Packet>& outputs = runner.Outputs().Index(0).packets;
EXPECT_EQ(1, outputs.size());
EXPECT_EQ(Timestamp(1), outputs[0].Timestamp());
std::vector<std::string> expected_vector = {"a", "b", "c", "d", "e", "f"};
EXPECT_EQ(expected_vector, outputs[0].Get<std::vector<std::string>>());
}
typedef ConcatenateVectorCalculator<std::unique_ptr<int>>
TestConcatenateUniqueIntPtrCalculator;
MEDIAPIPE_REGISTER_NODE(TestConcatenateUniqueIntPtrCalculator);
@@ -19,6 +19,7 @@
#include "mediapipe/framework/collection_item_id.h"
#include "mediapipe/framework/formats/classification.pb.h"
#include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/matrix_data.pb.h"
#include "mediapipe/framework/formats/time_series_header.pb.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/integral_types.h"
@@ -85,8 +86,12 @@ class ConstantSidePacketCalculator : public CalculatorBase {
packet.Set<LandmarkList>();
} else if (packet_options.has_double_value()) {
packet.Set<double>();
} else if (packet_options.has_matrix_data_value()) {
packet.Set<MatrixData>();
} else if (packet_options.has_time_series_header_value()) {
packet.Set<TimeSeriesHeader>();
} else if (packet_options.has_int64_value()) {
packet.Set<int64_t>();
} else {
return absl::InvalidArgumentError(
"None of supported values were specified in options.");
@@ -121,9 +126,13 @@ class ConstantSidePacketCalculator : public CalculatorBase {
MakePacket<LandmarkList>(packet_options.landmark_list_value()));
} else if (packet_options.has_double_value()) {
packet.Set(MakePacket<double>(packet_options.double_value()));
} else if (packet_options.has_matrix_data_value()) {
packet.Set(MakePacket<MatrixData>(packet_options.matrix_data_value()));
} else if (packet_options.has_time_series_header_value()) {
packet.Set(MakePacket<TimeSeriesHeader>(
packet_options.time_series_header_value()));
} else if (packet_options.has_int64_value()) {
packet.Set(MakePacket<int64_t>(packet_options.int64_value()));
} else {
return absl::InvalidArgumentError(
"None of supported values were specified in options.");
@@ -19,6 +19,7 @@ package mediapipe;
import "mediapipe/framework/calculator.proto";
import "mediapipe/framework/formats/classification.proto";
import "mediapipe/framework/formats/landmark.proto";
import "mediapipe/framework/formats/matrix_data.proto";
import "mediapipe/framework/formats/time_series_header.proto";
message ConstantSidePacketCalculatorOptions {
@@ -29,14 +30,16 @@ message ConstantSidePacketCalculatorOptions {
message ConstantSidePacket {
oneof value {
int32 int_value = 1;
uint64 uint64_value = 5;
int64 int64_value = 11;
float float_value = 2;
double double_value = 9;
bool bool_value = 3;
string string_value = 4;
uint64 uint64_value = 5;
ClassificationList classification_list_value = 6;
LandmarkList landmark_list_value = 7;
double double_value = 9;
TimeSeriesHeader time_series_header_value = 10;
MatrixData matrix_data_value = 12;
}
}
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdint>
#include <string>
#include "absl/strings/string_view.h"
@@ -58,6 +59,7 @@ TEST(ConstantSidePacketCalculatorTest, EveryPossibleType) {
DoTestSingleSidePacket("{ float_value: 6.5f }", 6.5f);
DoTestSingleSidePacket("{ bool_value: true }", true);
DoTestSingleSidePacket<std::string>(R"({ string_value: "str" })", "str");
DoTestSingleSidePacket<int64_t>("{ int64_value: 63 }", 63);
}
TEST(ConstantSidePacketCalculatorTest, MultiplePackets) {
@@ -14,15 +14,19 @@
#include "mediapipe/calculators/core/end_loop_calculator.h"
#include <array>
#include <utility>
#include <vector>
#include "mediapipe/framework/formats/classification.pb.h"
#include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/image.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/rect.pb.h"
#include "mediapipe/framework/formats/tensor.h"
#include "mediapipe/gpu/gpu_buffer.h"
#include "mediapipe/util/render_data.pb.h"
#include "tensorflow/lite/interpreter.h"
@@ -68,8 +72,22 @@ REGISTER_CALCULATOR(EndLoopMatrixCalculator);
typedef EndLoopCalculator<std::vector<Tensor>> EndLoopTensorCalculator;
REGISTER_CALCULATOR(EndLoopTensorCalculator);
typedef EndLoopCalculator<std::vector<ImageFrame>> EndLoopImageFrameCalculator;
REGISTER_CALCULATOR(EndLoopImageFrameCalculator);
typedef EndLoopCalculator<std::vector<GpuBuffer>> EndLoopGpuBufferCalculator;
REGISTER_CALCULATOR(EndLoopGpuBufferCalculator);
typedef EndLoopCalculator<std::vector<::mediapipe::Image>>
EndLoopImageCalculator;
REGISTER_CALCULATOR(EndLoopImageCalculator);
typedef EndLoopCalculator<std::vector<std::array<float, 16>>>
EndLoopAffineMatrixCalculator;
REGISTER_CALCULATOR(EndLoopAffineMatrixCalculator);
typedef EndLoopCalculator<std::vector<std::pair<int, int>>>
EndLoopImageSizeCalculator;
REGISTER_CALCULATOR(EndLoopImageSizeCalculator);
} // namespace mediapipe
@@ -17,13 +17,11 @@
#include <type_traits>
#include "absl/status/status.h"
#include "mediapipe/framework/calculator_context.h"
#include "mediapipe/framework/calculator_contract.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/collection_item_id.h"
#include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
namespace mediapipe {
@@ -33,27 +31,7 @@ namespace mediapipe {
// from the "BATCH_END" tagged input stream, it emits the aggregated results
// at the original timestamp contained in the "BATCH_END" input stream.
//
// It is designed to be used like:
//
// node {
// calculator: "BeginLoopWithIterableCalculator"
// input_stream: "ITERABLE:input_iterable" # IterableT @ext_ts
// output_stream: "ITEM:input_element" # ItemT @loop_internal_ts
// output_stream: "BATCH_END:ext_ts" # Timestamp @loop_internal_ts
// }
//
// node {
// calculator: "ElementToBlaConverterSubgraph"
// input_stream: "ITEM:input_to_loop_body" # ItemT @loop_internal_ts
// output_stream: "BLA:output_of_loop_body" # ItemU @loop_internal_ts
// }
//
// node {
// calculator: "EndLoopWithOutputCalculator"
// input_stream: "ITEM:output_of_loop_body" # ItemU @loop_internal_ts
// input_stream: "BATCH_END:ext_ts" # Timestamp @loop_internal_ts
// output_stream: "ITERABLE:aggregated_result" # IterableU @ext_ts
// }
// See BeginLoopCalculator for a usage example.
template <typename IterableT>
class EndLoopCalculator : public CalculatorBase {
using ItemT = typename IterableT::value_type;
@@ -79,7 +57,7 @@ class EndLoopCalculator : public CalculatorBase {
}
// 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
// not copiable, then an error will be returned.
// not copyable, then an error will be returned.
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()));
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/log/absl_log.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/port/gtest.h"
@@ -356,18 +357,18 @@ TEST_F(GateCalculatorTest, AllowWithStateChangeNoDataStreams) {
RunTimeStepWithoutDataStream(kTimestampValue2, "ALLOW", true);
constexpr int64_t kTimestampValue3 = 45;
RunTimeStepWithoutDataStream(kTimestampValue3, "ALLOW", false);
LOG(INFO) << "a";
ABSL_LOG(INFO) << "a";
const std::vector<Packet>& output =
runner()->Outputs().Get("STATE_CHANGE", 0).packets;
LOG(INFO) << "s";
ABSL_LOG(INFO) << "s";
ASSERT_EQ(2, output.size());
LOG(INFO) << "d";
ABSL_LOG(INFO) << "d";
EXPECT_EQ(kTimestampValue1, output[0].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(false, output[1].Get<bool>()); // Disallow.
LOG(INFO) << "g";
ABSL_LOG(INFO) << "g";
}
TEST_F(GateCalculatorTest, DisallowWithStateChange) {
@@ -17,6 +17,7 @@
#include "mediapipe/framework/formats/classification.pb.h"
#include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/rect.pb.h"
namespace mediapipe {
namespace api2 {
@@ -37,5 +38,12 @@ using GetDetectionVectorItemCalculator =
GetVectorItemCalculator<mediapipe::Detection>;
REGISTER_CALCULATOR(GetDetectionVectorItemCalculator);
using GetNormalizedRectVectorItemCalculator =
GetVectorItemCalculator<NormalizedRect>;
REGISTER_CALCULATOR(GetNormalizedRectVectorItemCalculator);
using GetRectVectorItemCalculator = GetVectorItemCalculator<Rect>;
REGISTER_CALCULATOR(GetRectVectorItemCalculator);
} // namespace api2
} // namespace mediapipe
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/log/absl_log.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/ret_check.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()) {
cc->Outputs().Index(0).AddPacket(packet);
} else {
LOG_FIRST_N(WARNING, 5)
ABSL_LOG_FIRST_N(WARNING, 5)
<< "Dropping a packet with timestamp " << packet.Timestamp();
}
if (cc->Outputs().NumEntries() >= 2) {
@@ -16,6 +16,7 @@
#include <vector>
#include "Eigen/Core"
#include "absl/log/absl_check.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/formats/matrix.h"
@@ -209,7 +210,7 @@ TEST(MatrixMultiplyCalculatorTest, Multiply) {
MatrixFromTextProto(kSamplesText, &samples);
Matrix 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) {
// 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
// limitations under the License.
#include "absl/log/absl_log.h"
#include "mediapipe/framework/api2/node.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/ret_check.h"
@@ -53,7 +54,7 @@ class MergeCalculator : public Node {
static absl::Status UpdateContract(CalculatorContract* cc) {
RET_CHECK_GT(kIn(cc).Count(), 0) << "Needs at least one input stream";
if (kIn(cc).Count() == 1) {
LOG(WARNING)
ABSL_LOG(WARNING)
<< "MergeCalculator expects multiple input streams to merge but is "
"receiving only one. Make sure the calculator is configured "
"correctly or consider removing this calculator to reduce "
@@ -72,8 +73,8 @@ class MergeCalculator : public Node {
}
}
LOG(WARNING) << "Empty input packets at timestamp "
<< cc->InputTimestamp().Value();
ABSL_LOG(WARNING) << "Empty input packets at timestamp "
<< cc->InputTimestamp().Value();
return absl::OkStatus();
}
@@ -16,6 +16,9 @@
#include <memory>
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
namespace {
// 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) {
@@ -177,7 +180,7 @@ PacketResamplerCalculator::GetSamplingStrategy(
const PacketResamplerCalculatorOptions& options) {
if (options.reproducible_sampling()) {
if (!options.jitter_with_reflection()) {
LOG(WARNING)
ABSL_LOG(WARNING)
<< "reproducible_sampling enabled w/ jitter_with_reflection "
"disabled. "
<< "reproducible_sampling always uses jitter with reflection, "
@@ -200,15 +203,15 @@ PacketResamplerCalculator::GetSamplingStrategy(
Timestamp PacketResamplerCalculator::PeriodIndexToTimestamp(
int64_t index) const {
CHECK_EQ(jitter_, 0.0);
CHECK_NE(first_timestamp_, Timestamp::Unset());
ABSL_CHECK_EQ(jitter_, 0.0);
ABSL_CHECK_NE(first_timestamp_, Timestamp::Unset());
return first_timestamp_ + TimestampDiffFromSeconds(index / frame_rate_);
}
int64_t PacketResamplerCalculator::TimestampToPeriodIndex(
Timestamp timestamp) const {
CHECK_EQ(jitter_, 0.0);
CHECK_NE(first_timestamp_, Timestamp::Unset());
ABSL_CHECK_EQ(jitter_, 0.0);
ABSL_CHECK_NE(first_timestamp_, Timestamp::Unset());
return MathUtil::SafeRound<int64_t, double>(
(timestamp - first_timestamp_).Seconds() * frame_rate_);
}
@@ -229,13 +232,15 @@ absl::Status LegacyJitterWithReflectionStrategy::Open(CalculatorContext* cc) {
if (resampler_options.output_header() !=
PacketResamplerCalculatorOptions::NONE) {
LOG(WARNING) << "VideoHeader::frame_rate holds the target value and not "
"the actual value.";
ABSL_LOG(WARNING)
<< "VideoHeader::frame_rate holds the target value and not "
"the actual value.";
}
if (calculator_->flush_last_packet_) {
LOG(WARNING) << "PacketResamplerCalculatorOptions.flush_last_packet is "
"ignored, because we are adding jitter.";
ABSL_LOG(WARNING)
<< "PacketResamplerCalculatorOptions.flush_last_packet is "
"ignored, because we are adding jitter.";
}
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) {
if (!packet_reservoir_->IsEmpty()) {
LOG(INFO) << "Emitting pack from reservoir.";
ABSL_LOG(INFO) << "Emitting pack from reservoir.";
calculator_->OutputWithinLimits(cc, packet_reservoir_->GetSample());
}
return absl::OkStatus();
@@ -285,7 +290,7 @@ absl::Status LegacyJitterWithReflectionStrategy::Process(
if (calculator_->frame_time_usec_ <
(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.";
}
@@ -340,8 +345,8 @@ void LegacyJitterWithReflectionStrategy::UpdateNextOutputTimestampWithJitter() {
next_output_timestamp_ = Timestamp(ReflectBetween(
next_output_timestamp_.Value(), next_output_timestamp_min_.Value(),
next_output_timestamp_max_.Value()));
CHECK_GE(next_output_timestamp_, next_output_timestamp_min_);
CHECK_LT(next_output_timestamp_, next_output_timestamp_max_);
ABSL_CHECK_GE(next_output_timestamp_, next_output_timestamp_min_);
ABSL_CHECK_LT(next_output_timestamp_, next_output_timestamp_max_);
}
absl::Status ReproducibleJitterWithReflectionStrategy::Open(
@@ -352,13 +357,15 @@ absl::Status ReproducibleJitterWithReflectionStrategy::Open(
if (resampler_options.output_header() !=
PacketResamplerCalculatorOptions::NONE) {
LOG(WARNING) << "VideoHeader::frame_rate holds the target value and not "
"the actual value.";
ABSL_LOG(WARNING)
<< "VideoHeader::frame_rate holds the target value and not "
"the actual value.";
}
if (calculator_->flush_last_packet_) {
LOG(WARNING) << "PacketResamplerCalculatorOptions.flush_last_packet is "
"ignored, because we are adding jitter.";
ABSL_LOG(WARNING)
<< "PacketResamplerCalculatorOptions.flush_last_packet is "
"ignored, because we are adding jitter.";
}
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
// being emitted twice. Upsampling and jitter doesn't make much sense
// but does technically work.
LOG_FIRST_N(WARNING, 2)
ABSL_LOG_FIRST_N(WARNING, 2)
<< "Adding jitter is not very useful when upsampling.";
}
@@ -499,13 +506,15 @@ absl::Status JitterWithoutReflectionStrategy::Open(CalculatorContext* cc) {
if (resampler_options.output_header() !=
PacketResamplerCalculatorOptions::NONE) {
LOG(WARNING) << "VideoHeader::frame_rate holds the target value and not "
"the actual value.";
ABSL_LOG(WARNING)
<< "VideoHeader::frame_rate holds the target value and not "
"the actual value.";
}
if (calculator_->flush_last_packet_) {
LOG(WARNING) << "PacketResamplerCalculatorOptions.flush_last_packet is "
"ignored, because we are adding jitter.";
ABSL_LOG(WARNING)
<< "PacketResamplerCalculatorOptions.flush_last_packet is "
"ignored, because we are adding jitter.";
}
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_ <
(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.";
}
@@ -13,7 +13,6 @@
#include "mediapipe/framework/deps/random_base.h"
#include "mediapipe/framework/formats/video_stream_header.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/status.h"
#include "mediapipe/framework/port/status_macros.h"
@@ -17,6 +17,7 @@
#include <cmath> // for ceil
#include <memory>
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/core/packet_thinner_calculator.pb.h"
#include "mediapipe/framework/calculator_context.h"
#include "mediapipe/framework/calculator_framework.h"
@@ -160,8 +161,8 @@ absl::Status PacketThinnerCalculator::Open(CalculatorContext* cc) {
thinner_type_ = options.thinner_type();
// This check enables us to assume only two thinner types exist in Process()
CHECK(thinner_type_ == PacketThinnerCalculatorOptions::ASYNC ||
thinner_type_ == PacketThinnerCalculatorOptions::SYNC)
ABSL_CHECK(thinner_type_ == PacketThinnerCalculatorOptions::ASYNC ||
thinner_type_ == PacketThinnerCalculatorOptions::SYNC)
<< "Unsupported thinner type.";
if (thinner_type_ == PacketThinnerCalculatorOptions::ASYNC) {
@@ -177,7 +178,8 @@ absl::Status PacketThinnerCalculator::Open(CalculatorContext* cc) {
} else {
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()) {
start_time_ = Timestamp(options.start_time());
@@ -189,7 +191,7 @@ absl::Status PacketThinnerCalculator::Open(CalculatorContext* cc) {
end_time_ =
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";
sync_output_timestamps_ = options.sync_output_timestamps();
@@ -232,7 +234,7 @@ absl::Status PacketThinnerCalculator::Close(CalculatorContext* cc) {
// Emit any saved packets before quitting.
if (!saved_packet_.IsEmpty()) {
// Only sync thinner should have saved packets.
CHECK_EQ(PacketThinnerCalculatorOptions::SYNC, thinner_type_);
ABSL_CHECK_EQ(PacketThinnerCalculatorOptions::SYNC, thinner_type_);
if (sync_output_timestamps_) {
cc->Outputs().Index(0).AddPacket(
saved_packet_.At(NearestSyncTimestamp(saved_packet_.Timestamp())));
@@ -269,7 +271,7 @@ absl::Status PacketThinnerCalculator::SyncThinnerProcess(
const Timestamp saved_sync = NearestSyncTimestamp(saved);
const Timestamp now = cc->InputTimestamp();
const Timestamp now_sync = NearestSyncTimestamp(now);
CHECK_LE(saved_sync, now_sync);
ABSL_CHECK_LE(saved_sync, now_sync);
if (saved_sync == now_sync) {
// Saved Packet is in same interval as current packet.
// 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 {
CHECK_NE(start_time_, Timestamp::Unset())
ABSL_CHECK_NE(start_time_, Timestamp::Unset())
<< "Method only valid for sync thinner calculator.";
// 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 start64 = start_time_.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).
int64_t sync64 =
(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
<< "; sync64: " << sync64;
@@ -16,6 +16,7 @@
#include <string>
#include <vector>
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h"
#include "mediapipe/calculators/core/packet_thinner_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
@@ -70,7 +71,7 @@ class SimpleRunner : public CalculatorRunner {
}
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;
}
};
@@ -123,7 +123,10 @@ class PreviousLoopbackCalculator : public Node {
// However, LOOP packet is empty.
kPrevLoop(cc).SetNextTimestampBound(main_spec.timestamp + 1);
} else {
kPrevLoop(cc).Send(loop_candidate.At(main_spec.timestamp));
// Avoids sending leftovers to a stream that's already closed.
if (!kPrevLoop(cc).IsClosed()) {
kPrevLoop(cc).Send(loop_candidate.At(main_spec.timestamp));
}
}
loop_packets_.pop_front();
main_packet_specs_.pop_front();
@@ -14,6 +14,7 @@
#include <deque>
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/core/sequence_shift_calculator.pb.h"
#include "mediapipe/framework/api2/node.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()));
packet_cache_.pop_front();
} 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.
packet_cache_.push_back(kIn(cc).packet());
@@ -18,6 +18,7 @@
#include "mediapipe/framework/formats/classification.pb.h"
#include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/image.h"
#include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/rect.pb.h"
@@ -86,4 +87,12 @@ REGISTER_CALCULATOR(SplitUint64tVectorCalculator);
typedef SplitVectorCalculator<float, false> SplitFloatVectorCalculator;
REGISTER_CALCULATOR(SplitFloatVectorCalculator);
typedef SplitVectorCalculator<mediapipe::Image, false>
SplitImageVectorCalculator;
REGISTER_CALCULATOR(SplitImageVectorCalculator);
typedef SplitVectorCalculator<std::array<float, 16>, false>
SplitAffineMatrixVectorCalculator;
REGISTER_CALCULATOR(SplitAffineMatrixVectorCalculator);
} // namespace mediapipe
@@ -12,11 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "mediapipe/framework/api2/node.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/timestamp.h"
namespace mediapipe {
namespace api2 {
// A calculator that takes a packet of an input stream and converts it to an
// output side packet. This calculator only works under the assumption that the
@@ -28,21 +30,21 @@ namespace mediapipe {
// input_stream: "stream"
// output_side_packet: "side_packet"
// }
class StreamToSidePacketCalculator : public mediapipe::CalculatorBase {
class StreamToSidePacketCalculator : public Node {
public:
static absl::Status GetContract(mediapipe::CalculatorContract* cc) {
cc->Inputs().Index(0).SetAny();
cc->OutputSidePackets().Index(0).SetAny();
return absl::OkStatus();
}
static constexpr Input<AnyType>::Optional kIn{""};
static constexpr SideOutput<SameType<kIn>> kOut{""};
MEDIAPIPE_NODE_CONTRACT(kIn, kOut);
absl::Status Process(mediapipe::CalculatorContext* cc) override {
mediapipe::Packet& packet = cc->Inputs().Index(0).Value();
cc->OutputSidePackets().Index(0).Set(
packet.At(mediapipe::Timestamp::Unset()));
kOut(cc).Set(
kIn(cc).packet().As<AnyType>().At(mediapipe::Timestamp::Unset()));
return absl::OkStatus();
}
};
REGISTER_CALCULATOR(StreamToSidePacketCalculator);
MEDIAPIPE_REGISTER_NODE(StreamToSidePacketCalculator);
} // namespace api2
} // namespace mediapipe
+50 -4
View File
@@ -97,6 +97,7 @@ cc_library(
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:source_location",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
],
alwayslink = 1,
)
@@ -125,6 +126,7 @@ cc_library(
"//mediapipe/framework/port:opencv_imgcodecs",
"//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
],
alwayslink = 1,
)
@@ -135,7 +137,6 @@ cc_library(
deps = [
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:image_frame_opencv",
"//mediapipe/framework/port:opencv_imgcodecs",
"//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:status",
],
@@ -152,11 +153,11 @@ cc_library(
"//mediapipe/framework/formats:image_format_cc_proto",
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/formats:image_frame_opencv",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:opencv_core",
"//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:status",
"//mediapipe/framework/port:vector",
"@com_google_absl//absl/log:absl_log",
] + select({
"//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [
@@ -203,6 +204,7 @@ cc_library(
"//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:status",
"//mediapipe/framework/port:vector",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings",
] + select({
"//mediapipe/gpu:disable_gpu": [],
@@ -262,9 +264,12 @@ cc_library(
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/gpu:scale_mode_cc_proto",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
] + select({
"//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [
"//mediapipe/gpu:gl_base_hdr",
"//mediapipe/gpu:gl_calculator_helper",
"//mediapipe/gpu:gl_quad_renderer",
"//mediapipe/gpu:gl_simple_shaders",
@@ -274,6 +279,36 @@ cc_library(
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(
name = "image_cropping_calculator",
srcs = ["image_cropping_calculator.cc"],
@@ -301,6 +336,7 @@ cc_library(
"//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
] + select({
"//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [
@@ -317,6 +353,7 @@ cc_library(
cc_test(
name = "image_cropping_calculator_test",
srcs = ["image_cropping_calculator_test.cc"],
tags = ["not_run:arm"],
deps = [
":image_cropping_calculator",
":image_cropping_calculator_cc_proto",
@@ -396,6 +433,7 @@ cc_library(
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings",
],
)
@@ -420,6 +458,8 @@ cc_library(
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/util:image_frame_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings",
"@libyuv",
],
@@ -625,9 +665,9 @@ cc_library(
"//mediapipe/framework/formats:image",
"//mediapipe/framework/formats:image_format_cc_proto",
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:status",
"//mediapipe/framework/port:vector",
"@com_google_absl//absl/log:absl_log",
] + select({
"//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [
@@ -650,6 +690,7 @@ cc_library(
cc_test(
name = "segmentation_smoothing_calculator_test",
srcs = ["segmentation_smoothing_calculator_test.cc"],
tags = ["not_run:arm"],
deps = [
":image_clone_calculator",
":image_clone_calculator_cc_proto",
@@ -664,6 +705,7 @@ cc_test(
"//mediapipe/framework/port:opencv_imgcodecs",
"//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:parse_text_proto",
"@com_google_absl//absl/log:absl_log",
],
)
@@ -686,6 +728,7 @@ cc_library(
"//mediapipe/gpu:gpu_buffer",
"//mediapipe/gpu:gpu_origin_cc_proto",
"//mediapipe/gpu:shader_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
@@ -771,7 +814,10 @@ cc_test(
"//mediapipe/calculators/tensor:testdata/image_to_tensor/medium_sub_rect_with_rotation_border_zero_interp_cubic.png",
"//mediapipe/calculators/tensor:testdata/image_to_tensor/noop_except_range.png",
],
tags = ["desktop_only_test"],
tags = [
"desktop_only_test",
"not_run:arm",
],
deps = [
":affine_transformation",
":image_transformation_calculator",
@@ -20,6 +20,7 @@
#include "Eigen/Core"
#include "Eigen/Geometry"
#include "Eigen/LU"
#include "absl/log/absl_log.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
@@ -53,6 +54,10 @@ bool IsMatrixVerticalFlipNeeded(GpuOrigin::Mode gpu_origin) {
#endif // __APPLE__
case GpuOrigin::TOP_LEFT:
return false;
default:
ABSL_LOG(ERROR) << "Incorrect GpuOrigin: "
<< static_cast<int>(gpu_origin);
return true;
}
}
@@ -384,6 +389,8 @@ class GlTextureWarpAffineRunner
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glFlush();
return absl::OkStatus();
}
@@ -15,6 +15,7 @@
#include <memory>
#include <string>
#include "absl/log/absl_check.h"
#include "absl/strings/str_replace.h"
#include "mediapipe/calculators/image/bilateral_filter_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
@@ -112,7 +113,7 @@ class BilateralFilterCalculator : public CalculatorBase {
REGISTER_CALCULATOR(BilateralFilterCalculator);
absl::Status BilateralFilterCalculator::GetContract(CalculatorContract* cc) {
CHECK_GE(cc->Inputs().NumEntries(), 1);
RET_CHECK_GE(cc->Inputs().NumEntries(), 1);
if (cc->Inputs().HasTag(kInputFrameTag) &&
cc->Inputs().HasTag(kInputFrameTagGpu)) {
@@ -183,8 +184,8 @@ absl::Status BilateralFilterCalculator::Open(CalculatorContext* cc) {
sigma_color_ = options_.sigma_color();
sigma_space_ = options_.sigma_space();
CHECK_GE(sigma_color_, 0.0);
CHECK_GE(sigma_space_, 0.0);
ABSL_CHECK_GE(sigma_color_, 0.0);
ABSL_CHECK_GE(sigma_space_, 0.0);
if (!use_gpu_) sigma_color_ *= 255.0;
if (use_gpu_) {
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/log/absl_check.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h"
@@ -25,8 +26,8 @@
namespace mediapipe {
namespace {
void SetColorChannel(int channel, uint8 value, cv::Mat* mat) {
CHECK(mat->depth() == CV_8U);
CHECK(channel < mat->channels());
ABSL_CHECK(mat->depth() == CV_8U);
ABSL_CHECK(channel < mat->channels());
const int step = mat->channels();
for (int r = 0; r < mat->rows; ++r) {
uint8* row_ptr = mat->ptr<uint8>(r);
@@ -16,6 +16,7 @@
#include <cmath>
#include "absl/log/absl_log.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/formats/rect.pb.h"
@@ -202,8 +203,9 @@ absl::Status ImageCroppingCalculator::ValidateBorderModeForGPU(
switch (options.border_mode()) {
case mediapipe::ImageCroppingCalculatorOptions::BORDER_ZERO:
LOG(WARNING) << "BORDER_ZERO mode is not supported by GPU "
<< "implementation and will fall back into BORDER_REPLICATE";
ABSL_LOG(WARNING)
<< "BORDER_ZERO mode is not supported by GPU "
<< "implementation and will fall back into BORDER_REPLICATE";
break;
case mediapipe::ImageCroppingCalculatorOptions::BORDER_REPLICATE:
break;
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/status/status.h"
#include "mediapipe/calculators/image/image_transformation_calculator.pb.h"
#include "mediapipe/calculators/image/rotation_mode.pb.h"
#include "mediapipe/framework/calculator_framework.h"
@@ -27,6 +28,7 @@
#include "mediapipe/gpu/scale_mode.pb.h"
#if !MEDIAPIPE_DISABLE_GPU
#include "mediapipe/gpu/gl_base.h"
#include "mediapipe/gpu/gl_calculator_helper.h"
#include "mediapipe/gpu/gl_quad_renderer.h"
#include "mediapipe/gpu/gl_simple_shaders.h"
@@ -60,42 +62,42 @@ constexpr char kVideoPrestreamTag[] = "VIDEO_PRESTREAM";
int RotationModeToDegrees(mediapipe::RotationMode_Mode rotation) {
switch (rotation) {
case mediapipe::RotationMode_Mode_UNKNOWN:
case mediapipe::RotationMode_Mode_ROTATION_0:
case mediapipe::RotationMode::UNKNOWN:
case mediapipe::RotationMode::ROTATION_0:
return 0;
case mediapipe::RotationMode_Mode_ROTATION_90:
case mediapipe::RotationMode::ROTATION_90:
return 90;
case mediapipe::RotationMode_Mode_ROTATION_180:
case mediapipe::RotationMode::ROTATION_180:
return 180;
case mediapipe::RotationMode_Mode_ROTATION_270:
case mediapipe::RotationMode::ROTATION_270:
return 270;
}
}
mediapipe::RotationMode_Mode DegreesToRotationMode(int degrees) {
switch (degrees) {
case 0:
return mediapipe::RotationMode_Mode_ROTATION_0;
return mediapipe::RotationMode::ROTATION_0;
case 90:
return mediapipe::RotationMode_Mode_ROTATION_90;
return mediapipe::RotationMode::ROTATION_90;
case 180:
return mediapipe::RotationMode_Mode_ROTATION_180;
return mediapipe::RotationMode::ROTATION_180;
case 270:
return mediapipe::RotationMode_Mode_ROTATION_270;
return mediapipe::RotationMode::ROTATION_270;
default:
return mediapipe::RotationMode_Mode_UNKNOWN;
return mediapipe::RotationMode::UNKNOWN;
}
}
mediapipe::ScaleMode_Mode ParseScaleMode(
mediapipe::ScaleMode_Mode scale_mode,
mediapipe::ScaleMode_Mode default_mode) {
switch (scale_mode) {
case mediapipe::ScaleMode_Mode_DEFAULT:
case mediapipe::ScaleMode::DEFAULT:
return default_mode;
case mediapipe::ScaleMode_Mode_STRETCH:
case mediapipe::ScaleMode::STRETCH:
return scale_mode;
case mediapipe::ScaleMode_Mode_FIT:
case mediapipe::ScaleMode::FIT:
return scale_mode;
case mediapipe::ScaleMode_Mode_FILL_AND_CROP:
case mediapipe::ScaleMode::FILL_AND_CROP:
return scale_mode;
default:
return default_mode;
@@ -208,6 +210,8 @@ class ImageTransformationCalculator : public CalculatorBase {
bool use_gpu_ = false;
cv::Scalar padding_color_;
ImageTransformationCalculatorOptions::InterpolationMode interpolation_mode_;
#if !MEDIAPIPE_DISABLE_GPU
GlCalculatorHelper gpu_helper_;
std::unique_ptr<QuadRenderer> rgb_renderer_;
@@ -343,6 +347,11 @@ absl::Status ImageTransformationCalculator::Open(CalculatorContext* cc) {
options_.padding_color().green(),
options_.padding_color().blue());
interpolation_mode_ = options_.interpolation_mode();
if (options_.interpolation_mode() ==
ImageTransformationCalculatorOptions::DEFAULT) {
interpolation_mode_ = ImageTransformationCalculatorOptions::LINEAR;
}
if (use_gpu_) {
#if !MEDIAPIPE_DISABLE_GPU
// 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,
&output_height);
int opencv_interpolation_mode = cv::INTER_LINEAR;
if (output_width_ > 0 && output_height_ > 0) {
cv::Mat scaled_mat;
if (scale_mode_ == mediapipe::ScaleMode_Mode_STRETCH) {
int scale_flag =
input_mat.cols > output_width_ && input_mat.rows > output_height_
? cv::INTER_AREA
: cv::INTER_LINEAR;
if (scale_mode_ == mediapipe::ScaleMode::STRETCH) {
if (interpolation_mode_ == ImageTransformationCalculatorOptions::LINEAR) {
// Use INTER_AREA for downscaling if interpolation mode is set to
// 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_),
0, 0, scale_flag);
0, 0, opencv_interpolation_mode);
} else {
const float scale =
std::min(static_cast<float>(output_width_) / input_width,
static_cast<float>(output_height_) / input_height);
const int target_width = std::round(input_width * 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::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 bottom = output_height_ - target_height - top;
const int left = (output_width_ - target_width) / 2;
@@ -488,7 +519,7 @@ absl::Status ImageTransformationCalculator::RenderCpu(CalculatorContext* cc) {
padding_color_);
} else {
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_height = target_height;
}
@@ -514,17 +545,17 @@ absl::Status ImageTransformationCalculator::RenderCpu(CalculatorContext* cc) {
cv::warpAffine(input_mat, rotated_mat, rotation_mat, rotated_size);
} else {
switch (rotation_) {
case mediapipe::RotationMode_Mode_UNKNOWN:
case mediapipe::RotationMode_Mode_ROTATION_0:
case mediapipe::RotationMode::UNKNOWN:
case mediapipe::RotationMode::ROTATION_0:
rotated_mat = input_mat;
break;
case mediapipe::RotationMode_Mode_ROTATION_90:
case mediapipe::RotationMode::ROTATION_90:
cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_COUNTERCLOCKWISE);
break;
case mediapipe::RotationMode_Mode_ROTATION_180:
case mediapipe::RotationMode::ROTATION_180:
cv::rotate(input_mat, rotated_mat, cv::ROTATE_180);
break;
case mediapipe::RotationMode_Mode_ROTATION_270:
case mediapipe::RotationMode::ROTATION_270:
cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_CLOCKWISE);
break;
}
@@ -561,7 +592,7 @@ absl::Status ImageTransformationCalculator::RenderGpu(CalculatorContext* cc) {
ComputeOutputDimensions(input_width, input_height, &output_width,
&output_height);
if (scale_mode_ == mediapipe::ScaleMode_Mode_FILL_AND_CROP) {
if (scale_mode_ == mediapipe::ScaleMode::FILL_AND_CROP) {
const float scale =
std::min(static_cast<float>(output_width_) / input_width,
static_cast<float>(output_height_) / input_height);
@@ -628,6 +659,12 @@ absl::Status ImageTransformationCalculator::RenderGpu(CalculatorContext* cc) {
glActiveTexture(GL_TEXTURE1);
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(
src1.width(), src1.height(), dst.width(), dst.height(), scale_mode,
rotation, flip_horizontally_, flip_vertically_,
@@ -652,8 +689,8 @@ void ImageTransformationCalculator::ComputeOutputDimensions(
if (output_width_ > 0 && output_height_ > 0) {
*output_width = output_width_;
*output_height = output_height_;
} else if (rotation_ == mediapipe::RotationMode_Mode_ROTATION_90 ||
rotation_ == mediapipe::RotationMode_Mode_ROTATION_270) {
} else if (rotation_ == mediapipe::RotationMode::ROTATION_90 ||
rotation_ == mediapipe::RotationMode::ROTATION_270) {
*output_width = input_height;
*output_height = input_width;
} else {
@@ -666,9 +703,9 @@ void ImageTransformationCalculator::ComputeOutputLetterboxPadding(
int input_width, int input_height, int output_width, int output_height,
std::array<float, 4>* padding) {
padding->fill(0.f);
if (scale_mode_ == mediapipe::ScaleMode_Mode_FIT) {
if (rotation_ == mediapipe::RotationMode_Mode_ROTATION_90 ||
rotation_ == mediapipe::RotationMode_Mode_ROTATION_270) {
if (scale_mode_ == mediapipe::ScaleMode::FIT) {
if (rotation_ == mediapipe::RotationMode::ROTATION_90 ||
rotation_ == mediapipe::RotationMode::ROTATION_270) {
std::swap(input_width, input_height);
}
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
// FIT. Default is black. This is for CPU only.
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
// limitations under the License.
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.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) {
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 =
absl::make_unique<OpenCvImageEncoderCalculatorResults>();
@@ -18,6 +18,8 @@
#include <memory>
#include <string>
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"
#include "libyuv/scale.h"
@@ -293,7 +295,7 @@ absl::Status ScaleImageCalculator::InitializeFrameInfo(CalculatorContext* cc) {
header->width = output_width_;
header->height = output_height_;
header->format = output_format_;
LOG(INFO) << "OUTPUTTING HEADER on stream";
ABSL_LOG(INFO) << "OUTPUTTING HEADER on stream";
cc->Outputs()
.Tag("VIDEO_HEADER")
.Add(header.release(), Timestamp::PreStream());
@@ -393,10 +395,11 @@ absl::Status ScaleImageCalculator::Open(CalculatorContext* cc) {
.SetHeader(Adopt(output_header.release()));
has_header_ = true;
} else {
LOG(WARNING) << "Stream had a VideoHeader which didn't have sufficient "
"information. "
"Dropping VideoHeader and trying to deduce needed "
"information.";
ABSL_LOG(WARNING)
<< "Stream had a VideoHeader which didn't have sufficient "
"information. "
"Dropping VideoHeader and trying to deduce needed "
"information.";
input_width_ = 0;
input_height_ = 0;
if (!options_.has_input_format()) {
@@ -507,7 +510,7 @@ absl::Status ScaleImageCalculator::ValidateImageFrame(
absl::Status ScaleImageCalculator::ValidateYUVImage(CalculatorContext* cc,
const YUVImage& yuv_image) {
CHECK_EQ(input_format_, ImageFormat::YCBCR420P);
ABSL_CHECK_EQ(input_format_, ImageFormat::YCBCR420P);
if (!has_header_) {
if (input_width_ != yuv_image.width() ||
input_height_ != yuv_image.height()) {
@@ -18,6 +18,7 @@
#include <string>
#include "absl/log/absl_check.h"
#include "absl/strings/str_split.h"
#include "mediapipe/framework/port/logging.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, //
int* crop_width, int* crop_height, //
int* col_start, int* row_start) {
CHECK(crop_width);
CHECK(crop_height);
CHECK(col_start);
CHECK(row_start);
ABSL_CHECK(crop_width);
ABSL_CHECK(crop_height);
ABSL_CHECK(col_start);
ABSL_CHECK(row_start);
double min_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);
CHECK_LE(*crop_height, input_height);
ABSL_CHECK_LE(*crop_width, input_width);
ABSL_CHECK_LE(*crop_height, input_height);
return absl::OkStatus();
}
@@ -96,8 +97,8 @@ absl::Status FindOutputDimensions(int input_width, //
bool preserve_aspect_ratio, //
int scale_to_multiple_of, //
int* output_width, int* output_height) {
CHECK(output_width);
CHECK(output_height);
ABSL_CHECK(output_width);
ABSL_CHECK(output_height);
if (target_max_area > 0 && input_width * input_height > target_max_area) {
preserve_aspect_ratio = true;
@@ -15,13 +15,13 @@
#include <algorithm>
#include <memory>
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_options.pb.h"
#include "mediapipe/framework/formats/image.h"
#include "mediapipe/framework/formats/image_format.pb.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/vector.h"
@@ -110,7 +110,7 @@ REGISTER_CALCULATOR(SegmentationSmoothingCalculator);
absl::Status SegmentationSmoothingCalculator::GetContract(
CalculatorContract* cc) {
CHECK_GE(cc->Inputs().NumEntries(), 1);
RET_CHECK_GE(cc->Inputs().NumEntries(), 1);
cc->Inputs().Tag(kCurrentMaskTag).Set<Image>();
cc->Inputs().Tag(kPreviousMaskTag).Set<Image>();
@@ -273,7 +273,7 @@ absl::Status SegmentationSmoothingCalculator::RenderGpu(CalculatorContext* cc) {
const auto& previous_frame = cc->Inputs().Tag(kPreviousMaskTag).Get<Image>();
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);
@@ -14,6 +14,7 @@
#include <memory>
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
@@ -169,7 +170,7 @@ void RunTest(bool use_gpu, float mix_ratio, cv::Mat& test_result) {
}
}
} else {
LOG(ERROR) << "invalid ratio";
ABSL_LOG(ERROR) << "invalid ratio";
}
}
@@ -14,13 +14,13 @@
#include <memory>
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/image/set_alpha_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_options.pb.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/logging.h"
#include "mediapipe/framework/port/opencv_core_inc.h"
#include "mediapipe/framework/port/opencv_imgproc_inc.h"
#include "mediapipe/framework/port/status.h"
@@ -142,7 +142,7 @@ class SetAlphaCalculator : public CalculatorBase {
REGISTER_CALCULATOR(SetAlphaCalculator);
absl::Status SetAlphaCalculator::GetContract(CalculatorContract* cc) {
CHECK_GE(cc->Inputs().NumEntries(), 1);
RET_CHECK_GE(cc->Inputs().NumEntries(), 1);
bool use_gpu = false;
@@ -268,7 +268,7 @@ absl::Status SetAlphaCalculator::RenderCpu(CalculatorContext* cc) {
const auto& input_frame = cc->Inputs().Tag(kInputFrameTag).Get<ImageFrame>();
const cv::Mat input_mat = formats::MatView(&input_frame);
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
@@ -328,7 +328,7 @@ absl::Status SetAlphaCalculator::RenderGpu(CalculatorContext* cc) {
cc->Inputs().Tag(kInputFrameTagGpu).Get<mediapipe::GpuBuffer>();
if (!(input_frame.format() == mediapipe::GpuBufferFormat::kBGRA32 ||
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);
+1
View File
@@ -18,6 +18,7 @@ licenses(["notice"])
filegroup(
name = "test_images",
srcs = [
"binary_mask.png",
"dino.jpg",
"dino_quality_50.jpg",
"dino_quality_80.jpg",
Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

@@ -38,7 +38,7 @@ std::string FourCCToString(libyuv::FourCC fourcc) {
buf[0] = (fourcc >> 24) & 0xff;
buf[1] = (fourcc >> 16) & 0xff;
buf[2] = (fourcc >> 8) & 0xff;
buf[3] = (fourcc)&0xff;
buf[3] = (fourcc) & 0xff;
buf[4] = 0;
return std::string(buf);
}
+2
View File
@@ -31,12 +31,14 @@ mediapipe_proto_library(
cc_library(
name = "callback_packet_calculator",
srcs = ["callback_packet_calculator.cc"],
hdrs = ["callback_packet_calculator.h"],
visibility = ["//mediapipe/framework:__subpackages__"],
deps = [
":callback_packet_calculator_cc_proto",
"//mediapipe/framework:calculator_base",
"//mediapipe/framework:calculator_registry",
"//mediapipe/framework:output_side_packet",
"@com_google_absl//absl/status",
],
alwayslink = 1,
)
@@ -11,10 +11,12 @@
// 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/internal/callback_packet_calculator.h"
#include <functional>
#include <string>
#include "absl/status/status.h"
#include "mediapipe/calculators/internal/callback_packet_calculator.pb.h" // NOLINT
#include "mediapipe/framework/calculator_base.h"
#include "mediapipe/framework/calculator_registry.h"
@@ -39,64 +41,55 @@ void DumpPostStreamPacket(Packet* post_stream_packet, const Packet& packet) {
*post_stream_packet = packet;
}
}
} // namespace
// 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) {
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) {
absl::Status CallbackPacketCalculator::GetContract(CalculatorContract* cc) {
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)
<< "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();
<< "Invalid type of callback to produce.";
}
return absl::OkStatus();
}
absl::Status Process(CalculatorContext* cc) override {
return absl::OkStatus();
absl::Status CallbackPacketCalculator::Open(CalculatorContext* cc) {
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);
@@ -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_
+33 -3
View File
@@ -87,6 +87,7 @@ cc_library(
"//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:ret_check",
"//mediapipe/util:time_series_util",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
@@ -181,6 +182,7 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/api2:node",
"//mediapipe/framework/formats:tensor",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/status",
],
alwayslink = 1,
@@ -198,6 +200,7 @@ cc_test(
"//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:parse_text_proto",
"@com_google_absl//absl/log:absl_check",
"@org_tensorflow//tensorflow/lite/c:common",
],
)
@@ -228,7 +231,6 @@ cc_library(
"//mediapipe/tasks/metadata:metadata_schema_cc",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
alwayslink = 1,
@@ -280,7 +282,6 @@ cc_library(
"//mediapipe/tasks/cc/text/tokenizers:tokenizer_utils",
"//mediapipe/tasks/metadata:metadata_schema_cc",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
],
alwayslink = 1,
)
@@ -394,7 +395,7 @@ mediapipe_proto_library(
# If you want to have precise control of which implementations to include (e.g. for strict binary
# size concerns), depend on those implementations directly, and do not depend on
# :inference_calculator.
# In all cases, use "InferenceCalulator" in your graphs.
# In all cases, use "InferenceCalculator" in your graphs.
cc_library_with_tflite(
name = "inference_calculator_interface",
srcs = ["inference_calculator.cc"],
@@ -447,6 +448,7 @@ cc_library(
"//mediapipe/framework/deps:file_path",
"//mediapipe/gpu:gl_calculator_helper",
"//mediapipe/util/tflite:tflite_gpu_runner",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
@@ -476,6 +478,7 @@ cc_library(
"//mediapipe/gpu:gpu_buffer",
"//mediapipe/objc:mediapipe_framework_ios",
"//mediapipe/util/tflite:config",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings:str_format",
"@org_tensorflow//tensorflow/lite/delegates/gpu:metal_delegate",
@@ -622,6 +625,7 @@ mediapipe_proto_library(
deps = [
"//mediapipe/framework:calculator_options_proto",
"//mediapipe/framework:calculator_proto",
"//mediapipe/gpu:gpu_origin_proto",
],
)
@@ -651,10 +655,26 @@ cc_library(
"//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:tensor",
"//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",
"@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({
"//mediapipe/gpu:disable_gpu": [],
"//conditions:default": ["tensor_converter_calculator_gpu_deps"],
}) + select({
"//mediapipe:apple": [
"//third_party/apple_frameworks:MetalKit",
],
"//conditions:default": [],
}),
alwayslink = 1,
)
@@ -696,9 +716,11 @@ cc_test(
"//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:opencv_core",
"//mediapipe/framework/port:parse_text_proto",
"//mediapipe/framework/tool:validate_type",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
],
)
@@ -734,6 +756,8 @@ cc_library(
"//mediapipe/framework/formats:tensor",
"//mediapipe/framework/formats/object_detection:anchor_cc_proto",
"//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/types:span",
] + selects.with_or({
@@ -790,6 +814,7 @@ cc_library(
"//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:tensor",
"//mediapipe/framework/port:ret_check",
"@com_google_absl//absl/log:absl_check",
],
alwayslink = 1,
)
@@ -982,6 +1007,8 @@ cc_library(
"//mediapipe/framework/port:status",
"//mediapipe/framework/port:statusor",
"//mediapipe/gpu:gpu_origin_cc_proto",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
] + select({
"//mediapipe/gpu:disable_gpu": [],
"//conditions:default": [":image_to_tensor_calculator_gpu_deps"],
@@ -1052,6 +1079,7 @@ cc_test(
"testdata/image_to_tensor/medium_sub_rect_with_rotation_border_zero.png",
"testdata/image_to_tensor/noop_except_range.png",
],
tags = ["not_run:arm"],
deps = [
":image_to_tensor_calculator",
":image_to_tensor_converter",
@@ -1073,6 +1101,7 @@ cc_test(
"//mediapipe/framework/port:parse_text_proto",
"//mediapipe/util:image_test_utils",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
@@ -1200,6 +1229,7 @@ cc_library(
"//mediapipe/gpu:gl_calculator_helper",
"//mediapipe/gpu:gl_simple_shaders",
"//mediapipe/gpu:shader_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings",
],
}),
@@ -20,6 +20,7 @@
#include <utility>
#include <vector>
#include "absl/log/absl_check.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
@@ -282,18 +283,23 @@ absl::Status AudioToTensorCalculator::Open(CalculatorContext* cc) {
if (options.has_volume_gain_db()) {
gain_ = pow(10, options.volume_gain_db() / 20.0);
}
RET_CHECK(kAudioSampleRateIn(cc).IsConnected() ^
!kAudioIn(cc).Header().IsEmpty())
<< "Must either specify the time series header of the \"AUDIO\" stream "
"or have the \"SAMPLE_RATE\" stream connected.";
if (!kAudioIn(cc).Header().IsEmpty()) {
mediapipe::TimeSeriesHeader input_header;
MP_RETURN_IF_ERROR(mediapipe::time_series_util::FillTimeSeriesHeaderIfValid(
kAudioIn(cc).Header(), &input_header));
if (stream_mode_) {
MP_RETURN_IF_ERROR(SetupStreamingResampler(input_header.sample_rate()));
} else {
source_sample_rate_ = input_header.sample_rate();
if (options.has_source_sample_rate()) {
source_sample_rate_ = options.source_sample_rate();
} else {
RET_CHECK(kAudioSampleRateIn(cc).IsConnected() ^
!kAudioIn(cc).Header().IsEmpty())
<< "Must either specify the time series header of the \"AUDIO\" stream "
"or have the \"SAMPLE_RATE\" stream connected.";
if (!kAudioIn(cc).Header().IsEmpty()) {
mediapipe::TimeSeriesHeader input_header;
MP_RETURN_IF_ERROR(
mediapipe::time_series_util::FillTimeSeriesHeaderIfValid(
kAudioIn(cc).Header(), &input_header));
if (stream_mode_) {
MP_RETURN_IF_ERROR(SetupStreamingResampler(input_header.sample_rate()));
} else {
source_sample_rate_ = input_header.sample_rate();
}
}
}
AppendZerosToSampleBuffer(padding_samples_before_);
@@ -343,7 +349,7 @@ absl::Status AudioToTensorCalculator::Process(CalculatorContext* cc) {
return absl::InvalidArgumentError(
"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
// Mono mixdown.
: input_frame.colwise().mean();
@@ -452,7 +458,7 @@ absl::Status AudioToTensorCalculator::SetupStreamingResampler(
}
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) {
return;
}
@@ -85,4 +85,7 @@ message AudioToTensorCalculatorOptions {
// The volume gain, measured in dB.
// Scale the input audio amplitude by 10^(volume_gain_db/20).
optional double volume_gain_db = 12;
// The source number of samples per second (hertz) of the input audio buffers.
optional double source_sample_rate = 13;
}
@@ -22,7 +22,6 @@
#include "absl/container/flat_hash_set.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/ascii.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
@@ -244,7 +243,8 @@ std::vector<Tensor> BertPreprocessorCalculator::GenerateInputTensors(
input_tensors.reserve(kNumInputTensorsForBert);
for (int i = 0; i < kNumInputTensorsForBert; ++i) {
input_tensors.push_back(
{Tensor::ElementType::kInt32, Tensor::Shape({tensor_size})});
{Tensor::ElementType::kInt32,
Tensor::Shape({1, tensor_size}, has_dynamic_input_tensors_)});
}
std::memcpy(input_tensors[input_ids_tensor_index_]
.GetCpuWriteView()
@@ -18,6 +18,7 @@
#include <utility>
#include <vector>
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/tensor/feedback_tensors_calculator.pb.h"
#include "mediapipe/framework/calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
@@ -65,7 +66,7 @@ template <typename T>
Tensor MakeTensor(std::initializer_list<int> shape,
std::initializer_list<T> values) {
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`";
absl::c_copy(values, tensor.GetCpuWriteView().buffer<T>());
return tensor;
@@ -16,6 +16,7 @@
#include <memory>
#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_converter.h"
#include "mediapipe/calculators/tensor/image_to_tensor_utils.h"
@@ -284,9 +285,9 @@ class ImageToTensorCalculator : public Node {
cc, GetBorderMode(options_.border_mode()),
GetOutputTensorType(/*uses_gpu=*/false, params_)));
#else
LOG(FATAL) << "Cannot create image to tensor CPU converter since "
"MEDIAPIPE_DISABLE_OPENCV is defined and "
"MEDIAPIPE_ENABLE_HALIDE is not defined.";
ABSL_LOG(FATAL) << "Cannot create image to tensor CPU converter since "
"MEDIAPIPE_DISABLE_OPENCV is defined and "
"MEDIAPIPE_ENABLE_HALIDE is not defined.";
#endif // !MEDIAPIPE_DISABLE_HALIDE
}
}
@@ -18,6 +18,7 @@
#include <vector>
#include "absl/flags/flag.h"
#include "absl/log/absl_check.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_format.h"
#include "absl/strings/substitute.h"
@@ -205,7 +206,7 @@ mediapipe::ImageFormat::Format GetImageFormat(int image_channels) {
} else if (image_channels == 1) {
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) {
@@ -22,6 +22,7 @@
#include <memory>
#include <vector>
#include "absl/log/absl_log.h"
#include "absl/strings/str_cat.h"
#include "mediapipe/calculators/tensor/image_to_tensor_converter.h"
#include "mediapipe/calculators/tensor/image_to_tensor_converter_gl_utils.h"
@@ -259,7 +260,7 @@ class GlProcessor : public ImageToTensorConverter {
// error. So in that case, we'll grab the transpose of our original matrix
// and send that instead.
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) {
GetTransposedRotatedSubRectToRectTransformMatrix(
sub_rect, texture.width(), texture.height(), flip_horizontaly,
@@ -88,6 +88,20 @@ message InferenceCalculatorOptions {
// serialized model is invalid or missing.
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
// "serialized_model_dir". It is the caller's responsibility to ensure
// there is no clash of the tokens.
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdint>
#include <cstring>
#include <memory>
#include <string>
@@ -26,6 +27,7 @@
#include "mediapipe/util/tflite/tflite_gpu_runner.h"
#if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS)
#include "absl/log/absl_log.h"
#include "mediapipe/framework/deps/file_path.h"
#include "mediapipe/util/android/file/base/file.h"
#include "mediapipe/util/android/file/base/filesystem.h"
@@ -68,13 +70,21 @@ class InferenceCalculatorGlAdvancedImpl
const mediapipe::InferenceCalculatorOptions::Delegate::Gpu&
gpu_delegate_options);
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_; }
private:
// Writes caches to disk, returns error on failure.
absl::Status SaveGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const;
bool use_kernel_caching_ = false;
std::string cached_kernel_filename_;
bool use_serialized_model_ = false;
std::string serialized_model_path_;
mediapipe::InferenceCalculatorOptions::Delegate::Gpu::CacheWritingBehavior
cache_writing_behavior_;
};
// Helper class that wraps everything related to GPU inference acceleration.
@@ -150,8 +160,6 @@ InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::Process(
}
absl::Status InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::Close() {
MP_RETURN_IF_ERROR(
on_disk_cache_helper_.SaveGpuCaches(tflite_gpu_runner_.get()));
return gpu_helper_.RunInGlContext([this]() -> absl::Status {
tflite_gpu_runner_.reset();
return absl::OkStatus();
@@ -226,9 +234,15 @@ InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::InitTFLiteGPURunner(
tflite_gpu_runner_->GetOutputShapes()[i].c};
}
if (on_disk_cache_helper_.UseSerializedModel()) {
tflite_gpu_runner_->ForceOpenCLInitFromSerializedModel();
}
MP_RETURN_IF_ERROR(
on_disk_cache_helper_.ReadGpuCaches(tflite_gpu_runner_.get()));
return tflite_gpu_runner_->Build();
MP_RETURN_IF_ERROR(tflite_gpu_runner_->Build());
return on_disk_cache_helper_.SaveGpuCachesBasedOnBehavior(
tflite_gpu_runner_.get());
}
#if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS)
@@ -257,9 +271,36 @@ absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::Init(
mediapipe::file::JoinPath(gpu_delegate_options.serialized_model_dir(),
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();
}
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
InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::SaveGpuCaches(
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
@@ -314,6 +355,12 @@ absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::Init(
return absl::OkStatus();
}
absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::
SaveGpuCachesBasedOnBehavior(
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
return absl::OkStatus();
}
absl::Status
InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::ReadGpuCaches(
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
#include "absl/log/absl_log.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_format.h"
#include "mediapipe/calculators/tensor/inference_calculator.h"
@@ -74,7 +75,7 @@ tflite::gpu::BHWC BhwcFromTensorShape(const Tensor::Shape& shape) {
break;
default:
// Handles 0 and >4.
LOG(FATAL)
ABSL_LOG(FATAL)
<< "Dimensions size must be in range [1,4] for GPU inference, but "
<< shape.dims.size() << " is provided";
}
@@ -16,7 +16,7 @@
#include <string>
#include <vector>
#include "absl/log/check.h"
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
@@ -96,6 +96,19 @@ absl::StatusOr<std::vector<Tensor>> InferenceInterpreterDelegateRunner::Run(
CalculatorContext* cc, const std::vector<Tensor>& input_tensors) {
// Read CPU input into tensors.
RET_CHECK_EQ(interpreter_->inputs().size(), input_tensors.size());
// If the input tensors have dynamic shape, then the tensors need to be
// resized and reallocated before we can copy the tensor values.
bool resized_tensor_shapes = false;
for (int i = 0; i < input_tensors.size(); ++i) {
if (input_tensors[i].shape().is_dynamic) {
interpreter_->ResizeInputTensorStrict(i, input_tensors[i].shape().dims);
resized_tensor_shapes = true;
}
}
// Reallocation is needed for memory sanity.
if (resized_tensor_shapes) interpreter_->AllocateTensors();
for (int i = 0; i < input_tensors.size(); ++i) {
const TfLiteType input_tensor_type =
interpreter_->tensor(interpreter_->inputs()[i])->type;
@@ -20,7 +20,6 @@
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "mediapipe/calculators/tensor/regex_preprocessor_calculator.pb.h"
#include "mediapipe/framework/api2/node.h"
#include "mediapipe/framework/api2/port.h"
@@ -161,7 +160,7 @@ absl::Status RegexPreprocessorCalculator::Process(CalculatorContext* cc) {
// not found in the tokenizer vocab.
std::vector<Tensor> result;
result.push_back(
{Tensor::ElementType::kInt32, Tensor::Shape({max_seq_len_})});
{Tensor::ElementType::kInt32, Tensor::Shape({1, max_seq_len_})});
std::memcpy(result[0].GetCpuWriteView().buffer<int32_t>(),
input_tokens.data(), input_tokens.size() * sizeof(int32_t));
kTensorsOut(cc).Send(std::move(result));
@@ -12,9 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdint>
#include <string>
#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/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame.h"
@@ -22,7 +28,8 @@
#include "mediapipe/framework/formats/tensor.h"
#include "mediapipe/framework/port.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
#include "mediapipe/gpu/gpu_buffer.h"
@@ -43,12 +50,50 @@
#endif // !MEDIAPIPE_DISABLE_GPU
namespace {
constexpr int kWorkgroupSize = 8; // Block size for GPU shader.
// Commonly used to compute the number of blocks to launch in a kernel.
int NumGroups(const int size, const int group_size) { // NOLINT
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>
RowMajorMatrixXf;
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 kTensorsTag[] = "TENSORS";
constexpr char kMatrixTag[] = "MATRIX";
} // namespace
namespace mediapipe {
@@ -109,7 +155,7 @@ class TensorConverterCalculator : public CalculatorBase {
private:
absl::Status InitGpu(CalculatorContext* cc);
absl::Status LoadOptions(CalculatorContext* cc);
absl::Status LoadOptions(CalculatorContext* cc, bool use_gpu);
template <class T>
absl::Status NormalizeImage(const ImageFrame& image_frame,
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)) +
static_cast<int>(cc->Inputs().HasTag(kGpuBufferTag)) +
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)) {
cc->Inputs().Tag(kImageFrameTag).Set<ImageFrame>();
@@ -173,8 +220,6 @@ absl::Status TensorConverterCalculator::GetContract(CalculatorContract* cc) {
absl::Status TensorConverterCalculator::Open(CalculatorContext* cc) {
cc->SetOffset(TimestampDiff(0));
MP_RETURN_IF_ERROR(LoadOptions(cc));
#if !MEDIAPIPE_DISABLE_GPU
if (cc->Inputs().HasTag(kGpuBufferTag)) {
use_gpu_ = true;
@@ -187,6 +232,8 @@ absl::Status TensorConverterCalculator::Open(CalculatorContext* cc) {
}
#endif // !MEDIAPIPE_DISABLE_GPU
MP_RETURN_IF_ERROR(LoadOptions(cc, use_gpu_));
return absl::OkStatus();
}
@@ -378,23 +425,34 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
// Get input image sizes.
const auto& input =
cc->Inputs().Tag(kGpuBufferTag).Get<mediapipe::GpuBuffer>();
mediapipe::ImageFormat::Format format =
mediapipe::ImageFormatForGpuBufferFormat(input.format());
mediapipe::GpuBufferFormat format = input.format();
const bool include_alpha = (max_num_channels_ == 4);
const bool single_channel = (max_num_channels_ == 1);
if (!(format == mediapipe::ImageFormat::GRAY8 ||
format == mediapipe::ImageFormat::SRGB ||
format == mediapipe::ImageFormat::SRGBA))
RET_CHECK_FAIL() << "Unsupported GPU input format.";
if (include_alpha && (format != mediapipe::ImageFormat::SRGBA))
RET_CHECK_FAIL() << "Num input channels is less than desired output.";
RET_CHECK(format == mediapipe::GpuBufferFormat::kBGRA32 ||
format == mediapipe::GpuBufferFormat::kRGB24 ||
format == mediapipe::GpuBufferFormat::kRGBA32 ||
format == mediapipe::GpuBufferFormat::kRGBAFloat128 ||
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
id<MTLDevice> device = gpu_helper_.mtlDevice;
// Shader to convert GL Texture to Metal Buffer,
// with normalization to either: [0,1] or [-1,1].
const std::string shader_source = absl::Substitute(
R"(
R"glsl(
#include <metal_stdlib>
using namespace metal;
@@ -413,7 +471,7 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
$3 // g & b channels
$4 // alpha channel
}
)",
)glsl",
/*$0=*/
output_range_.has_value()
? absl::Substitute("pixel = pixel * half($0) + half($1);",
@@ -423,8 +481,8 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
/*$1=*/max_num_channels_,
/*$2=*/flip_vertically_ ? "(in_tex.get_height() - 1 - gid.y)" : "gid.y",
/*$3=*/
single_channel ? "" : R"(out_buf[linear_index + 1] = pixel.y;
out_buf[linear_index + 2] = pixel.z;)",
single_channel ? "" : R"glsl(out_buf[linear_index + 1] = pixel.y;
out_buf[linear_index + 2] = pixel.z;)glsl",
/*$4=*/include_alpha ? "out_buf[linear_index + 3] = pixel.w;" : "");
NSString* library_source =
@@ -442,17 +500,17 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
RET_CHECK(to_buffer_program_ != nil) << "Couldn't create pipeline state " <<
[[error localizedDescription] UTF8String];
#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
&input,
&input,
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
&single_channel]()
-> absl::Status {
&single_channel]() -> absl::Status {
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
// Shader to convert GL Texture to Shader Storage Buffer Object (SSBO),
// with normalization to either: [0,1] or [-1,1].
const std::string shader_source = absl::Substitute(
R"( #version 310 es
// Shader to convert GL Texture to Shader Storage Buffer Object (SSBO),
// with normalization to either: [0,1] or [-1,1].
const std::string shader_source = absl::Substitute(
R"glsl( #version 310 es
layout(local_size_x = $0, local_size_y = $0) in;
layout(binding = 0) uniform sampler2D input_texture;
layout(std430, binding = 1) buffer Output {float elements[];} output_data;
@@ -466,38 +524,40 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
output_data.elements[linear_index + 0] = pixel.x; // r channel
$5 // g & b channels
$6 // alpha channel
})",
/*$0=*/kWorkgroupSize, /*$1=*/input.width(), /*$2=*/input.height(),
/*$3=*/
output_range_.has_value()
? absl::Substitute("pixel = pixel * float($0) + float($1);",
(output_range_->second - output_range_->first),
output_range_->first)
: "",
/*$4=*/flip_vertically_ ? "(width_height.y - 1 - gid.y)" : "gid.y",
/*$5=*/
single_channel ? ""
: R"(output_data.elements[linear_index + 1] = pixel.y;
output_data.elements[linear_index + 2] = pixel.z;)",
/*$6=*/
include_alpha ? "output_data.elements[linear_index + 3] = pixel.w;"
: "",
/*$7=*/max_num_channels_);
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
const GLchar* sources[] = {shader_source.c_str()};
glShaderSource(shader, 1, sources, NULL);
glCompileShader(shader);
GLint compiled = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
RET_CHECK(compiled == GL_TRUE);
to_buffer_program_ = glCreateProgram();
glAttachShader(to_buffer_program_, shader);
glDeleteShader(shader);
glLinkProgram(to_buffer_program_);
})glsl",
/*$0=*/kWorkgroupSize, /*$1=*/input.width(), /*$2=*/input.height(),
/*$3=*/
output_range_.has_value()
? absl::Substitute(
"pixel = pixel * float($0) + float($1);",
(output_range_->second - output_range_->first),
output_range_->first)
: "",
/*$4=*/flip_vertically_ ? "(width_height.y - 1 - gid.y)" : "gid.y",
/*$5=*/
single_channel
? ""
: R"glsl(output_data.elements[linear_index + 1] = pixel.y;
output_data.elements[linear_index + 2] = pixel.z;)glsl",
/*$6=*/
include_alpha ? "output_data.elements[linear_index + 3] = pixel.w;"
: "",
/*$7=*/max_num_channels_);
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
const GLchar* sources[] = {shader_source.c_str()};
glShaderSource(shader, 1, sources, NULL);
glCompileShader(shader);
GLint compiled = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
RET_CHECK(compiled == GL_TRUE);
to_buffer_program_ = glCreateProgram();
glAttachShader(to_buffer_program_, shader);
glDeleteShader(shader);
glLinkProgram(to_buffer_program_);
#else
// OpenGL ES 3.0 fragment shader Texture2d -> Texture2d conversion.
const std::string shader_source = absl::Substitute(
R"(
// OpenGL ES 3.0 fragment shader Texture2d -> Texture2d conversion.
const std::string shader_source = absl::Substitute(
R"glsl(
#if __VERSION__ < 130
#define in varying
#endif // __VERSION__ < 130
@@ -523,49 +583,51 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
fragColor.r = pixel.r; // r channel
$3 // g & b channels
$4 // alpha channel
})",
/*$0=*/single_channel ? "vec1" : "vec4",
/*$1=*/
flip_vertically_
? "vec2(sample_coordinate.x, 1.0 - sample_coordinate.y);"
: "sample_coordinate;",
/*$2=*/output_range_.has_value()
? absl::Substitute("pixel = pixel * float($0) + float($1);",
(output_range_->second - output_range_->first),
output_range_->first)
: "",
/*$3=*/single_channel ? "" : R"(fragColor.g = pixel.g;
fragColor.b = pixel.b;)",
/*$4=*/
include_alpha ? "fragColor.a = pixel.a;"
: (single_channel ? "" : "fragColor.a = 1.0;"));
})glsl",
/*$0=*/single_channel ? "vec1" : "vec4",
/*$1=*/
flip_vertically_
? "vec2(sample_coordinate.x, 1.0 - sample_coordinate.y);"
: "sample_coordinate;",
/*$2=*/output_range_.has_value()
? absl::Substitute(
"pixel = pixel * float($0) + float($1);",
(output_range_->second - output_range_->first),
output_range_->first)
: "",
/*$3=*/single_channel ? "" : R"glsl(fragColor.g = pixel.g;
fragColor.b = pixel.b;)glsl",
/*$4=*/
include_alpha ? "fragColor.a = pixel.a;"
: (single_channel ? "" : "fragColor.a = 1.0;"));
const GLint attr_location[NUM_ATTRIBUTES] = {
ATTRIB_VERTEX,
ATTRIB_TEXTURE_POSITION,
};
const GLchar* attr_name[NUM_ATTRIBUTES] = {
"position",
"texture_coordinate",
};
// shader program and params
mediapipe::GlhCreateProgram(
mediapipe::kBasicVertexShader, shader_source.c_str(), NUM_ATTRIBUTES,
&attr_name[0], attr_location, &to_tex2d_program_);
RET_CHECK(to_tex2d_program_) << "Problem initializing the program.";
glUseProgram(to_tex2d_program_);
glUniform1i(glGetUniformLocation(to_tex2d_program_, "frame"), 1);
glGenFramebuffers(1, &framebuffer_);
const GLint attr_location[NUM_ATTRIBUTES] = {
ATTRIB_VERTEX,
ATTRIB_TEXTURE_POSITION,
};
const GLchar* attr_name[NUM_ATTRIBUTES] = {
"position",
"texture_coordinate",
};
// shader program and params
mediapipe::GlhCreateProgram(
mediapipe::kBasicVertexShader, shader_source.c_str(),
NUM_ATTRIBUTES, &attr_name[0], attr_location, &to_tex2d_program_);
RET_CHECK(to_tex2d_program_) << "Problem initializing the program.";
glUseProgram(to_tex2d_program_);
glUniform1i(glGetUniformLocation(to_tex2d_program_, "frame"), 1);
glGenFramebuffers(1, &framebuffer_);
#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_DISABLE_GPU
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.
const auto& options =
cc->Options<::mediapipe::TensorConverterCalculatorOptions>();
@@ -582,7 +644,7 @@ absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc) {
if (options.has_output_tensor_float_range()) {
output_range_.emplace(options.output_tensor_float_range().min(),
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.
@@ -593,16 +655,16 @@ absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc) {
}
// Get y-flip mode.
flip_vertically_ = options.flip_vertically();
ASSIGN_OR_RETURN(flip_vertically_, ShouldFlipVertically(options, use_gpu));
// Get row_major_matrix mode.
row_major_matrix_ = options.row_major_matrix();
// Get desired way to handle input channels.
max_num_channels_ = options.max_num_channels();
CHECK_GE(max_num_channels_, 1);
CHECK_LE(max_num_channels_, 4);
CHECK_NE(max_num_channels_, 2);
ABSL_CHECK_GE(max_num_channels_, 1);
ABSL_CHECK_LE(max_num_channels_, 4);
ABSL_CHECK_NE(max_num_channels_, 2);
return absl::OkStatus();
}
@@ -3,6 +3,7 @@ syntax = "proto2";
package mediapipe;
import "mediapipe/framework/calculator.proto";
import "mediapipe/gpu/gpu_origin.proto";
// Full Example:
//
@@ -43,8 +44,16 @@ message TensorConverterCalculatorOptions {
// 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
// origin.
// Prefer gpu_origin over this field when using GPU input images.
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
// tensor. Valid values are 1,3,4 only. Ignored for iOS GPU.
optional int32 max_num_channels = 3 [default = 3];
@@ -12,10 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cmath>
#include <cstdint>
#include <memory>
#include <random>
#include <utility>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/strings/substitute.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
@@ -24,8 +29,10 @@
#include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/tensor.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.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/status_matchers.h" // NOLINT
#include "mediapipe/framework/tool/validate_type.h"
@@ -40,7 +47,7 @@ constexpr char kTransposeOptionsString[] =
} // namespace
using RandomEngine = std::mt19937_64;
using testing::Eq;
using ::testing::HasSubstr;
const uint32_t kSeed = 1234;
const int kNumSizes = 8;
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) {
RandomEngine random(kSeed);
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);
if (row_major_matrix) {
for (int y = 0; y < num_rows; ++y) {
@@ -101,7 +108,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixColMajor) {
tool::AddVectorSink("tensor", &graph_config, &output_packets);
// Run the graph.
graph_ = absl::make_unique<CalculatorGraph>();
graph_ = std::make_unique<CalculatorGraph>();
MP_ASSERT_OK(graph_->Initialize(graph_config));
MP_ASSERT_OK(graph_->StartRun({}));
@@ -110,12 +117,12 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixColMajor) {
// Wait until the calculator done processing.
MP_ASSERT_OK(graph_->WaitUntilIdle());
EXPECT_EQ(1, output_packets.size());
ASSERT_EQ(output_packets.size(), 1);
// Get and process results.
const std::vector<Tensor>& tensor_vec =
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];
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
@@ -127,7 +134,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixColMajor) {
auto tensor_buffer = view.buffer<float>();
for (int i = 0; i < num_rows * num_columns; ++i) {
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
@@ -163,7 +170,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixRowMajor) {
tool::AddVectorSink("tensor", &graph_config, &output_packets);
// Run the graph.
graph_ = absl::make_unique<CalculatorGraph>();
graph_ = std::make_unique<CalculatorGraph>();
MP_ASSERT_OK(graph_->Initialize(graph_config));
MP_ASSERT_OK(graph_->StartRun({}));
@@ -172,12 +179,12 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixRowMajor) {
// Wait until the calculator done processing.
MP_ASSERT_OK(graph_->WaitUntilIdle());
EXPECT_EQ(1, output_packets.size());
ASSERT_EQ(output_packets.size(), 1);
// Get and process results.
const std::vector<Tensor>& tensor_vec =
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];
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
@@ -189,7 +196,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixRowMajor) {
auto tensor_buffer = view.buffer<float>();
for (int i = 0; i < num_rows * num_columns; ++i) {
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
@@ -227,7 +234,7 @@ TEST_F(TensorConverterCalculatorTest, CustomDivAndSub) {
// Run the graph.
MP_ASSERT_OK(graph.Initialize(graph_config));
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());
mat.at<uint8_t>(0, 0) = 200;
MP_ASSERT_OK(graph.AddPacketToInputStream(
@@ -239,12 +246,12 @@ TEST_F(TensorConverterCalculatorTest, CustomDivAndSub) {
// Get and process results.
const std::vector<Tensor>& tensor_vec =
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];
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
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
// after calling WaitUntilDone().
@@ -259,32 +266,29 @@ TEST_F(TensorConverterCalculatorTest, SetOutputRange) {
for (std::pair<float, float> range : range_values) {
CalculatorGraph graph;
CalculatorGraphConfig graph_config =
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(
absl::Substitute(R"(
input_stream: "input_image"
node {
calculator: "TensorConverterCalculator"
input_stream: "IMAGE:input_image"
output_stream: "TENSORS:tensor"
options {
[mediapipe.TensorConverterCalculatorOptions.ext] {
output_tensor_float_range {
min: $0
max: $1
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(absl::Substitute(
R"pb(
input_stream: "input_image"
node {
calculator: "TensorConverterCalculator"
input_stream: "IMAGE:input_image"
output_stream: "TENSORS:tensor"
options {
[mediapipe.TensorConverterCalculatorOptions.ext] {
output_tensor_float_range { min: $0 max: $1 }
}
}
}
}
}
}
)",
/*$0=*/range.first,
/*$1=*/range.second));
)pb",
/*$0=*/range.first,
/*$1=*/range.second));
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 = 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());
mat.at<uint8_t>(0, 0) = 200;
MP_ASSERT_OK(graph.AddPacketToInputStream(
@@ -292,26 +296,23 @@ TEST_F(TensorConverterCalculatorTest, SetOutputRange) {
// Wait until the calculator finishes processing.
MP_ASSERT_OK(graph.WaitUntilIdle());
EXPECT_THAT(output_packets.size(), Eq(1));
ASSERT_EQ(output_packets.size(), 1);
// Get and process results.
const std::vector<Tensor>& tensor_vec =
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];
// Calculate the expected normalized value:
float normalized_value =
float expected_value =
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();
float dataf = *view.buffer<float>();
EXPECT_THAT(
normalized_value,
testing::FloatNear(dataf, 2.0f * std::abs(dataf) *
std::numeric_limits<float>::epsilon()));
float actual_value = *view.buffer<float>();
EXPECT_FLOAT_EQ(actual_value, expected_value);
// Fully close graph at end, otherwise calculator+tensors are destroyed
// 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
@@ -15,6 +15,7 @@
#include <unordered_map>
#include <vector>
#include "absl/log/absl_log.h"
#include "absl/strings/str_format.h"
#include "absl/types/span.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,
int num_boxes, float* raw_anchors) {
CHECK_EQ(anchors.size(), num_boxes);
ABSL_CHECK_EQ(anchors.size(), num_boxes);
int box = 0;
for (const auto& anchor : anchors) {
raw_anchors[box * kNumCoordsPerBox + 0] = anchor.y_center();
@@ -256,6 +257,7 @@ class TensorsToDetectionsCalculator : public Node {
bool gpu_inited_ = false;
bool gpu_input_ = false;
bool gpu_has_enough_work_groups_ = true;
bool anchors_init_ = false;
};
MEDIAPIPE_REGISTER_NODE(TensorsToDetectionsCalculator);
@@ -291,7 +293,7 @@ absl::Status TensorsToDetectionsCalculator::Open(CalculatorContext* cc) {
absl::Status TensorsToDetectionsCalculator::Process(CalculatorContext* cc) {
auto output_detections = absl::make_unique<std::vector<Detection>>();
bool gpu_processing = false;
if (CanUseGpu()) {
if (CanUseGpu() && gpu_has_enough_work_groups_) {
// Use GPU processing only if at least one input tensor is already on GPU
// (to avoid CPU->GPU overhead).
for (const auto& tensor : *kInTensors(cc)) {
@@ -321,11 +323,20 @@ absl::Status TensorsToDetectionsCalculator::Process(CalculatorContext* cc) {
RET_CHECK(!has_custom_box_indices_);
}
if (gpu_processing) {
if (!gpu_inited_) {
MP_RETURN_IF_ERROR(GpuInit(cc));
if (gpu_processing && !gpu_inited_) {
auto status = GpuInit(cc);
if (status.ok()) {
gpu_inited_ = true;
} else if (status.code() == absl::StatusCode::kFailedPrecondition) {
// For initialization error because of hardware limitation, fallback to
// CPU processing.
ABSL_LOG(WARNING) << status.message();
} else {
// For other error, let the error propagates.
return status;
}
}
if (gpu_processing && gpu_inited_) {
MP_RETURN_IF_ERROR(ProcessGPU(cc, output_detections.get()));
} else {
MP_RETURN_IF_ERROR(ProcessCPU(cc, output_detections.get()));
@@ -346,17 +357,41 @@ absl::Status TensorsToDetectionsCalculator::ProcessCPU(
// TODO: Add flexible input tensor size handling.
auto raw_box_tensor =
&input_tensors[tensor_mapping_.detections_tensor_index()];
RET_CHECK_EQ(raw_box_tensor->shape().dims.size(), 3);
RET_CHECK_EQ(raw_box_tensor->shape().dims[0], 1);
RET_CHECK_GT(num_boxes_, 0) << "Please set num_boxes in calculator options";
RET_CHECK_EQ(raw_box_tensor->shape().dims[1], num_boxes_);
RET_CHECK_EQ(raw_box_tensor->shape().dims[2], num_coords_);
if (raw_box_tensor->shape().dims.size() == 3) {
// The tensors from CPU inference has dim 3.
RET_CHECK_EQ(raw_box_tensor->shape().dims[0], 1);
RET_CHECK_EQ(raw_box_tensor->shape().dims[1], num_boxes_);
RET_CHECK_EQ(raw_box_tensor->shape().dims[2], num_coords_);
} else if (raw_box_tensor->shape().dims.size() == 4) {
// The tensors from GPU inference has dim 4. For gpu-cpu fallback support,
// we allow tensors with 4 dims.
RET_CHECK_EQ(raw_box_tensor->shape().dims[0], 1);
RET_CHECK_EQ(raw_box_tensor->shape().dims[1], 1);
RET_CHECK_EQ(raw_box_tensor->shape().dims[2], num_boxes_);
RET_CHECK_EQ(raw_box_tensor->shape().dims[3], num_coords_);
} else {
return absl::InvalidArgumentError(
"The dimensions of box Tensor must be 3 or 4.");
}
auto raw_score_tensor =
&input_tensors[tensor_mapping_.scores_tensor_index()];
RET_CHECK_EQ(raw_score_tensor->shape().dims.size(), 3);
RET_CHECK_EQ(raw_score_tensor->shape().dims[0], 1);
RET_CHECK_EQ(raw_score_tensor->shape().dims[1], num_boxes_);
RET_CHECK_EQ(raw_score_tensor->shape().dims[2], num_classes_);
if (raw_score_tensor->shape().dims.size() == 3) {
// The tensors from CPU inference has dim 3.
RET_CHECK_EQ(raw_score_tensor->shape().dims[0], 1);
RET_CHECK_EQ(raw_score_tensor->shape().dims[1], num_boxes_);
RET_CHECK_EQ(raw_score_tensor->shape().dims[2], num_classes_);
} else if (raw_score_tensor->shape().dims.size() == 4) {
// The tensors from GPU inference has dim 4. For gpu-cpu fallback support,
// we allow tensors with 4 dims.
RET_CHECK_EQ(raw_score_tensor->shape().dims[0], 1);
RET_CHECK_EQ(raw_score_tensor->shape().dims[1], 1);
RET_CHECK_EQ(raw_score_tensor->shape().dims[2], num_boxes_);
RET_CHECK_EQ(raw_score_tensor->shape().dims[3], num_classes_);
} else {
return absl::InvalidArgumentError(
"The dimensions of score Tensor must be 3 or 4.");
}
auto raw_box_view = raw_box_tensor->GetCpuReadView();
auto raw_boxes = raw_box_view.buffer<float>();
auto raw_scores_view = raw_score_tensor->GetCpuReadView();
@@ -634,7 +669,7 @@ absl::Status TensorsToDetectionsCalculator::ProcessGPU(
output_detections));
#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)
return absl::OkStatus();
}
@@ -669,18 +704,18 @@ absl::Status TensorsToDetectionsCalculator::LoadOptions(CalculatorContext* cc) {
num_boxes_ = options_.num_boxes();
num_coords_ = options_.num_coords();
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 "
"non-zero.";
max_results_ = options_.max_results();
// 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_EQ(options_.num_keypoints() * options_.num_values_per_keypoint() +
kNumCoordsPerBox,
num_coords_);
ABSL_CHECK_EQ(options_.num_keypoints() * options_.num_values_per_keypoint() +
kNumCoordsPerBox,
num_coords_);
if (kSideInIgnoreClasses(cc).IsConnected()) {
RET_CHECK(!kSideInIgnoreClasses(cc).IsEmpty());
@@ -1111,15 +1146,21 @@ void main() {
int max_wg_size; // typically <= 1024
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1,
&max_wg_size); // y-dim
CHECK_LT(num_classes_, max_wg_size)
<< "# classes must be < " << max_wg_size;
gpu_has_enough_work_groups_ = num_classes_ < max_wg_size;
if (!gpu_has_enough_work_groups_) {
return absl::FailedPreconditionError(absl::StrFormat(
"Hardware limitation: Processing will be done on CPU, because "
"num_classes %d exceeds the max work_group size %d.",
num_classes_, max_wg_size));
}
// TODO support better filtering.
if (class_index_set_.is_allowlist) {
CHECK_EQ(class_index_set_.values.size(),
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
ABSL_CHECK_EQ(class_index_set_.values.size(),
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
<< "Only all classes >= class 0 or >= class 1";
} 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";
}
@@ -1340,11 +1381,12 @@ kernel void scoreKernel(
// TODO support better filtering.
if (class_index_set_.is_allowlist) {
CHECK_EQ(class_index_set_.values.size(),
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
ABSL_CHECK_EQ(class_index_set_.values.size(),
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
<< "Only all classes >= class 0 or >= class 1";
} 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";
}
@@ -1370,7 +1412,13 @@ kernel void scoreKernel(
Tensor::ElementType::kFloat32, Tensor::Shape{1, num_boxes_ * 2});
// # filter classes supported is hardware dependent.
int max_wg_size = score_program_.maxTotalThreadsPerThreadgroup;
CHECK_LT(num_classes_, max_wg_size) << "# classes must be <" << max_wg_size;
gpu_has_enough_work_groups_ = num_classes_ < max_wg_size;
if (!gpu_has_enough_work_groups_) {
return absl::FailedPreconditionError(absl::StrFormat(
"Hardware limitation: Processing will be done on CPU, because "
"num_classes %d exceeds the max work_group size %d.",
num_classes_, max_wg_size));
}
}
#endif // !defined(MEDIAPIPE_DISABLE_GL_COMPUTE)
@@ -142,7 +142,7 @@ absl::Status TensorsToLandmarksCalculator::Process(CalculatorContext* cc) {
RET_CHECK(input_tensors[0].element_type() == Tensor::ElementType::kFloat32);
int num_values = input_tensors[0].shape().num_elements();
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 raw_landmarks = view.buffer<float>();
+38 -11
View File
@@ -13,6 +13,7 @@
# limitations under the License.
#
# Placeholder: load py_proto_library
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library", "mediapipe_proto_library")
licenses(["notice"])
@@ -314,6 +315,7 @@ cc_library(
"//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
] + select({
"//conditions:default": [
"@org_tensorflow//tensorflow/core:framework",
@@ -366,18 +368,18 @@ cc_library(
name = "pack_media_sequence_calculator",
srcs = ["pack_media_sequence_calculator.cc"],
deps = [
":pack_media_sequence_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/formats:detection_cc_proto",
"//mediapipe/framework/formats:location",
"//mediapipe/framework/formats:location_opencv",
"//mediapipe/framework/port:opencv_imgcodecs",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/util/sequence:media_sequence",
"//mediapipe/util/sequence:media_sequence_util",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/core:protos_all_cc",
],
@@ -406,8 +408,13 @@ cc_library(
alwayslink = 1,
)
# This dependency removed tensorflow_jellyfish_deps and xprofilez_with_server because they failed
# Boq conformance test. Weigh your use case to see if this will work for you.
# This dependency removed the following 3 targets because they failed Boq conformance test:
#
# tensorflow_jellyfish_deps
# jfprof_lib
# xprofilez_with_server
#
# If you need them plz consider tensorflow_inference_calculator_no_envelope_loader.
cc_library(
name = "tensorflow_inference_calculator_for_boq",
srcs = ["tensorflow_inference_calculator.cc"],
@@ -424,7 +431,7 @@ cc_library(
"//mediapipe/framework/port:status",
"//mediapipe/framework/tool:status_util",
"@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/strings",
"@com_google_absl//absl/synchronization",
@@ -483,10 +490,10 @@ cc_library(
"//mediapipe/calculators/tensorflow:tensorflow_session_from_frozen_graph_calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/deps:clock",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/framework/tool:status_util",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:protos_all_cc",
] + select({
"//conditions:default": [
@@ -514,10 +521,10 @@ cc_library(
":tensorflow_session_from_frozen_graph_generator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/deps:clock",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/framework/tool:status_util",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:protos_all_cc",
] + select({
"//conditions:default": [
@@ -550,6 +557,7 @@ cc_library(
"//mediapipe/framework/deps:file_path",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/cc/saved_model:constants",
"@org_tensorflow//tensorflow/cc/saved_model:loader_lite",
@@ -627,6 +635,7 @@ cc_library(
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/framework/tool:status_util",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/cc/saved_model:constants",
@@ -648,6 +657,7 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:framework",
],
alwayslink = 1,
@@ -662,6 +672,7 @@ cc_library(
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
"@org_tensorflow//tensorflow/core:framework",
],
alwayslink = 1,
@@ -677,6 +688,7 @@ cc_library(
"//mediapipe/framework/formats:time_series_header_cc_proto",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
] + select({
"//conditions:default": [
"@org_tensorflow//tensorflow/core:framework",
@@ -711,6 +723,7 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@org_tensorflow//tensorflow/core/platform:bfloat16",
] + select({
"//conditions:default": [
"@org_tensorflow//tensorflow/core:framework",
@@ -773,6 +786,7 @@ cc_library(
"//mediapipe/framework/port:status",
"//mediapipe/util:audio_decoder_cc_proto",
"//mediapipe/util/sequence:media_sequence",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/core:protos_all_cc",
],
@@ -787,6 +801,8 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:framework",
],
alwayslink = 1,
@@ -800,6 +816,7 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:framework",
],
alwayslink = 1,
@@ -813,6 +830,7 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/log:absl_log",
"@org_tensorflow//tensorflow/core:framework",
],
alwayslink = 1,
@@ -826,6 +844,8 @@ cc_library(
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:packet",
"//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",
],
alwayslink = 1,
@@ -920,22 +940,24 @@ cc_test(
srcs = ["pack_media_sequence_calculator_test.cc"],
deps = [
":pack_media_sequence_calculator",
":pack_media_sequence_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_runner",
"//mediapipe/framework:packet",
"//mediapipe/framework:timestamp",
"//mediapipe/framework/formats:detection_cc_proto",
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/formats:image_frame_opencv",
"//mediapipe/framework/formats:location",
"//mediapipe/framework/formats:location_opencv",
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:opencv_imgcodecs",
"//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/status",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
"@org_tensorflow//tensorflow/core:protos_all_cc",
],
)
@@ -1077,6 +1099,7 @@ cc_test(
linkstatic = 1,
deps = [
":tensor_to_image_frame_calculator",
":tensor_to_image_frame_calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:calculator_runner",
"//mediapipe/framework/formats:image_frame",
@@ -1117,6 +1140,7 @@ cc_test(
"//mediapipe/util:packet_test_util",
"@org_tensorflow//tensorflow/core:framework",
"@org_tensorflow//tensorflow/core:protos_all_cc",
"@org_tensorflow//tensorflow/core/platform:bfloat16",
],
)
@@ -1162,6 +1186,7 @@ cc_test(
"//mediapipe/framework/port:rectangle",
"//mediapipe/util:audio_decoder_cc_proto",
"//mediapipe/util/sequence:media_sequence",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
"@org_tensorflow//tensorflow/core:protos_all_cc",
@@ -1243,6 +1268,8 @@ cc_test(
"//mediapipe/framework/tool:sink",
"//mediapipe/framework/tool:validate_type",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
] + select({
"//conditions:default": [
"@org_tensorflow//tensorflow/core:direct_session",
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/tensorflow/matrix_to_tensor_calculator_options.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/matrix.h"
@@ -28,7 +29,7 @@ namespace mediapipe {
namespace {
absl::Status FillTimeSeriesHeaderIfValid(const Packet& header_packet,
TimeSeriesHeader* header) {
CHECK(header);
ABSL_CHECK(header);
if (header_packet.IsEmpty()) {
return absl::UnknownError("No header found.");
}
@@ -12,21 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/strings/match.h"
#include "absl/strings/strip.h"
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
#include "mediapipe/calculators/tensorflow/pack_media_sequence_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/location.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/ret_check.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/util/sequence/media_sequence.h"
#include "mediapipe/util/sequence/media_sequence_util.h"
#include "tensorflow/core/example/example.pb.h"
@@ -36,7 +38,11 @@ namespace mediapipe {
const char kSequenceExampleTag[] = "SEQUENCE_EXAMPLE";
const char kImageTag[] = "IMAGE";
const char kImageLabelPrefixTag[] = "IMAGE_LABEL_";
const char kClipLabelPrefixTag[] = "CLIP_LABEL_";
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 kIntFeaturePrefixTag[] = "INT_FEATURE_";
const char kBytesFeaturePrefixTag[] = "BYTES_FEATURE_";
@@ -44,6 +50,7 @@ const char kForwardFlowEncodedTag[] = "FORWARD_FLOW_ENCODED";
const char kBBoxTag[] = "BBOX";
const char kKeypointsTag[] = "KEYPOINTS";
const char kSegmentationMaskTag[] = "CLASS_SEGMENTATION";
const char kClipMediaIdTag[] = "CLIP_MEDIA_ID";
namespace tf = ::tensorflow;
namespace mpms = mediapipe::mediasequence;
@@ -55,16 +62,23 @@ namespace mpms = mediapipe::mediasequence;
// context features can be supplied verbatim in the calculator's options. The
// SequenceExample will conform to the description in media_sequence.h.
//
// The supported input stream tags are "IMAGE", which stores the encoded
// images from the OpenCVImageEncoderCalculator, "FORWARD_FLOW_ENCODED", which
// stores the encoded optical flow from the same calculator, "BBOX" which stores
// bounding boxes from vector<Detections>, and streams with the
// "FLOAT_FEATURE_${NAME}" pattern, which stores the values from vector<float>'s
// associated with the name ${NAME}. "KEYPOINTS" stores a map of 2D keypoints
// from flat_hash_map<string, vector<pair<float, float>>>. "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.
// The supported input stream tags are:
// * "IMAGE", which stores the encoded images from the
// OpenCVImageEncoderCalculator,
// * "IMAGE_LABEL", which stores whole image labels from Detection,
// * "FORWARD_FLOW_ENCODED", which stores the encoded optical flow from the same
// calculator,
// * "BBOX" which stores bounding boxes from vector<Detections>,
// * streams with the "FLOAT_FEATURE_${NAME}" pattern, which stores the values
// from vector<float>'s associated with the name ${NAME},
// * "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.
// "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:
// node {
@@ -100,6 +114,9 @@ class PackMediaSequenceCalculator : public CalculatorBase {
static absl::Status GetContract(CalculatorContract* cc) {
RET_CHECK(cc->InputSidePackets().HasTag(kSequenceExampleTag));
cc->InputSidePackets().Tag(kSequenceExampleTag).Set<tf::SequenceExample>();
if (cc->InputSidePackets().HasTag(kClipMediaIdTag)) {
cc->InputSidePackets().Tag(kClipMediaIdTag).Set<std::string>();
}
if (cc->Inputs().HasTag(kForwardFlowEncodedTag)) {
cc->Inputs()
@@ -112,6 +129,10 @@ class PackMediaSequenceCalculator : public CalculatorBase {
for (const auto& tag : cc->Inputs().GetTags()) {
if (absl::StartsWith(tag, kImageTag)) {
if (absl::StartsWith(tag, kImageLabelPrefixTag)) {
cc->Inputs().Tag(tag).Set<Detection>();
continue;
}
std::string key = "";
if (tag != kImageTag) {
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
@@ -150,9 +171,18 @@ class PackMediaSequenceCalculator : public CalculatorBase {
}
cc->Inputs().Tag(tag).Set<std::vector<Detection>>();
}
if (absl::StartsWith(tag, kClipLabelPrefixTag)) {
cc->Inputs().Tag(tag).Set<Detection>();
}
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag)) {
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)) {
cc->Inputs().Tag(tag).Set<std::vector<float>>();
}
@@ -164,8 +194,8 @@ class PackMediaSequenceCalculator : public CalculatorBase {
}
}
CHECK(cc->Outputs().HasTag(kSequenceExampleTag) ||
cc->OutputSidePackets().HasTag(kSequenceExampleTag))
RET_CHECK(cc->Outputs().HasTag(kSequenceExampleTag) ||
cc->OutputSidePackets().HasTag(kSequenceExampleTag))
<< "Neither the output stream nor the output side packet is set to "
"output the sequence example.";
if (cc->Outputs().HasTag(kSequenceExampleTag)) {
@@ -184,6 +214,11 @@ class PackMediaSequenceCalculator : public CalculatorBase {
cc->InputSidePackets()
.Tag(kSequenceExampleTag)
.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 =
cc->Options<PackMediaSequenceCalculatorOptions>().context_feature_map();
@@ -197,8 +232,19 @@ class PackMediaSequenceCalculator : public CalculatorBase {
replace_keypoints_ = false;
if (cc->Options<PackMediaSequenceCalculatorOptions>()
.replace_data_instead_of_append()) {
// Clear the existing values under the same key.
for (const auto& tag : cc->Inputs().GetTags()) {
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 = "";
if (tag != kImageTag) {
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
@@ -227,12 +273,41 @@ class PackMediaSequenceCalculator : public CalculatorBase {
mpms::ClearBBoxNumRegions(key, sequence_.get());
mpms::ClearBBoxLabelString(key, sequence_.get());
mpms::ClearBBoxLabelIndex(key, sequence_.get());
mpms::ClearBBoxLabelConfidence(key, sequence_.get());
mpms::ClearBBoxClassString(key, sequence_.get());
mpms::ClearBBoxClassIndex(key, sequence_.get());
mpms::ClearBBoxTrackString(key, sequence_.get());
mpms::ClearBBoxTrackIndex(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)) {
std::string key = tag.substr(sizeof(kFloatFeaturePrefixTag) /
sizeof(*kFloatFeaturePrefixTag) -
@@ -343,6 +418,34 @@ class PackMediaSequenceCalculator : public CalculatorBase {
if (absl::StartsWith(tag, kImageTag) &&
!cc->Inputs().Tag(tag).IsEmpty()) {
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) {
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
if (tag[tag_length] == '_') {
@@ -393,6 +496,7 @@ class PackMediaSequenceCalculator : public CalculatorBase {
mpms::ClearBBoxNumRegions(prefix, sequence_.get());
mpms::ClearBBoxLabelString(prefix, sequence_.get());
mpms::ClearBBoxLabelIndex(prefix, sequence_.get());
mpms::ClearBBoxLabelConfidence(prefix, sequence_.get());
mpms::ClearBBoxClassString(prefix, sequence_.get());
mpms::ClearBBoxClassIndex(prefix, sequence_.get());
mpms::ClearBBoxTrackString(prefix, sequence_.get());
@@ -405,6 +509,33 @@ class PackMediaSequenceCalculator : public CalculatorBase {
}
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.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 label and score fields.
if (!detection.label_id().empty()) {
if (detection.label_id().size() != detection.label().size()) {
return absl::InvalidArgumentError(
"Different size of detection.label_id and detection.label");
}
}
for (int i = 0; i < detection.label().size(); ++i) {
if (!detection.label_id().empty()) {
mpms::AddClipLabelIndex(key, detection.label_id(i),
sequence_.get());
}
mpms::AddClipLabelString(key, detection.label(i), sequence_.get());
mpms::AddClipLabelConfidence(key, detection.score(i),
sequence_.get());
}
}
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag) &&
!cc->Inputs().Tag(tag).IsEmpty()) {
std::string key =
@@ -412,9 +543,36 @@ class PackMediaSequenceCalculator : public CalculatorBase {
sizeof(*kFloatContextFeaturePrefixTag) -
1);
RET_CHECK_EQ(cc->InputTimestamp(), Timestamp::PostStream());
mpms::SetContextFeatureFloats(
key, cc->Inputs().Tag(tag).Get<std::vector<float>>(),
sequence_.get());
for (const auto& value :
cc->Inputs().Tag(tag).Get<std::vector<float>>()) {
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) &&
!cc->Inputs().Tag(tag).IsEmpty()) {
@@ -460,6 +618,7 @@ class PackMediaSequenceCalculator : public CalculatorBase {
}
std::vector<Location> predicted_locations;
std::vector<std::string> predicted_class_strings;
std::vector<float> predicted_class_confidences;
std::vector<int> predicted_label_ids;
for (auto& detection :
cc->Inputs().Tag(tag).Get<std::vector<Detection>>()) {
@@ -488,6 +647,9 @@ class PackMediaSequenceCalculator : public CalculatorBase {
if (detection.label_id_size() > 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()) {
@@ -501,6 +663,10 @@ class PackMediaSequenceCalculator : public CalculatorBase {
if (!predicted_label_ids.empty()) {
mpms::AddBBoxLabelIndex(key, predicted_label_ids, sequence_.get());
}
if (!predicted_class_confidences.empty()) {
mpms::AddBBoxLabelConfidence(key, predicted_class_confidences,
sequence_.get());
}
}
}
}
@@ -548,10 +714,14 @@ class PackMediaSequenceCalculator : public CalculatorBase {
}
}
}
if (clip_media_id_.has_value()) {
mpms::SetClipMediaId(*clip_media_id_, sequence_.get());
}
return absl::OkStatus();
}
std::unique_ptr<tf::SequenceExample> sequence_;
std::optional<std::string> clip_media_id_ = std::nullopt;
std::map<std::string, bool> features_present_;
bool replace_keypoints_;
};
@@ -12,28 +12,32 @@
// See the License for the specific language governing permissions and
// 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/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/tensorflow/pack_media_sequence_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/formats/location.h"
#include "mediapipe/framework/formats/location_opencv.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h"
#include "mediapipe/framework/packet.h"
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
#include "mediapipe/framework/port/status_matchers.h"
#include "mediapipe/framework/timestamp.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/feature.pb.h"
#include "testing/base/public/gmock.h"
#include "testing/base/public/gunit.h"
namespace mediapipe {
namespace {
@@ -55,13 +59,22 @@ constexpr char kBytesFeatureTestTag[] = "BYTES_FEATURE_TEST";
constexpr char kForwardFlowEncodedTag[] = "FORWARD_FLOW_ENCODED";
constexpr char kFloatContextFeatureOtherTag[] = "FLOAT_CONTEXT_FEATURE_OTHER";
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 kFloatFeatureTestTag[] = "FLOAT_FEATURE_TEST";
constexpr char kIntFeatureOtherTag[] = "INT_FEATURE_OTHER";
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 kSequenceExampleTag[] = "SEQUENCE_EXAMPLE";
constexpr char kImageTag[] = "IMAGE";
constexpr char kClipMediaIdTag[] = "CLIP_MEDIA_ID";
constexpr char kClipLabelTestTag[] = "CLIP_LABEL_TEST";
constexpr char kClipLabelOtherTag[] = "CLIP_LABEL_OTHER";
class PackMediaSequenceCalculatorTest : public ::testing::Test {
protected:
@@ -69,10 +82,14 @@ class PackMediaSequenceCalculatorTest : public ::testing::Test {
const tf::Features& features,
const bool output_only_if_all_present,
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;
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");
for (const std::string& stream : input_streams) {
config.add_input_stream(stream);
@@ -96,7 +113,8 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoImages) {
mpms::SetClipMediaId(test_video_id, input_sequence.get());
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
std::vector<uchar> bytes;
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
ASSERT_TRUE(
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
OpenCvImageEncoderCalculatorResults encoded_image;
encoded_image.set_encoded_image(bytes.data(), bytes.size());
encoded_image.set_width(2);
@@ -139,7 +157,8 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoPrefixedImages) {
mpms::SetClipMediaId(test_video_id, input_sequence.get());
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
std::vector<uchar> bytes;
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
ASSERT_TRUE(
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
OpenCvImageEncoderCalculatorResults encoded_image;
encoded_image.set_encoded_image(bytes.data(), bytes.size());
encoded_image.set_width(2);
@@ -312,6 +331,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) {
SetUpCalculator({"FLOAT_FEATURE_TEST:test"}, {}, false, true, true);
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
@@ -367,6 +456,315 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoContextFloatLists) {
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) {
tf::Features context;
(*context.mutable_feature())["TEST"].mutable_bytes_list()->add_value("YES");
@@ -378,7 +776,8 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksAdditionalContext) {
Adopt(input_sequence.release());
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
std::vector<uchar> bytes;
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
ASSERT_TRUE(
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
OpenCvImageEncoderCalculatorResults encoded_image;
encoded_image.set_encoded_image(bytes.data(), bytes.size());
auto image_ptr =
@@ -410,7 +809,8 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoForwardFlowEncodeds) {
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
std::vector<uchar> bytes;
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
ASSERT_TRUE(
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
std::string test_flow_string(bytes.begin(), bytes.end());
OpenCvImageEncoderCalculatorResults encoded_flow;
encoded_flow.set_encoded_image(test_flow_string);
@@ -526,6 +926,10 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoBBoxDetections) {
auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i);
ASSERT_EQ(0, class_indices[0]);
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]);
}
}
@@ -618,7 +1022,8 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksBBoxWithImages) {
}
cv::Mat image(height, width, CV_8UC3, cv::Scalar(0, 0, 255));
std::vector<uchar> bytes;
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
ASSERT_TRUE(
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
OpenCvImageEncoderCalculatorResults encoded_image;
encoded_image.set_encoded_image(bytes.data(), bytes.size());
encoded_image.set_width(width);
@@ -667,6 +1072,10 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksBBoxWithImages) {
auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i);
ASSERT_EQ(0, class_indices[0]);
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]);
}
}
@@ -757,6 +1166,365 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoMaskDetections) {
testing::ElementsAreArray(::std::vector<std::string>({"mask"})));
}
TEST_F(PackMediaSequenceCalculatorTest, PackTwoClipLabels) {
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;
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)));
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));
}
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 labels 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.label")));
}
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) {
SetUpCalculator(
{"FORWARD_FLOW_ENCODED:flow", "FLOAT_FEATURE_I3D_FLOW:feature"}, {},
@@ -767,7 +1535,8 @@ TEST_F(PackMediaSequenceCalculatorTest, MissingStreamOK) {
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
std::vector<uchar> bytes;
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
ASSERT_TRUE(
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
std::string test_flow_string(bytes.begin(), bytes.end());
OpenCvImageEncoderCalculatorResults encoded_flow;
encoded_flow.set_encoded_image(test_flow_string);
@@ -813,7 +1582,8 @@ TEST_F(PackMediaSequenceCalculatorTest, MissingStreamNotOK) {
mpms::SetClipMediaId(test_video_id, input_sequence.get());
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
std::vector<uchar> bytes;
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
ASSERT_TRUE(
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
std::string test_flow_string(bytes.begin(), bytes.end());
OpenCvImageEncoderCalculatorResults encoded_flow;
encoded_flow.set_encoded_image(test_flow_string);
@@ -970,7 +1740,8 @@ TEST_F(PackMediaSequenceCalculatorTest, TestReconcilingAnnotations) {
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
std::vector<uchar> bytes;
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
ASSERT_TRUE(
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
OpenCvImageEncoderCalculatorResults encoded_image;
encoded_image.set_encoded_image(bytes.data(), bytes.size());
encoded_image.set_width(2);
@@ -1021,7 +1792,8 @@ TEST_F(PackMediaSequenceCalculatorTest, TestOverwritingAndReconciling) {
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
std::vector<uchar> bytes;
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
ASSERT_TRUE(
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
OpenCvImageEncoderCalculatorResults encoded_image;
encoded_image.set_encoded_image(bytes.data(), bytes.size());
int height = 2;
@@ -1057,6 +1829,7 @@ TEST_F(PackMediaSequenceCalculatorTest, TestOverwritingAndReconciling) {
mpms::AddBBoxNumRegions(-1, input_sequence.get());
mpms::AddBBoxLabelString({"anything"}, input_sequence.get());
mpms::AddBBoxLabelIndex({-1}, input_sequence.get());
mpms::AddBBoxLabelConfidence({-1}, input_sequence.get());
mpms::AddBBoxClassString({"anything"}, input_sequence.get());
mpms::AddBBoxClassIndex({-1}, input_sequence.get());
mpms::AddBBoxTrackString({"anything"}, input_sequence.get());
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/log/absl_log.h"
#include "mediapipe/calculators/tensorflow/tensor_squeeze_dimensions_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/ret_check.h"
@@ -99,10 +100,11 @@ class TensorSqueezeDimensionsCalculator : public CalculatorBase {
}
}
if (remove_dims_.empty()) {
LOG(ERROR) << "TensorSqueezeDimensionsCalculator is squeezing input with "
"no single-dimensions. Calculator will be a no-op.";
LOG(ERROR) << "Input to TensorSqueezeDimensionsCalculator has shape "
<< tensor_shape.DebugString();
ABSL_LOG(ERROR)
<< "TensorSqueezeDimensionsCalculator is squeezing input with "
"no single-dimensions. Calculator will be a no-op.";
ABSL_LOG(ERROR) << "Input to TensorSqueezeDimensionsCalculator has shape "
<< tensor_shape.DebugString();
}
}
};
@@ -14,6 +14,7 @@
#include <iostream>
#include "absl/log/absl_check.h"
#include "mediapipe/calculators/tensorflow/tensor_to_image_frame_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame.h"
@@ -65,6 +66,7 @@ class TensorToImageFrameCalculator : public CalculatorBase {
private:
float scale_factor_;
bool scale_per_frame_min_max_;
};
REGISTER_CALCULATOR(TensorToImageFrameCalculator);
@@ -88,6 +90,8 @@ absl::Status TensorToImageFrameCalculator::GetContract(CalculatorContract* cc) {
absl::Status TensorToImageFrameCalculator::Open(CalculatorContext* cc) {
scale_factor_ =
cc->Options<TensorToImageFrameCalculatorOptions>().scale_factor();
scale_per_frame_min_max_ = cc->Options<TensorToImageFrameCalculatorOptions>()
.scale_per_frame_min_max();
cc->SetOffset(TimestampDiff(0));
return absl::OkStatus();
}
@@ -96,7 +100,7 @@ absl::Status TensorToImageFrameCalculator::Process(CalculatorContext* cc) {
const tf::Tensor& input_tensor = cc->Inputs().Tag(kTensor).Get<tf::Tensor>();
int32_t depth = 1;
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: "
<< input_tensor.dims();
depth = input_tensor.dim_size(2);
@@ -109,16 +113,38 @@ absl::Status TensorToImageFrameCalculator::Process(CalculatorContext* cc) {
auto format = (depth == 3 ? ImageFormat::SRGB : ImageFormat::GRAY8);
const int32_t total_size = height * width * depth;
if (scale_per_frame_min_max_) {
RET_CHECK_EQ(input_tensor.dtype(), tensorflow::DT_FLOAT)
<< "Setting scale_per_frame_min_max requires FLOAT input tensors.";
}
::std::unique_ptr<const ImageFrame> output;
if (input_tensor.dtype() == tensorflow::DT_FLOAT) {
// Allocate buffer with alignments.
std::unique_ptr<uint8_t[]> buffer(
new (std::align_val_t(EIGEN_MAX_ALIGN_BYTES)) uint8_t[total_size]);
auto data = input_tensor.flat<float>().data();
float min = 1e23;
float max = -1e23;
if (scale_per_frame_min_max_) {
for (int i = 0; i < total_size; ++i) {
float d = scale_factor_ * data[i];
if (d < min) {
min = d;
}
if (d > max) {
max = d;
}
}
}
for (int i = 0; i < total_size; ++i) {
float d = scale_factor_ * data[i];
if (d < 0) d = 0;
if (d > 255) d = 255;
float d = data[i];
if (scale_per_frame_min_max_) {
d = 255 * (d - min) / (max - min + 1e-9);
} else {
d = scale_factor_ * d;
if (d < 0) d = 0;
if (d > 255) d = 255;
}
buffer[i] = d;
}
output = ::absl::make_unique<ImageFrame>(
@@ -26,4 +26,8 @@ message TensorToImageFrameCalculatorOptions {
// Multiples floating point tensor outputs by this value before converting to
// uint8. This is useful for converting from range [0, 1] to [0, 255]
optional float scale_factor = 1 [default = 1.0];
// If true, scales any FLOAT tensor input of [min, max] to be between [0, 255]
// per frame. This overrides any explicit scale_factor.
optional bool scale_per_frame_min_max = 2 [default = false];
}
@@ -11,7 +11,9 @@
// 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 <type_traits>
#include "mediapipe/calculators/tensorflow/tensor_to_image_frame_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/formats/image_frame.h"
@@ -32,11 +34,14 @@ constexpr char kImage[] = "IMAGE";
template <class TypeParam>
class TensorToImageFrameCalculatorTest : public ::testing::Test {
protected:
void SetUpRunner() {
void SetUpRunner(bool scale_per_frame_min_max = false) {
CalculatorGraphConfig::Node config;
config.set_calculator("TensorToImageFrameCalculator");
config.add_input_stream("TENSOR:input_tensor");
config.add_output_stream("IMAGE:output_image");
config.mutable_options()
->MutableExtension(mediapipe::TensorToImageFrameCalculatorOptions::ext)
->set_scale_per_frame_min_max(scale_per_frame_min_max);
runner_ = absl::make_unique<CalculatorRunner>(config);
}
@@ -157,4 +162,47 @@ TYPED_TEST(TensorToImageFrameCalculatorTest,
}
}
TYPED_TEST(TensorToImageFrameCalculatorTest,
Converts3DTensorToImageFrame2DGrayWithScaling) {
this->SetUpRunner(true);
auto& runner = this->runner_;
constexpr int kWidth = 16;
constexpr int kHeight = 8;
const tf::TensorShape tensor_shape{kHeight, kWidth};
auto tensor = absl::make_unique<tf::Tensor>(
tf::DataTypeToEnum<TypeParam>::v(), tensor_shape);
auto tensor_vec = tensor->template flat<TypeParam>().data();
// Writing sequence of integers as floats which we want normalized.
tensor_vec[0] = 255;
for (int i = 1; i < kWidth * kHeight; ++i) {
tensor_vec[i] = 200;
}
const int64_t time = 1234;
runner->MutableInputs()->Tag(kTensor).packets.push_back(
Adopt(tensor.release()).At(Timestamp(time)));
if (!std::is_same<TypeParam, float>::value) {
EXPECT_FALSE(runner->Run().ok());
return; // Short circuit because does not apply to other types.
} else {
EXPECT_TRUE(runner->Run().ok());
const std::vector<Packet>& output_packets =
runner->Outputs().Tag(kImage).packets;
EXPECT_EQ(1, output_packets.size());
EXPECT_EQ(time, output_packets[0].Timestamp().Value());
const ImageFrame& output_image = output_packets[0].Get<ImageFrame>();
EXPECT_EQ(ImageFormat::GRAY8, output_image.Format());
EXPECT_EQ(kWidth, output_image.Width());
EXPECT_EQ(kHeight, output_image.Height());
EXPECT_EQ(255, output_image.PixelData()[0]);
for (int i = 1; i < kWidth * kHeight; ++i) {
const uint8_t pixel_value = output_image.PixelData()[i];
ASSERT_EQ(0, pixel_value);
}
}
}
} // namespace mediapipe

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