Compare commits
@@ -40,18 +40,16 @@ body:
|
|||||||
label: Programming Language and version (e.g. C++, Python, Java)
|
label: Programming Language and version (e.g. C++, Python, Java)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: input
|
||||||
id: current_model
|
id: current_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the actual behavior
|
label: Describe the actual behavior
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: input
|
||||||
id: expected_model
|
id: expected_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the expected behaviour
|
label: Describe the expected behaviour
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
@@ -41,18 +41,16 @@ body:
|
|||||||
label: Task name (e.g. Image classification, Gesture recognition etc.)
|
label: Task name (e.g. Image classification, Gesture recognition etc.)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: input
|
||||||
id: current_model
|
id: current_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the actual behavior
|
label: Describe the actual behavior
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: input
|
||||||
id: expected_model
|
id: expected_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the expected behaviour
|
label: Describe the expected behaviour
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
@@ -31,18 +31,16 @@ body:
|
|||||||
label: URL that shows the problem
|
label: URL that shows the problem
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: input
|
||||||
id: current_model
|
id: current_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the actual behavior
|
label: Describe the actual behavior
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: input
|
||||||
id: expected_model
|
id: expected_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the expected behaviour
|
label: Describe the expected behaviour
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
@@ -28,37 +28,33 @@ body:
|
|||||||
- 'No'
|
- 'No'
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: input
|
||||||
id: behaviour
|
id: behaviour
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the feature and the current behaviour/state
|
label: Describe the feature and the current behaviour/state
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: input
|
||||||
id: api_change
|
id: api_change
|
||||||
attributes:
|
attributes:
|
||||||
label: Will this change the current API? How?
|
label: Will this change the current API? How?
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: input
|
||||||
id: benifit
|
id: benifit
|
||||||
attributes:
|
attributes:
|
||||||
label: Who will benefit with this feature?
|
label: Who will benefit with this feature?
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: input
|
||||||
id: use_case
|
id: use_case
|
||||||
attributes:
|
attributes:
|
||||||
label: Please specify the use cases for this feature
|
label: Please specify the use cases for this feature
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: input
|
||||||
id: info_other
|
id: info_other
|
||||||
attributes:
|
attributes:
|
||||||
label: Any Other info
|
label: Any Other info
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|||||||
@@ -87,14 +87,13 @@ body:
|
|||||||
placeholder:
|
placeholder:
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: input
|
||||||
id: what-happened
|
id: what-happened
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the problem
|
label: Describe the problem
|
||||||
description: Provide the exact sequence of commands / steps that you executed before running into the [problem](https://google.github.io/mediapipe/getting_started/getting_started.html)
|
description: Provide the exact sequence of commands / steps that you executed before running into the [problem](https://google.github.io/mediapipe/getting_started/getting_started.html)
|
||||||
placeholder: Tell us what you see!
|
placeholder: Tell us what you see!
|
||||||
value: "A bug happened!"
|
value: "A bug happened!"
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
@@ -80,18 +80,16 @@ body:
|
|||||||
label: Xcode & Tulsi version (if issue is related to building for iOS)
|
label: Xcode & Tulsi version (if issue is related to building for iOS)
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: input
|
||||||
id: current_model
|
id: current_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the actual behavior
|
label: Describe the actual behavior
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: input
|
||||||
id: expected_model
|
id: expected_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the expected behaviour
|
label: Describe the expected behaviour
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
@@ -48,18 +48,16 @@ body:
|
|||||||
placeholder: e.g. C++, Python, Java
|
placeholder: e.g. C++, Python, Java
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: input
|
||||||
id: current_model
|
id: current_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the actual behavior
|
label: Describe the actual behavior
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: input
|
||||||
id: expected_model
|
id: expected_model
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the expected behaviour
|
label: Describe the expected behaviour
|
||||||
render: shell
|
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ jobs:
|
|||||||
# Limit the No. of API calls in one run default value is 30.
|
# Limit the No. of API calls in one run default value is 30.
|
||||||
operations-per-run: 500
|
operations-per-run: 500
|
||||||
# Prevent to remove stale label when PRs or issues are updated.
|
# Prevent to remove stale label when PRs or issues are updated.
|
||||||
remove-stale-when-updated: false
|
remove-stale-when-updated: true
|
||||||
|
# List of labels to remove when issues/PRs unstale.
|
||||||
|
labels-to-remove-when-unstale: 'stat:awaiting response'
|
||||||
# comment on issue if not active for more then 7 days.
|
# comment on issue if not active for more then 7 days.
|
||||||
stale-issue-message: 'This issue has been marked stale because it has no recent activity since 7 days. It will be closed if no further activity occurs. Thank you.'
|
stale-issue-message: 'This issue has been marked stale because it has no recent activity since 7 days. It will be closed if no further activity occurs. Thank you.'
|
||||||
# comment on PR if not active for more then 14 days.
|
# comment on PR if not active for more then 14 days.
|
||||||
|
|||||||
@@ -73,12 +73,9 @@ http_archive(
|
|||||||
http_archive(
|
http_archive(
|
||||||
name = "zlib",
|
name = "zlib",
|
||||||
build_file = "@//third_party:zlib.BUILD",
|
build_file = "@//third_party:zlib.BUILD",
|
||||||
sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1",
|
sha256 = "b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30",
|
||||||
strip_prefix = "zlib-1.2.11",
|
strip_prefix = "zlib-1.2.13",
|
||||||
urls = [
|
url = "http://zlib.net/fossils/zlib-1.2.13.tar.gz",
|
||||||
"http://mirror.bazel.build/zlib.net/fossils/zlib-1.2.11.tar.gz",
|
|
||||||
"http://zlib.net/fossils/zlib-1.2.11.tar.gz", # 2017-01-15
|
|
||||||
],
|
|
||||||
patches = [
|
patches = [
|
||||||
"@//third_party:zlib.diff",
|
"@//third_party:zlib.diff",
|
||||||
],
|
],
|
||||||
@@ -157,19 +154,19 @@ http_archive(
|
|||||||
# 2020-08-21
|
# 2020-08-21
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "com_github_glog_glog",
|
name = "com_github_glog_glog",
|
||||||
strip_prefix = "glog-3a0d4d22c5ae0b9a2216988411cfa6bf860cc372",
|
strip_prefix = "glog-0.6.0",
|
||||||
sha256 = "170d08f80210b82d95563f4723a15095eff1aad1863000e8eeb569c96a98fefb",
|
sha256 = "8a83bf982f37bb70825df71a9709fa90ea9f4447fb3c099e1d720a439d88bad6",
|
||||||
urls = [
|
urls = [
|
||||||
"https://github.com/google/glog/archive/3a0d4d22c5ae0b9a2216988411cfa6bf860cc372.zip",
|
"https://github.com/google/glog/archive/v0.6.0.tar.gz",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "com_github_glog_glog_no_gflags",
|
name = "com_github_glog_glog_no_gflags",
|
||||||
strip_prefix = "glog-3a0d4d22c5ae0b9a2216988411cfa6bf860cc372",
|
strip_prefix = "glog-0.6.0",
|
||||||
sha256 = "170d08f80210b82d95563f4723a15095eff1aad1863000e8eeb569c96a98fefb",
|
sha256 = "8a83bf982f37bb70825df71a9709fa90ea9f4447fb3c099e1d720a439d88bad6",
|
||||||
build_file = "@//third_party:glog_no_gflags.BUILD",
|
build_file = "@//third_party:glog_no_gflags.BUILD",
|
||||||
urls = [
|
urls = [
|
||||||
"https://github.com/google/glog/archive/3a0d4d22c5ae0b9a2216988411cfa6bf860cc372.zip",
|
"https://github.com/google/glog/archive/v0.6.0.tar.gz",
|
||||||
],
|
],
|
||||||
patches = [
|
patches = [
|
||||||
"@//third_party:com_github_glog_glog.diff",
|
"@//third_party:com_github_glog_glog.diff",
|
||||||
@@ -179,6 +176,25 @@ http_archive(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 2023-06-05
|
||||||
|
# This version of Glog is required for Windows support, but currently causes
|
||||||
|
# crashes on some Android devices.
|
||||||
|
http_archive(
|
||||||
|
name = "com_github_glog_glog_windows",
|
||||||
|
strip_prefix = "glog-3a0d4d22c5ae0b9a2216988411cfa6bf860cc372",
|
||||||
|
sha256 = "170d08f80210b82d95563f4723a15095eff1aad1863000e8eeb569c96a98fefb",
|
||||||
|
urls = [
|
||||||
|
"https://github.com/google/glog/archive/3a0d4d22c5ae0b9a2216988411cfa6bf860cc372.zip",
|
||||||
|
],
|
||||||
|
patches = [
|
||||||
|
"@//third_party:com_github_glog_glog.diff",
|
||||||
|
"@//third_party:com_github_glog_glog_windows_patch.diff",
|
||||||
|
],
|
||||||
|
patch_args = [
|
||||||
|
"-p1",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# easyexif
|
# easyexif
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "easyexif",
|
name = "easyexif",
|
||||||
@@ -485,10 +501,10 @@ http_archive(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# TensorFlow repo should always go after the other external dependencies.
|
# TensorFlow repo should always go after the other external dependencies.
|
||||||
# TF on 2023-06-13.
|
# TF on 2023-07-26.
|
||||||
_TENSORFLOW_GIT_COMMIT = "491681a5620e41bf079a582ac39c585cc86878b9"
|
_TENSORFLOW_GIT_COMMIT = "e92261fd4cec0b726692081c4d2966b75abf31dd"
|
||||||
# curl -L https://github.com/tensorflow/tensorflow/archive/<TENSORFLOW_GIT_COMMIT>.tar.gz | shasum -a 256
|
# curl -L https://github.com/tensorflow/tensorflow/archive/<TENSORFLOW_GIT_COMMIT>.tar.gz | shasum -a 256
|
||||||
_TENSORFLOW_SHA256 = "9f76389af7a2835e68413322c1eaabfadc912f02a76d71dc16be507f9ca3d3ac"
|
_TENSORFLOW_SHA256 = "478a229bd4ec70a5b568ac23b5ea013d9fca46a47d6c43e30365a0412b9febf4"
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "org_tensorflow",
|
name = "org_tensorflow",
|
||||||
urls = [
|
urls = [
|
||||||
@@ -496,6 +512,7 @@ http_archive(
|
|||||||
],
|
],
|
||||||
patches = [
|
patches = [
|
||||||
"@//third_party:org_tensorflow_compatibility_fixes.diff",
|
"@//third_party:org_tensorflow_compatibility_fixes.diff",
|
||||||
|
"@//third_party:org_tensorflow_system_python.diff",
|
||||||
# Diff is generated with a script, don't update it manually.
|
# Diff is generated with a script, don't update it manually.
|
||||||
"@//third_party:org_tensorflow_custom_ops.diff",
|
"@//third_party:org_tensorflow_custom_ops.diff",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ as the primary developer documentation site for MediaPipe as of April 3, 2023.*
|
|||||||
3. The [`hello world`] example uses a simple MediaPipe graph in the
|
3. The [`hello world`] example uses a simple MediaPipe graph in the
|
||||||
`PrintHelloWorld()` function, defined in a [`CalculatorGraphConfig`] proto.
|
`PrintHelloWorld()` function, defined in a [`CalculatorGraphConfig`] proto.
|
||||||
|
|
||||||
```C++
|
```c++
|
||||||
absl::Status PrintHelloWorld() {
|
absl::Status PrintHelloWorld() {
|
||||||
// Configures a simple graph, which concatenates 2 PassThroughCalculators.
|
// Configures a simple graph, which concatenates 2 PassThroughCalculators.
|
||||||
CalculatorGraphConfig config = ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
|
CalculatorGraphConfig config = ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
|
||||||
@@ -126,7 +126,7 @@ as the primary developer documentation site for MediaPipe as of April 3, 2023.*
|
|||||||
```c++
|
```c++
|
||||||
mediapipe::Packet packet;
|
mediapipe::Packet packet;
|
||||||
while (poller.Next(&packet)) {
|
while (poller.Next(&packet)) {
|
||||||
LOG(INFO) << packet.Get<string>();
|
ABSL_LOG(INFO) << packet.Get<string>();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ Create a `BUILD` file in the `$APPLICATION_PATH` and add the following build
|
|||||||
rules:
|
rules:
|
||||||
|
|
||||||
```
|
```
|
||||||
MIN_IOS_VERSION = "11.0"
|
MIN_IOS_VERSION = "12.0"
|
||||||
|
|
||||||
load(
|
load(
|
||||||
"@build_bazel_rules_apple//apple:ios.bzl",
|
"@build_bazel_rules_apple//apple:ios.bzl",
|
||||||
|
|||||||
+54
-43
@@ -14,57 +14,54 @@
|
|||||||
|
|
||||||
licenses(["notice"]) # Apache 2.0
|
licenses(["notice"]) # Apache 2.0
|
||||||
|
|
||||||
# Note: yes, these need to use "//external:android/crosstool", not
|
load("@mediapipe//mediapipe:platforms.bzl", "config_setting_and_platform")
|
||||||
# @androidndk//:default_crosstool.
|
|
||||||
|
|
||||||
|
# Generic Android
|
||||||
config_setting(
|
config_setting(
|
||||||
name = "android",
|
name = "android",
|
||||||
values = {"crosstool_top": "//external:android/crosstool"},
|
constraint_values = [
|
||||||
|
"@platforms//os:android",
|
||||||
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
config_setting(
|
# Android x86 32-bit.
|
||||||
|
config_setting_and_platform(
|
||||||
name = "android_x86",
|
name = "android_x86",
|
||||||
values = {
|
constraint_values = [
|
||||||
"crosstool_top": "//external:android/crosstool",
|
"@platforms//os:android",
|
||||||
"cpu": "x86",
|
"@platforms//cpu:x86_32",
|
||||||
},
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
config_setting(
|
# Android x86 64-bit.
|
||||||
|
config_setting_and_platform(
|
||||||
name = "android_x86_64",
|
name = "android_x86_64",
|
||||||
values = {
|
constraint_values = [
|
||||||
"crosstool_top": "//external:android/crosstool",
|
"@platforms//os:android",
|
||||||
"cpu": "x86_64",
|
"@platforms//cpu:x86_64",
|
||||||
},
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
config_setting(
|
# Android ARMv7.
|
||||||
name = "android_armeabi",
|
config_setting_and_platform(
|
||||||
values = {
|
|
||||||
"crosstool_top": "//external:android/crosstool",
|
|
||||||
"cpu": "armeabi",
|
|
||||||
},
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
||||||
|
|
||||||
config_setting(
|
|
||||||
name = "android_arm",
|
name = "android_arm",
|
||||||
values = {
|
constraint_values = [
|
||||||
"crosstool_top": "//external:android/crosstool",
|
"@platforms//os:android",
|
||||||
"cpu": "armeabi-v7a",
|
"@platforms//cpu:armv7",
|
||||||
},
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
config_setting(
|
# Android ARM64.
|
||||||
|
config_setting_and_platform(
|
||||||
name = "android_arm64",
|
name = "android_arm64",
|
||||||
values = {
|
constraint_values = [
|
||||||
"crosstool_top": "//external:android/crosstool",
|
"@platforms//os:android",
|
||||||
"cpu": "arm64-v8a",
|
"@platforms//cpu:arm64",
|
||||||
},
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -78,7 +75,7 @@ config_setting(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# MacOS x86 64-bit.
|
# MacOS x86 64-bit.
|
||||||
config_setting(
|
config_setting_and_platform(
|
||||||
name = "macos_x86_64",
|
name = "macos_x86_64",
|
||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//os:macos",
|
"@platforms//os:macos",
|
||||||
@@ -88,7 +85,7 @@ config_setting(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# MacOS ARM64.
|
# MacOS ARM64.
|
||||||
config_setting(
|
config_setting_and_platform(
|
||||||
name = "macos_arm64",
|
name = "macos_arm64",
|
||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//os:macos",
|
"@platforms//os:macos",
|
||||||
@@ -107,7 +104,7 @@ config_setting(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# iOS device ARM32.
|
# iOS device ARM32.
|
||||||
config_setting(
|
config_setting_and_platform(
|
||||||
name = "ios_armv7",
|
name = "ios_armv7",
|
||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//os:ios",
|
"@platforms//os:ios",
|
||||||
@@ -117,7 +114,7 @@ config_setting(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# iOS device ARM64.
|
# iOS device ARM64.
|
||||||
config_setting(
|
config_setting_and_platform(
|
||||||
name = "ios_arm64",
|
name = "ios_arm64",
|
||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//os:ios",
|
"@platforms//os:ios",
|
||||||
@@ -127,7 +124,7 @@ config_setting(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# iOS device ARM64E.
|
# iOS device ARM64E.
|
||||||
config_setting(
|
config_setting_and_platform(
|
||||||
name = "ios_arm64e",
|
name = "ios_arm64e",
|
||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//os:ios",
|
"@platforms//os:ios",
|
||||||
@@ -137,7 +134,7 @@ config_setting(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# iOS simulator x86 32-bit.
|
# iOS simulator x86 32-bit.
|
||||||
config_setting(
|
config_setting_and_platform(
|
||||||
name = "ios_i386",
|
name = "ios_i386",
|
||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//os:ios",
|
"@platforms//os:ios",
|
||||||
@@ -148,7 +145,7 @@ config_setting(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# iOS simulator x86 64-bit.
|
# iOS simulator x86 64-bit.
|
||||||
config_setting(
|
config_setting_and_platform(
|
||||||
name = "ios_x86_64",
|
name = "ios_x86_64",
|
||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//os:ios",
|
"@platforms//os:ios",
|
||||||
@@ -159,7 +156,7 @@ config_setting(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# iOS simulator ARM64.
|
# iOS simulator ARM64.
|
||||||
config_setting(
|
config_setting_and_platform(
|
||||||
name = "ios_sim_arm64",
|
name = "ios_sim_arm64",
|
||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//os:ios",
|
"@platforms//os:ios",
|
||||||
@@ -169,7 +166,6 @@ config_setting(
|
|||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generic Apple.
|
|
||||||
alias(
|
alias(
|
||||||
name = "apple",
|
name = "apple",
|
||||||
actual = select({
|
actual = select({
|
||||||
@@ -180,9 +176,24 @@ alias(
|
|||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
config_setting(
|
# Windows 64-bit.
|
||||||
|
config_setting_and_platform(
|
||||||
name = "windows",
|
name = "windows",
|
||||||
values = {"cpu": "x64_windows"},
|
constraint_values = [
|
||||||
|
"@platforms//os:windows",
|
||||||
|
"@platforms//cpu:x86_64",
|
||||||
|
],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Linux 64-bit.
|
||||||
|
config_setting_and_platform(
|
||||||
|
name = "linux",
|
||||||
|
constraint_values = [
|
||||||
|
"@platforms//os:linux",
|
||||||
|
"@platforms//cpu:x86_64",
|
||||||
|
],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
exports_files(
|
exports_files(
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Placeholder: load py_proto_library
|
||||||
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library")
|
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library")
|
||||||
|
|
||||||
licenses(["notice"])
|
licenses(["notice"])
|
||||||
@@ -145,6 +146,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:logging",
|
"//mediapipe/framework/port:logging",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/util:time_series_util",
|
"//mediapipe/util:time_series_util",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@com_google_audio_tools//audio/dsp/mfcc",
|
"@com_google_audio_tools//audio/dsp/mfcc",
|
||||||
"@eigen_archive//:eigen3",
|
"@eigen_archive//:eigen3",
|
||||||
@@ -163,8 +165,9 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:matrix",
|
"//mediapipe/framework/formats:matrix",
|
||||||
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
||||||
"//mediapipe/framework/port:integral_types",
|
"//mediapipe/framework/port:integral_types",
|
||||||
"//mediapipe/framework/port:logging",
|
|
||||||
"//mediapipe/util:time_series_util",
|
"//mediapipe/util:time_series_util",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@com_google_audio_tools//audio/dsp:resampler",
|
"@com_google_audio_tools//audio/dsp:resampler",
|
||||||
"@com_google_audio_tools//audio/dsp:resampler_q",
|
"@com_google_audio_tools//audio/dsp:resampler_q",
|
||||||
@@ -185,6 +188,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:core_proto",
|
"//mediapipe/framework/port:core_proto",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/util:time_series_util",
|
"//mediapipe/util:time_series_util",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
@@ -224,6 +228,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/util:time_series_util",
|
"//mediapipe/util:time_series_util",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_audio_tools//audio/dsp:window_functions",
|
"@com_google_audio_tools//audio/dsp:window_functions",
|
||||||
"@eigen_archive//:eigen3",
|
"@eigen_archive//:eigen3",
|
||||||
],
|
],
|
||||||
@@ -294,6 +299,7 @@ cc_test(
|
|||||||
"//mediapipe/framework/port:integral_types",
|
"//mediapipe/framework/port:integral_types",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/util:time_series_test_util",
|
"//mediapipe/util:time_series_test_util",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_audio_tools//audio/dsp:number_util",
|
"@com_google_audio_tools//audio/dsp:number_util",
|
||||||
"@eigen_archive//:eigen3",
|
"@eigen_archive//:eigen3",
|
||||||
],
|
],
|
||||||
@@ -327,6 +333,7 @@ cc_binary(
|
|||||||
"//mediapipe/framework:packet",
|
"//mediapipe/framework:packet",
|
||||||
"//mediapipe/framework/formats:matrix",
|
"//mediapipe/framework/formats:matrix",
|
||||||
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_benchmark//:benchmark",
|
"@com_google_benchmark//:benchmark",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -345,6 +352,7 @@ cc_test(
|
|||||||
"//mediapipe/framework/port:integral_types",
|
"//mediapipe/framework/port:integral_types",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/util:time_series_test_util",
|
"//mediapipe/util:time_series_test_util",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_audio_tools//audio/dsp:window_functions",
|
"@com_google_audio_tools//audio/dsp:window_functions",
|
||||||
"@eigen_archive//:eigen3",
|
"@eigen_archive//:eigen3",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Eigen/Core"
|
#include "Eigen/Core"
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "absl/strings/substitute.h"
|
#include "absl/strings/substitute.h"
|
||||||
@@ -138,7 +139,7 @@ absl::Status FramewiseTransformCalculatorBase::Process(CalculatorContext* cc) {
|
|||||||
TransformFrame(input_frame, &output_frame);
|
TransformFrame(input_frame, &output_frame);
|
||||||
|
|
||||||
// Copy output from vector<float> to Eigen::Vector.
|
// Copy output from vector<float> to Eigen::Vector.
|
||||||
CHECK_EQ(output_frame.size(), num_output_channels_);
|
ABSL_CHECK_EQ(output_frame.size(), num_output_channels_);
|
||||||
Eigen::Map<const Eigen::MatrixXd> output_frame_map(&output_frame[0],
|
Eigen::Map<const Eigen::MatrixXd> output_frame_map(&output_frame[0],
|
||||||
output_frame.size(), 1);
|
output_frame.size(), 1);
|
||||||
output->col(frame) = output_frame_map.cast<float>();
|
output->col(frame) = output_frame_map.cast<float>();
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include "mediapipe/calculators/audio/rational_factor_resample_calculator.h"
|
#include "mediapipe/calculators/audio/rational_factor_resample_calculator.h"
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "audio/dsp/resampler_q.h"
|
#include "audio/dsp/resampler_q.h"
|
||||||
|
|
||||||
using audio_dsp::Resampler;
|
using audio_dsp::Resampler;
|
||||||
@@ -45,9 +47,9 @@ void CopyVectorToChannel(const std::vector<float>& vec, Matrix* matrix,
|
|||||||
if (matrix->cols() == 0) {
|
if (matrix->cols() == 0) {
|
||||||
matrix->resize(matrix->rows(), vec.size());
|
matrix->resize(matrix->rows(), vec.size());
|
||||||
} else {
|
} else {
|
||||||
CHECK_EQ(vec.size(), matrix->cols());
|
ABSL_CHECK_EQ(vec.size(), matrix->cols());
|
||||||
}
|
}
|
||||||
CHECK_LT(channel, matrix->rows());
|
ABSL_CHECK_LT(channel, matrix->rows());
|
||||||
matrix->row(channel) =
|
matrix->row(channel) =
|
||||||
Eigen::Map<const Eigen::ArrayXf>(vec.data(), vec.size());
|
Eigen::Map<const Eigen::ArrayXf>(vec.data(), vec.size());
|
||||||
}
|
}
|
||||||
@@ -77,7 +79,7 @@ absl::Status RationalFactorResampleCalculator::Open(CalculatorContext* cc) {
|
|||||||
r = ResamplerFromOptions(source_sample_rate_, target_sample_rate_,
|
r = ResamplerFromOptions(source_sample_rate_, target_sample_rate_,
|
||||||
resample_options);
|
resample_options);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
LOG(ERROR) << "Failed to initialize resampler.";
|
ABSL_LOG(ERROR) << "Failed to initialize resampler.";
|
||||||
return absl::UnknownError("Failed to initialize resampler.");
|
return absl::UnknownError("Failed to initialize resampler.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
#include "mediapipe/framework/formats/matrix.h"
|
#include "mediapipe/framework/formats/matrix.h"
|
||||||
#include "mediapipe/framework/formats/time_series_header.pb.h"
|
#include "mediapipe/framework/formats/time_series_header.pb.h"
|
||||||
#include "mediapipe/framework/port/integral_types.h"
|
#include "mediapipe/framework/port/integral_types.h"
|
||||||
#include "mediapipe/framework/port/logging.h"
|
|
||||||
#include "mediapipe/util/time_series_util.h"
|
#include "mediapipe/util/time_series_util.h"
|
||||||
|
|
||||||
namespace mediapipe {
|
namespace mediapipe {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Eigen/Core"
|
#include "Eigen/Core"
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "audio/dsp/number_util.h"
|
#include "audio/dsp/number_util.h"
|
||||||
#include "mediapipe/calculators/audio/spectrogram_calculator.pb.h"
|
#include "mediapipe/calculators/audio/spectrogram_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -882,11 +883,11 @@ void BM_ProcessDC(benchmark::State& state) {
|
|||||||
|
|
||||||
const CalculatorRunner::StreamContents& output = runner.Outputs().Index(0);
|
const CalculatorRunner::StreamContents& output = runner.Outputs().Index(0);
|
||||||
const Matrix& output_matrix = output.packets[0].Get<Matrix>();
|
const Matrix& output_matrix = output.packets[0].Get<Matrix>();
|
||||||
LOG(INFO) << "Output matrix=" << output_matrix.rows() << "x"
|
ABSL_LOG(INFO) << "Output matrix=" << output_matrix.rows() << "x"
|
||||||
<< output_matrix.cols();
|
<< output_matrix.cols();
|
||||||
LOG(INFO) << "First values=" << output_matrix(0, 0) << ", "
|
ABSL_LOG(INFO) << "First values=" << output_matrix(0, 0) << ", "
|
||||||
<< output_matrix(1, 0) << ", " << output_matrix(2, 0) << ", "
|
<< output_matrix(1, 0) << ", " << output_matrix(2, 0) << ", "
|
||||||
<< output_matrix(3, 0);
|
<< output_matrix(3, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK(BM_ProcessDC);
|
BENCHMARK(BM_ProcessDC);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "mediapipe/calculators/audio/stabilized_log_calculator.pb.h"
|
#include "mediapipe/calculators/audio/stabilized_log_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/formats/matrix.h"
|
#include "mediapipe/framework/formats/matrix.h"
|
||||||
@@ -59,7 +60,7 @@ class StabilizedLogCalculator : public CalculatorBase {
|
|||||||
output_scale_ = stabilized_log_calculator_options.output_scale();
|
output_scale_ = stabilized_log_calculator_options.output_scale();
|
||||||
check_nonnegativity_ =
|
check_nonnegativity_ =
|
||||||
stabilized_log_calculator_options.check_nonnegativity();
|
stabilized_log_calculator_options.check_nonnegativity();
|
||||||
CHECK_GE(stabilizer_, 0.0)
|
ABSL_CHECK_GE(stabilizer_, 0.0)
|
||||||
<< "stabilizer must be >= 0.0, received a value of " << stabilizer_;
|
<< "stabilizer must be >= 0.0, received a value of " << stabilizer_;
|
||||||
|
|
||||||
// If the input packets have a header, propagate the header to the output.
|
// If the input packets have a header, propagate the header to the output.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Eigen/Core"
|
#include "Eigen/Core"
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "audio/dsp/window_functions.h"
|
#include "audio/dsp/window_functions.h"
|
||||||
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
|
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -104,7 +105,7 @@ class TimeSeriesFramerCalculator : public CalculatorBase {
|
|||||||
// All numbers are in input samples.
|
// All numbers are in input samples.
|
||||||
const int64_t current_output_frame_start = static_cast<int64_t>(
|
const int64_t current_output_frame_start = static_cast<int64_t>(
|
||||||
round(cumulative_output_frames_ * average_frame_step_samples_));
|
round(cumulative_output_frames_ * average_frame_step_samples_));
|
||||||
CHECK_EQ(current_output_frame_start, cumulative_completed_samples_);
|
ABSL_CHECK_EQ(current_output_frame_start, cumulative_completed_samples_);
|
||||||
const int64_t next_output_frame_start = static_cast<int64_t>(
|
const int64_t next_output_frame_start = static_cast<int64_t>(
|
||||||
round((cumulative_output_frames_ + 1) * average_frame_step_samples_));
|
round((cumulative_output_frames_ + 1) * average_frame_step_samples_));
|
||||||
return next_output_frame_start - current_output_frame_start;
|
return next_output_frame_start - current_output_frame_start;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "benchmark/benchmark.h"
|
#include "benchmark/benchmark.h"
|
||||||
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
|
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -70,7 +71,7 @@ void BM_TimeSeriesFramerCalculator(benchmark::State& state) {
|
|||||||
}
|
}
|
||||||
// Initialize graph.
|
// Initialize graph.
|
||||||
mediapipe::CalculatorGraph graph;
|
mediapipe::CalculatorGraph graph;
|
||||||
CHECK_OK(graph.Initialize(config));
|
ABSL_CHECK_OK(graph.Initialize(config));
|
||||||
// Prepare input header.
|
// Prepare input header.
|
||||||
auto header = std::make_unique<mediapipe::TimeSeriesHeader>();
|
auto header = std::make_unique<mediapipe::TimeSeriesHeader>();
|
||||||
header->set_sample_rate(kSampleRate);
|
header->set_sample_rate(kSampleRate);
|
||||||
@@ -78,13 +79,13 @@ void BM_TimeSeriesFramerCalculator(benchmark::State& state) {
|
|||||||
|
|
||||||
state.ResumeTiming(); // Resume benchmark timing.
|
state.ResumeTiming(); // Resume benchmark timing.
|
||||||
|
|
||||||
CHECK_OK(graph.StartRun({}, {{"input", Adopt(header.release())}}));
|
ABSL_CHECK_OK(graph.StartRun({}, {{"input", Adopt(header.release())}}));
|
||||||
for (auto& packet : input_packets) {
|
for (auto& packet : input_packets) {
|
||||||
CHECK_OK(graph.AddPacketToInputStream("input", packet));
|
ABSL_CHECK_OK(graph.AddPacketToInputStream("input", packet));
|
||||||
}
|
}
|
||||||
CHECK(!graph.HasError());
|
ABSL_CHECK(!graph.HasError());
|
||||||
CHECK_OK(graph.CloseAllInputStreams());
|
ABSL_CHECK_OK(graph.CloseAllInputStreams());
|
||||||
CHECK_OK(graph.WaitUntilIdle());
|
ABSL_CHECK_OK(graph.WaitUntilIdle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BENCHMARK(BM_TimeSeriesFramerCalculator);
|
BENCHMARK(BM_TimeSeriesFramerCalculator);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Eigen/Core"
|
#include "Eigen/Core"
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "audio/dsp/window_functions.h"
|
#include "audio/dsp/window_functions.h"
|
||||||
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
|
#include "mediapipe/calculators/audio/time_series_framer_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -186,11 +187,12 @@ class TimeSeriesFramerCalculatorTest
|
|||||||
const int num_unique_output_samples =
|
const int num_unique_output_samples =
|
||||||
round((output().packets.size() - 1) * frame_step_samples) +
|
round((output().packets.size() - 1) * frame_step_samples) +
|
||||||
frame_duration_samples;
|
frame_duration_samples;
|
||||||
LOG(INFO) << "packets.size()=" << output().packets.size()
|
ABSL_LOG(INFO) << "packets.size()=" << output().packets.size()
|
||||||
<< " frame_duration_samples=" << frame_duration_samples
|
<< " frame_duration_samples=" << frame_duration_samples
|
||||||
<< " frame_step_samples=" << frame_step_samples
|
<< " frame_step_samples=" << frame_step_samples
|
||||||
<< " num_input_samples_=" << num_input_samples_
|
<< " num_input_samples_=" << num_input_samples_
|
||||||
<< " num_unique_output_samples=" << num_unique_output_samples;
|
<< " num_unique_output_samples="
|
||||||
|
<< num_unique_output_samples;
|
||||||
const int num_padding_samples =
|
const int num_padding_samples =
|
||||||
num_unique_output_samples - num_input_samples_;
|
num_unique_output_samples - num_input_samples_;
|
||||||
if (options_.pad_final_packet()) {
|
if (options_.pad_final_packet()) {
|
||||||
|
|||||||
@@ -325,6 +325,7 @@ cc_library(
|
|||||||
":concatenate_vector_calculator_cc_proto",
|
":concatenate_vector_calculator_cc_proto",
|
||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/api2:node",
|
"//mediapipe/framework/api2:node",
|
||||||
|
"//mediapipe/framework/formats:body_rig_cc_proto",
|
||||||
"//mediapipe/framework/formats:classification_cc_proto",
|
"//mediapipe/framework/formats:classification_cc_proto",
|
||||||
"//mediapipe/framework/formats:landmark_cc_proto",
|
"//mediapipe/framework/formats:landmark_cc_proto",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
@@ -582,6 +583,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:logging",
|
"//mediapipe/framework/port:logging",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/tool:options_util",
|
"//mediapipe/framework/tool:options_util",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
@@ -597,6 +599,7 @@ cc_test(
|
|||||||
"//mediapipe/framework/formats:video_stream_header",
|
"//mediapipe/framework/formats:video_stream_header",
|
||||||
"//mediapipe/framework/port:gtest_main",
|
"//mediapipe/framework/port:gtest_main",
|
||||||
"//mediapipe/framework/port:integral_types",
|
"//mediapipe/framework/port:integral_types",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -629,6 +632,7 @@ cc_library(
|
|||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
@@ -776,10 +780,11 @@ cc_library(
|
|||||||
"//mediapipe/framework/deps:random",
|
"//mediapipe/framework/deps:random",
|
||||||
"//mediapipe/framework/formats:video_stream_header",
|
"//mediapipe/framework/formats:video_stream_header",
|
||||||
"//mediapipe/framework/port:integral_types",
|
"//mediapipe/framework/port:integral_types",
|
||||||
"//mediapipe/framework/port:logging",
|
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/tool:options_util",
|
"//mediapipe/framework/tool:options_util",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
@@ -835,6 +840,7 @@ cc_test(
|
|||||||
"//mediapipe/framework/port:gtest_main",
|
"//mediapipe/framework/port:gtest_main",
|
||||||
"//mediapipe/framework/port:logging",
|
"//mediapipe/framework/port:logging",
|
||||||
"//mediapipe/framework/tool:validate_type",
|
"//mediapipe/framework/tool:validate_type",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@eigen_archive//:eigen3",
|
"@eigen_archive//:eigen3",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -939,6 +945,7 @@ cc_library(
|
|||||||
deps = [
|
deps = [
|
||||||
":split_vector_calculator_cc_proto",
|
":split_vector_calculator_cc_proto",
|
||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
|
"//mediapipe/framework/formats:body_rig_cc_proto",
|
||||||
"//mediapipe/framework/formats:landmark_cc_proto",
|
"//mediapipe/framework/formats:landmark_cc_proto",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
@@ -1022,6 +1029,7 @@ cc_library(
|
|||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/api2:node",
|
"//mediapipe/framework/api2:node",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
@@ -1060,6 +1068,7 @@ cc_test(
|
|||||||
"//mediapipe/framework:calculator_runner",
|
"//mediapipe/framework:calculator_runner",
|
||||||
"//mediapipe/framework/port:gtest_main",
|
"//mediapipe/framework/port:gtest_main",
|
||||||
"//mediapipe/framework/port:parse_text_proto",
|
"//mediapipe/framework/port:parse_text_proto",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1106,6 +1115,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/api2:node",
|
"//mediapipe/framework/api2:node",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
@@ -1381,3 +1391,26 @@ cc_test(
|
|||||||
"@com_google_absl//absl/types:optional",
|
"@com_google_absl//absl/types:optional",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "value_or_default_calculator",
|
||||||
|
srcs = ["value_or_default_calculator.cc"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//mediapipe/framework:calculator_framework",
|
||||||
|
"//mediapipe/framework/port:status",
|
||||||
|
],
|
||||||
|
alwayslink = True,
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "value_or_default_calculator_test",
|
||||||
|
srcs = ["value_or_default_calculator_test.cc"],
|
||||||
|
deps = [
|
||||||
|
":value_or_default_calculator",
|
||||||
|
"//mediapipe/framework:calculator_framework",
|
||||||
|
"//mediapipe/framework:calculator_runner",
|
||||||
|
"//mediapipe/framework:packet",
|
||||||
|
"//mediapipe/framework/port:gtest_main",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
@@ -163,6 +164,75 @@ TEST_F(BeginEndLoopCalculatorGraphTest, MultipleVectors) {
|
|||||||
PacketOfIntsEq(input_timestamp2, std::vector<int>{3, 4})));
|
PacketOfIntsEq(input_timestamp2, std::vector<int>{3, 4})));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(BeginEndLoopCalculatorPossibleDataRaceTest,
|
||||||
|
EndLoopForIntegersDoesNotRace) {
|
||||||
|
auto graph_config = ParseTextProtoOrDie<CalculatorGraphConfig>(
|
||||||
|
R"pb(
|
||||||
|
num_threads: 4
|
||||||
|
input_stream: "ints"
|
||||||
|
node {
|
||||||
|
calculator: "BeginLoopIntegerCalculator"
|
||||||
|
input_stream: "ITERABLE:ints"
|
||||||
|
output_stream: "ITEM:int"
|
||||||
|
output_stream: "BATCH_END:timestamp"
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
calculator: "IncrementCalculator"
|
||||||
|
input_stream: "int"
|
||||||
|
output_stream: "int_plus_one"
|
||||||
|
}
|
||||||
|
# BEGIN: Data race possibility
|
||||||
|
# EndLoop###Calculator and another calculator using the same input
|
||||||
|
# may introduce race due to EndLoop###Calculator possibly consuming
|
||||||
|
# packet.
|
||||||
|
node {
|
||||||
|
calculator: "EndLoopIntegersCalculator"
|
||||||
|
input_stream: "ITEM:int_plus_one"
|
||||||
|
input_stream: "BATCH_END:timestamp"
|
||||||
|
output_stream: "ITERABLE:ints_plus_one"
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
calculator: "IncrementCalculator"
|
||||||
|
input_stream: "int_plus_one"
|
||||||
|
output_stream: "int_plus_two"
|
||||||
|
}
|
||||||
|
# END: Data race possibility
|
||||||
|
node {
|
||||||
|
calculator: "EndLoopIntegersCalculator"
|
||||||
|
input_stream: "ITEM:int_plus_two"
|
||||||
|
input_stream: "BATCH_END:timestamp"
|
||||||
|
output_stream: "ITERABLE:ints_plus_two"
|
||||||
|
}
|
||||||
|
)pb");
|
||||||
|
std::vector<Packet> int_plus_one_packets;
|
||||||
|
tool::AddVectorSink("ints_plus_one", &graph_config, &int_plus_one_packets);
|
||||||
|
std::vector<Packet> int_original_packets;
|
||||||
|
tool::AddVectorSink("ints_plus_two", &graph_config, &int_original_packets);
|
||||||
|
|
||||||
|
CalculatorGraph graph;
|
||||||
|
MP_ASSERT_OK(graph.Initialize(graph_config));
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
std::vector<int> ints = {i, i + 1, i + 2};
|
||||||
|
Timestamp ts = Timestamp(i);
|
||||||
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
|
"ints", MakePacket<std::vector<int>>(std::move(ints)).At(ts)));
|
||||||
|
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||||
|
EXPECT_THAT(int_plus_one_packets,
|
||||||
|
testing::ElementsAre(
|
||||||
|
PacketOfIntsEq(ts, std::vector<int>{i + 1, i + 2, i + 3})));
|
||||||
|
EXPECT_THAT(int_original_packets,
|
||||||
|
testing::ElementsAre(
|
||||||
|
PacketOfIntsEq(ts, std::vector<int>{i + 2, i + 3, i + 4})));
|
||||||
|
|
||||||
|
int_plus_one_packets.clear();
|
||||||
|
int_original_packets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_ASSERT_OK(graph.CloseAllPacketSources());
|
||||||
|
MP_ASSERT_OK(graph.WaitUntilDone());
|
||||||
|
}
|
||||||
|
|
||||||
// Passes non empty vector through or outputs empty vector in case of timestamp
|
// Passes non empty vector through or outputs empty vector in case of timestamp
|
||||||
// bound update.
|
// bound update.
|
||||||
class PassThroughOrEmptyVectorCalculator : public CalculatorBase {
|
class PassThroughOrEmptyVectorCalculator : public CalculatorBase {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class BypassCalculator : public Node {
|
|||||||
auto options = cc->Options<BypassCalculatorOptions>();
|
auto options = cc->Options<BypassCalculatorOptions>();
|
||||||
RET_CHECK_EQ(options.pass_input_stream().size(),
|
RET_CHECK_EQ(options.pass_input_stream().size(),
|
||||||
options.pass_output_stream().size());
|
options.pass_output_stream().size());
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
auto pass_streams,
|
auto pass_streams,
|
||||||
GetPassMap(options, *cc->Inputs().TagMap(), *cc->Outputs().TagMap()));
|
GetPassMap(options, *cc->Inputs().TagMap(), *cc->Outputs().TagMap()));
|
||||||
std::set<CollectionItemId> pass_out;
|
std::set<CollectionItemId> pass_out;
|
||||||
@@ -121,8 +121,9 @@ class BypassCalculator : public Node {
|
|||||||
// Saves the map of passthrough input and output stream ids.
|
// Saves the map of passthrough input and output stream ids.
|
||||||
absl::Status Open(CalculatorContext* cc) override {
|
absl::Status Open(CalculatorContext* cc) override {
|
||||||
auto options = cc->Options<BypassCalculatorOptions>();
|
auto options = cc->Options<BypassCalculatorOptions>();
|
||||||
ASSIGN_OR_RETURN(pass_streams_, GetPassMap(options, *cc->Inputs().TagMap(),
|
MP_ASSIGN_OR_RETURN(
|
||||||
*cc->Outputs().TagMap()));
|
pass_streams_,
|
||||||
|
GetPassMap(options, *cc->Inputs().TagMap(), *cc->Outputs().TagMap()));
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "mediapipe/calculators/core/concatenate_vector_calculator.pb.h"
|
#include "mediapipe/calculators/core/concatenate_vector_calculator.pb.h"
|
||||||
#include "mediapipe/framework/api2/node.h"
|
#include "mediapipe/framework/api2/node.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/formats/body_rig.pb.h"
|
||||||
#include "mediapipe/framework/formats/classification.pb.h"
|
#include "mediapipe/framework/formats/classification.pb.h"
|
||||||
#include "mediapipe/framework/formats/landmark.pb.h"
|
#include "mediapipe/framework/formats/landmark.pb.h"
|
||||||
#include "mediapipe/framework/port/canonical_errors.h"
|
#include "mediapipe/framework/port/canonical_errors.h"
|
||||||
@@ -128,6 +129,19 @@ class ConcatenateClassificationListCalculator
|
|||||||
};
|
};
|
||||||
MEDIAPIPE_REGISTER_NODE(ConcatenateClassificationListCalculator);
|
MEDIAPIPE_REGISTER_NODE(ConcatenateClassificationListCalculator);
|
||||||
|
|
||||||
|
class ConcatenateJointListCalculator
|
||||||
|
: public ConcatenateListsCalculator<Joint, JointList> {
|
||||||
|
protected:
|
||||||
|
int ListSize(const JointList& list) const override {
|
||||||
|
return list.joint_size();
|
||||||
|
}
|
||||||
|
const Joint GetItem(const JointList& list, int idx) const override {
|
||||||
|
return list.joint(idx);
|
||||||
|
}
|
||||||
|
Joint* AddItem(JointList& list) const override { return list.add_joint(); }
|
||||||
|
};
|
||||||
|
MEDIAPIPE_REGISTER_NODE(ConcatenateJointListCalculator);
|
||||||
|
|
||||||
} // namespace api2
|
} // namespace api2
|
||||||
} // namespace mediapipe
|
} // namespace mediapipe
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "mediapipe/calculators/core/end_loop_calculator.h"
|
#include "mediapipe/calculators/core/end_loop_calculator.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "mediapipe/framework/formats/classification.pb.h"
|
#include "mediapipe/framework/formats/classification.pb.h"
|
||||||
@@ -84,4 +86,8 @@ typedef EndLoopCalculator<std::vector<std::array<float, 16>>>
|
|||||||
EndLoopAffineMatrixCalculator;
|
EndLoopAffineMatrixCalculator;
|
||||||
REGISTER_CALCULATOR(EndLoopAffineMatrixCalculator);
|
REGISTER_CALCULATOR(EndLoopAffineMatrixCalculator);
|
||||||
|
|
||||||
|
typedef EndLoopCalculator<std::vector<std::pair<int, int>>>
|
||||||
|
EndLoopImageSizeCalculator;
|
||||||
|
REGISTER_CALCULATOR(EndLoopImageSizeCalculator);
|
||||||
|
|
||||||
} // namespace mediapipe
|
} // namespace mediapipe
|
||||||
|
|||||||
@@ -55,16 +55,16 @@ class EndLoopCalculator : public CalculatorBase {
|
|||||||
if (!input_stream_collection_) {
|
if (!input_stream_collection_) {
|
||||||
input_stream_collection_.reset(new IterableT);
|
input_stream_collection_.reset(new IterableT);
|
||||||
}
|
}
|
||||||
// Try to consume the item and move it into the collection. If the items
|
|
||||||
// are not consumable, then try to copy them instead. If the items are
|
if constexpr (std::is_copy_constructible_v<ItemT>) {
|
||||||
// not copyable, then an error will be returned.
|
input_stream_collection_->push_back(
|
||||||
auto item_ptr_or = cc->Inputs().Tag("ITEM").Value().Consume<ItemT>();
|
cc->Inputs().Tag("ITEM").Get<ItemT>());
|
||||||
if (item_ptr_or.ok()) {
|
|
||||||
input_stream_collection_->push_back(std::move(*item_ptr_or.value()));
|
|
||||||
} else {
|
} else {
|
||||||
if constexpr (std::is_copy_constructible_v<ItemT>) {
|
// Try to consume the item and move it into the collection. Return an
|
||||||
input_stream_collection_->push_back(
|
// error if the items are not consumable.
|
||||||
cc->Inputs().Tag("ITEM").template Get<ItemT>());
|
auto item_ptr_or = cc->Inputs().Tag("ITEM").Value().Consume<ItemT>();
|
||||||
|
if (item_ptr_or.ok()) {
|
||||||
|
input_stream_collection_->push_back(std::move(*item_ptr_or.value()));
|
||||||
} else {
|
} else {
|
||||||
return absl::InternalError(
|
return absl::InternalError(
|
||||||
"The item type is not copiable. Consider making the "
|
"The item type is not copiable. Consider making the "
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/calculator_runner.h"
|
#include "mediapipe/framework/calculator_runner.h"
|
||||||
#include "mediapipe/framework/port/gtest.h"
|
#include "mediapipe/framework/port/gtest.h"
|
||||||
@@ -356,18 +357,18 @@ TEST_F(GateCalculatorTest, AllowWithStateChangeNoDataStreams) {
|
|||||||
RunTimeStepWithoutDataStream(kTimestampValue2, "ALLOW", true);
|
RunTimeStepWithoutDataStream(kTimestampValue2, "ALLOW", true);
|
||||||
constexpr int64_t kTimestampValue3 = 45;
|
constexpr int64_t kTimestampValue3 = 45;
|
||||||
RunTimeStepWithoutDataStream(kTimestampValue3, "ALLOW", false);
|
RunTimeStepWithoutDataStream(kTimestampValue3, "ALLOW", false);
|
||||||
LOG(INFO) << "a";
|
ABSL_LOG(INFO) << "a";
|
||||||
const std::vector<Packet>& output =
|
const std::vector<Packet>& output =
|
||||||
runner()->Outputs().Get("STATE_CHANGE", 0).packets;
|
runner()->Outputs().Get("STATE_CHANGE", 0).packets;
|
||||||
LOG(INFO) << "s";
|
ABSL_LOG(INFO) << "s";
|
||||||
ASSERT_EQ(2, output.size());
|
ASSERT_EQ(2, output.size());
|
||||||
LOG(INFO) << "d";
|
ABSL_LOG(INFO) << "d";
|
||||||
EXPECT_EQ(kTimestampValue1, output[0].Timestamp().Value());
|
EXPECT_EQ(kTimestampValue1, output[0].Timestamp().Value());
|
||||||
EXPECT_EQ(kTimestampValue3, output[1].Timestamp().Value());
|
EXPECT_EQ(kTimestampValue3, output[1].Timestamp().Value());
|
||||||
LOG(INFO) << "f";
|
ABSL_LOG(INFO) << "f";
|
||||||
EXPECT_EQ(true, output[0].Get<bool>()); // Allow.
|
EXPECT_EQ(true, output[0].Get<bool>()); // Allow.
|
||||||
EXPECT_EQ(false, output[1].Get<bool>()); // Disallow.
|
EXPECT_EQ(false, output[1].Get<bool>()); // Disallow.
|
||||||
LOG(INFO) << "g";
|
ABSL_LOG(INFO) << "g";
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(GateCalculatorTest, DisallowWithStateChange) {
|
TEST_F(GateCalculatorTest, DisallowWithStateChange) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/port/ret_check.h"
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
#include "mediapipe/framework/port/status.h"
|
#include "mediapipe/framework/port/status.h"
|
||||||
@@ -78,7 +79,7 @@ absl::Status ImmediateMuxCalculator::Process(CalculatorContext* cc) {
|
|||||||
if (packet.Timestamp() >= cc->Outputs().Index(0).NextTimestampBound()) {
|
if (packet.Timestamp() >= cc->Outputs().Index(0).NextTimestampBound()) {
|
||||||
cc->Outputs().Index(0).AddPacket(packet);
|
cc->Outputs().Index(0).AddPacket(packet);
|
||||||
} else {
|
} else {
|
||||||
LOG_FIRST_N(WARNING, 5)
|
ABSL_LOG_FIRST_N(WARNING, 5)
|
||||||
<< "Dropping a packet with timestamp " << packet.Timestamp();
|
<< "Dropping a packet with timestamp " << packet.Timestamp();
|
||||||
}
|
}
|
||||||
if (cc->Outputs().NumEntries() >= 2) {
|
if (cc->Outputs().NumEntries() >= 2) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Eigen/Core"
|
#include "Eigen/Core"
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/calculator_runner.h"
|
#include "mediapipe/framework/calculator_runner.h"
|
||||||
#include "mediapipe/framework/formats/matrix.h"
|
#include "mediapipe/framework/formats/matrix.h"
|
||||||
@@ -209,7 +210,7 @@ TEST(MatrixMultiplyCalculatorTest, Multiply) {
|
|||||||
MatrixFromTextProto(kSamplesText, &samples);
|
MatrixFromTextProto(kSamplesText, &samples);
|
||||||
Matrix expected;
|
Matrix expected;
|
||||||
MatrixFromTextProto(kExpectedText, &expected);
|
MatrixFromTextProto(kExpectedText, &expected);
|
||||||
CHECK_EQ(samples.cols(), expected.cols());
|
ABSL_CHECK_EQ(samples.cols(), expected.cols());
|
||||||
|
|
||||||
for (int i = 0; i < samples.cols(); ++i) {
|
for (int i = 0; i < samples.cols(); ++i) {
|
||||||
// Take a column from samples and produce a packet with just that
|
// Take a column from samples and produce a packet with just that
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/framework/api2/node.h"
|
#include "mediapipe/framework/api2/node.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/port/ret_check.h"
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
@@ -53,7 +54,7 @@ class MergeCalculator : public Node {
|
|||||||
static absl::Status UpdateContract(CalculatorContract* cc) {
|
static absl::Status UpdateContract(CalculatorContract* cc) {
|
||||||
RET_CHECK_GT(kIn(cc).Count(), 0) << "Needs at least one input stream";
|
RET_CHECK_GT(kIn(cc).Count(), 0) << "Needs at least one input stream";
|
||||||
if (kIn(cc).Count() == 1) {
|
if (kIn(cc).Count() == 1) {
|
||||||
LOG(WARNING)
|
ABSL_LOG(WARNING)
|
||||||
<< "MergeCalculator expects multiple input streams to merge but is "
|
<< "MergeCalculator expects multiple input streams to merge but is "
|
||||||
"receiving only one. Make sure the calculator is configured "
|
"receiving only one. Make sure the calculator is configured "
|
||||||
"correctly or consider removing this calculator to reduce "
|
"correctly or consider removing this calculator to reduce "
|
||||||
@@ -72,8 +73,8 @@ class MergeCalculator : public Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(WARNING) << "Empty input packets at timestamp "
|
ABSL_LOG(WARNING) << "Empty input packets at timestamp "
|
||||||
<< cc->InputTimestamp().Value();
|
<< cc->InputTimestamp().Value();
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Reflect an integer against the lower and upper bound of an interval.
|
// Reflect an integer against the lower and upper bound of an interval.
|
||||||
int64_t ReflectBetween(int64_t ts, int64_t ts_min, int64_t ts_max) {
|
int64_t ReflectBetween(int64_t ts, int64_t ts_min, int64_t ts_max) {
|
||||||
@@ -177,7 +180,7 @@ PacketResamplerCalculator::GetSamplingStrategy(
|
|||||||
const PacketResamplerCalculatorOptions& options) {
|
const PacketResamplerCalculatorOptions& options) {
|
||||||
if (options.reproducible_sampling()) {
|
if (options.reproducible_sampling()) {
|
||||||
if (!options.jitter_with_reflection()) {
|
if (!options.jitter_with_reflection()) {
|
||||||
LOG(WARNING)
|
ABSL_LOG(WARNING)
|
||||||
<< "reproducible_sampling enabled w/ jitter_with_reflection "
|
<< "reproducible_sampling enabled w/ jitter_with_reflection "
|
||||||
"disabled. "
|
"disabled. "
|
||||||
<< "reproducible_sampling always uses jitter with reflection, "
|
<< "reproducible_sampling always uses jitter with reflection, "
|
||||||
@@ -200,15 +203,15 @@ PacketResamplerCalculator::GetSamplingStrategy(
|
|||||||
|
|
||||||
Timestamp PacketResamplerCalculator::PeriodIndexToTimestamp(
|
Timestamp PacketResamplerCalculator::PeriodIndexToTimestamp(
|
||||||
int64_t index) const {
|
int64_t index) const {
|
||||||
CHECK_EQ(jitter_, 0.0);
|
ABSL_CHECK_EQ(jitter_, 0.0);
|
||||||
CHECK_NE(first_timestamp_, Timestamp::Unset());
|
ABSL_CHECK_NE(first_timestamp_, Timestamp::Unset());
|
||||||
return first_timestamp_ + TimestampDiffFromSeconds(index / frame_rate_);
|
return first_timestamp_ + TimestampDiffFromSeconds(index / frame_rate_);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t PacketResamplerCalculator::TimestampToPeriodIndex(
|
int64_t PacketResamplerCalculator::TimestampToPeriodIndex(
|
||||||
Timestamp timestamp) const {
|
Timestamp timestamp) const {
|
||||||
CHECK_EQ(jitter_, 0.0);
|
ABSL_CHECK_EQ(jitter_, 0.0);
|
||||||
CHECK_NE(first_timestamp_, Timestamp::Unset());
|
ABSL_CHECK_NE(first_timestamp_, Timestamp::Unset());
|
||||||
return MathUtil::SafeRound<int64_t, double>(
|
return MathUtil::SafeRound<int64_t, double>(
|
||||||
(timestamp - first_timestamp_).Seconds() * frame_rate_);
|
(timestamp - first_timestamp_).Seconds() * frame_rate_);
|
||||||
}
|
}
|
||||||
@@ -229,13 +232,15 @@ absl::Status LegacyJitterWithReflectionStrategy::Open(CalculatorContext* cc) {
|
|||||||
|
|
||||||
if (resampler_options.output_header() !=
|
if (resampler_options.output_header() !=
|
||||||
PacketResamplerCalculatorOptions::NONE) {
|
PacketResamplerCalculatorOptions::NONE) {
|
||||||
LOG(WARNING) << "VideoHeader::frame_rate holds the target value and not "
|
ABSL_LOG(WARNING)
|
||||||
"the actual value.";
|
<< "VideoHeader::frame_rate holds the target value and not "
|
||||||
|
"the actual value.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calculator_->flush_last_packet_) {
|
if (calculator_->flush_last_packet_) {
|
||||||
LOG(WARNING) << "PacketResamplerCalculatorOptions.flush_last_packet is "
|
ABSL_LOG(WARNING)
|
||||||
"ignored, because we are adding jitter.";
|
<< "PacketResamplerCalculatorOptions.flush_last_packet is "
|
||||||
|
"ignored, because we are adding jitter.";
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>();
|
const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>();
|
||||||
@@ -254,7 +259,7 @@ absl::Status LegacyJitterWithReflectionStrategy::Open(CalculatorContext* cc) {
|
|||||||
}
|
}
|
||||||
absl::Status LegacyJitterWithReflectionStrategy::Close(CalculatorContext* cc) {
|
absl::Status LegacyJitterWithReflectionStrategy::Close(CalculatorContext* cc) {
|
||||||
if (!packet_reservoir_->IsEmpty()) {
|
if (!packet_reservoir_->IsEmpty()) {
|
||||||
LOG(INFO) << "Emitting pack from reservoir.";
|
ABSL_LOG(INFO) << "Emitting pack from reservoir.";
|
||||||
calculator_->OutputWithinLimits(cc, packet_reservoir_->GetSample());
|
calculator_->OutputWithinLimits(cc, packet_reservoir_->GetSample());
|
||||||
}
|
}
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
@@ -285,7 +290,7 @@ absl::Status LegacyJitterWithReflectionStrategy::Process(
|
|||||||
|
|
||||||
if (calculator_->frame_time_usec_ <
|
if (calculator_->frame_time_usec_ <
|
||||||
(cc->InputTimestamp() - calculator_->last_packet_.Timestamp()).Value()) {
|
(cc->InputTimestamp() - calculator_->last_packet_.Timestamp()).Value()) {
|
||||||
LOG_FIRST_N(WARNING, 2)
|
ABSL_LOG_FIRST_N(WARNING, 2)
|
||||||
<< "Adding jitter is not very useful when upsampling.";
|
<< "Adding jitter is not very useful when upsampling.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,8 +345,8 @@ void LegacyJitterWithReflectionStrategy::UpdateNextOutputTimestampWithJitter() {
|
|||||||
next_output_timestamp_ = Timestamp(ReflectBetween(
|
next_output_timestamp_ = Timestamp(ReflectBetween(
|
||||||
next_output_timestamp_.Value(), next_output_timestamp_min_.Value(),
|
next_output_timestamp_.Value(), next_output_timestamp_min_.Value(),
|
||||||
next_output_timestamp_max_.Value()));
|
next_output_timestamp_max_.Value()));
|
||||||
CHECK_GE(next_output_timestamp_, next_output_timestamp_min_);
|
ABSL_CHECK_GE(next_output_timestamp_, next_output_timestamp_min_);
|
||||||
CHECK_LT(next_output_timestamp_, next_output_timestamp_max_);
|
ABSL_CHECK_LT(next_output_timestamp_, next_output_timestamp_max_);
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Status ReproducibleJitterWithReflectionStrategy::Open(
|
absl::Status ReproducibleJitterWithReflectionStrategy::Open(
|
||||||
@@ -352,13 +357,15 @@ absl::Status ReproducibleJitterWithReflectionStrategy::Open(
|
|||||||
|
|
||||||
if (resampler_options.output_header() !=
|
if (resampler_options.output_header() !=
|
||||||
PacketResamplerCalculatorOptions::NONE) {
|
PacketResamplerCalculatorOptions::NONE) {
|
||||||
LOG(WARNING) << "VideoHeader::frame_rate holds the target value and not "
|
ABSL_LOG(WARNING)
|
||||||
"the actual value.";
|
<< "VideoHeader::frame_rate holds the target value and not "
|
||||||
|
"the actual value.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calculator_->flush_last_packet_) {
|
if (calculator_->flush_last_packet_) {
|
||||||
LOG(WARNING) << "PacketResamplerCalculatorOptions.flush_last_packet is "
|
ABSL_LOG(WARNING)
|
||||||
"ignored, because we are adding jitter.";
|
<< "PacketResamplerCalculatorOptions.flush_last_packet is "
|
||||||
|
"ignored, because we are adding jitter.";
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>();
|
const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>();
|
||||||
@@ -411,7 +418,7 @@ absl::Status ReproducibleJitterWithReflectionStrategy::Process(
|
|||||||
// Note, if the stream is upsampling, this could lead to the same packet
|
// Note, if the stream is upsampling, this could lead to the same packet
|
||||||
// being emitted twice. Upsampling and jitter doesn't make much sense
|
// being emitted twice. Upsampling and jitter doesn't make much sense
|
||||||
// but does technically work.
|
// but does technically work.
|
||||||
LOG_FIRST_N(WARNING, 2)
|
ABSL_LOG_FIRST_N(WARNING, 2)
|
||||||
<< "Adding jitter is not very useful when upsampling.";
|
<< "Adding jitter is not very useful when upsampling.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,13 +506,15 @@ absl::Status JitterWithoutReflectionStrategy::Open(CalculatorContext* cc) {
|
|||||||
|
|
||||||
if (resampler_options.output_header() !=
|
if (resampler_options.output_header() !=
|
||||||
PacketResamplerCalculatorOptions::NONE) {
|
PacketResamplerCalculatorOptions::NONE) {
|
||||||
LOG(WARNING) << "VideoHeader::frame_rate holds the target value and not "
|
ABSL_LOG(WARNING)
|
||||||
"the actual value.";
|
<< "VideoHeader::frame_rate holds the target value and not "
|
||||||
|
"the actual value.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calculator_->flush_last_packet_) {
|
if (calculator_->flush_last_packet_) {
|
||||||
LOG(WARNING) << "PacketResamplerCalculatorOptions.flush_last_packet is "
|
ABSL_LOG(WARNING)
|
||||||
"ignored, because we are adding jitter.";
|
<< "PacketResamplerCalculatorOptions.flush_last_packet is "
|
||||||
|
"ignored, because we are adding jitter.";
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>();
|
const auto& seed = cc->InputSidePackets().Tag(kSeedTag).Get<std::string>();
|
||||||
@@ -555,7 +564,7 @@ absl::Status JitterWithoutReflectionStrategy::Process(CalculatorContext* cc) {
|
|||||||
|
|
||||||
if (calculator_->frame_time_usec_ <
|
if (calculator_->frame_time_usec_ <
|
||||||
(cc->InputTimestamp() - calculator_->last_packet_.Timestamp()).Value()) {
|
(cc->InputTimestamp() - calculator_->last_packet_.Timestamp()).Value()) {
|
||||||
LOG_FIRST_N(WARNING, 2)
|
ABSL_LOG_FIRST_N(WARNING, 2)
|
||||||
<< "Adding jitter is not very useful when upsampling.";
|
<< "Adding jitter is not very useful when upsampling.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#include "mediapipe/framework/deps/random_base.h"
|
#include "mediapipe/framework/deps/random_base.h"
|
||||||
#include "mediapipe/framework/formats/video_stream_header.h"
|
#include "mediapipe/framework/formats/video_stream_header.h"
|
||||||
#include "mediapipe/framework/port/integral_types.h"
|
#include "mediapipe/framework/port/integral_types.h"
|
||||||
#include "mediapipe/framework/port/logging.h"
|
|
||||||
#include "mediapipe/framework/port/ret_check.h"
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
#include "mediapipe/framework/port/status.h"
|
#include "mediapipe/framework/port/status.h"
|
||||||
#include "mediapipe/framework/port/status_macros.h"
|
#include "mediapipe/framework/port/status_macros.h"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <cmath> // for ceil
|
#include <cmath> // for ceil
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "mediapipe/calculators/core/packet_thinner_calculator.pb.h"
|
#include "mediapipe/calculators/core/packet_thinner_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_context.h"
|
#include "mediapipe/framework/calculator_context.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -160,8 +161,8 @@ absl::Status PacketThinnerCalculator::Open(CalculatorContext* cc) {
|
|||||||
|
|
||||||
thinner_type_ = options.thinner_type();
|
thinner_type_ = options.thinner_type();
|
||||||
// This check enables us to assume only two thinner types exist in Process()
|
// This check enables us to assume only two thinner types exist in Process()
|
||||||
CHECK(thinner_type_ == PacketThinnerCalculatorOptions::ASYNC ||
|
ABSL_CHECK(thinner_type_ == PacketThinnerCalculatorOptions::ASYNC ||
|
||||||
thinner_type_ == PacketThinnerCalculatorOptions::SYNC)
|
thinner_type_ == PacketThinnerCalculatorOptions::SYNC)
|
||||||
<< "Unsupported thinner type.";
|
<< "Unsupported thinner type.";
|
||||||
|
|
||||||
if (thinner_type_ == PacketThinnerCalculatorOptions::ASYNC) {
|
if (thinner_type_ == PacketThinnerCalculatorOptions::ASYNC) {
|
||||||
@@ -177,7 +178,8 @@ absl::Status PacketThinnerCalculator::Open(CalculatorContext* cc) {
|
|||||||
} else {
|
} else {
|
||||||
period_ = TimestampDiff(options.period());
|
period_ = TimestampDiff(options.period());
|
||||||
}
|
}
|
||||||
CHECK_LT(TimestampDiff(0), period_) << "Specified period must be positive.";
|
ABSL_CHECK_LT(TimestampDiff(0), period_)
|
||||||
|
<< "Specified period must be positive.";
|
||||||
|
|
||||||
if (options.has_start_time()) {
|
if (options.has_start_time()) {
|
||||||
start_time_ = Timestamp(options.start_time());
|
start_time_ = Timestamp(options.start_time());
|
||||||
@@ -189,7 +191,7 @@ absl::Status PacketThinnerCalculator::Open(CalculatorContext* cc) {
|
|||||||
|
|
||||||
end_time_ =
|
end_time_ =
|
||||||
options.has_end_time() ? Timestamp(options.end_time()) : Timestamp::Max();
|
options.has_end_time() ? Timestamp(options.end_time()) : Timestamp::Max();
|
||||||
CHECK_LT(start_time_, end_time_)
|
ABSL_CHECK_LT(start_time_, end_time_)
|
||||||
<< "Invalid PacketThinner: start_time must be earlier than end_time";
|
<< "Invalid PacketThinner: start_time must be earlier than end_time";
|
||||||
|
|
||||||
sync_output_timestamps_ = options.sync_output_timestamps();
|
sync_output_timestamps_ = options.sync_output_timestamps();
|
||||||
@@ -232,7 +234,7 @@ absl::Status PacketThinnerCalculator::Close(CalculatorContext* cc) {
|
|||||||
// Emit any saved packets before quitting.
|
// Emit any saved packets before quitting.
|
||||||
if (!saved_packet_.IsEmpty()) {
|
if (!saved_packet_.IsEmpty()) {
|
||||||
// Only sync thinner should have saved packets.
|
// Only sync thinner should have saved packets.
|
||||||
CHECK_EQ(PacketThinnerCalculatorOptions::SYNC, thinner_type_);
|
ABSL_CHECK_EQ(PacketThinnerCalculatorOptions::SYNC, thinner_type_);
|
||||||
if (sync_output_timestamps_) {
|
if (sync_output_timestamps_) {
|
||||||
cc->Outputs().Index(0).AddPacket(
|
cc->Outputs().Index(0).AddPacket(
|
||||||
saved_packet_.At(NearestSyncTimestamp(saved_packet_.Timestamp())));
|
saved_packet_.At(NearestSyncTimestamp(saved_packet_.Timestamp())));
|
||||||
@@ -269,7 +271,7 @@ absl::Status PacketThinnerCalculator::SyncThinnerProcess(
|
|||||||
const Timestamp saved_sync = NearestSyncTimestamp(saved);
|
const Timestamp saved_sync = NearestSyncTimestamp(saved);
|
||||||
const Timestamp now = cc->InputTimestamp();
|
const Timestamp now = cc->InputTimestamp();
|
||||||
const Timestamp now_sync = NearestSyncTimestamp(now);
|
const Timestamp now_sync = NearestSyncTimestamp(now);
|
||||||
CHECK_LE(saved_sync, now_sync);
|
ABSL_CHECK_LE(saved_sync, now_sync);
|
||||||
if (saved_sync == now_sync) {
|
if (saved_sync == now_sync) {
|
||||||
// Saved Packet is in same interval as current packet.
|
// Saved Packet is in same interval as current packet.
|
||||||
// Replace saved packet with current if it is at least as
|
// Replace saved packet with current if it is at least as
|
||||||
@@ -295,7 +297,7 @@ absl::Status PacketThinnerCalculator::SyncThinnerProcess(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Timestamp PacketThinnerCalculator::NearestSyncTimestamp(Timestamp now) const {
|
Timestamp PacketThinnerCalculator::NearestSyncTimestamp(Timestamp now) const {
|
||||||
CHECK_NE(start_time_, Timestamp::Unset())
|
ABSL_CHECK_NE(start_time_, Timestamp::Unset())
|
||||||
<< "Method only valid for sync thinner calculator.";
|
<< "Method only valid for sync thinner calculator.";
|
||||||
|
|
||||||
// Computation is done using int64 arithmetic. No easy way to avoid
|
// Computation is done using int64 arithmetic. No easy way to avoid
|
||||||
@@ -303,12 +305,12 @@ Timestamp PacketThinnerCalculator::NearestSyncTimestamp(Timestamp now) const {
|
|||||||
const int64_t now64 = now.Value();
|
const int64_t now64 = now.Value();
|
||||||
const int64_t start64 = start_time_.Value();
|
const int64_t start64 = start_time_.Value();
|
||||||
const int64_t period64 = period_.Value();
|
const int64_t period64 = period_.Value();
|
||||||
CHECK_LE(0, period64);
|
ABSL_CHECK_LE(0, period64);
|
||||||
|
|
||||||
// Round now64 to its closest interval (units of period64).
|
// Round now64 to its closest interval (units of period64).
|
||||||
int64_t sync64 =
|
int64_t sync64 =
|
||||||
(now64 - start64 + period64 / 2) / period64 * period64 + start64;
|
(now64 - start64 + period64 / 2) / period64 * period64 + start64;
|
||||||
CHECK_LE(abs(now64 - sync64), period64 / 2)
|
ABSL_CHECK_LE(abs(now64 - sync64), period64 / 2)
|
||||||
<< "start64: " << start64 << "; now64: " << now64
|
<< "start64: " << start64 << "; now64: " << now64
|
||||||
<< "; sync64: " << sync64;
|
<< "; sync64: " << sync64;
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
#include "mediapipe/calculators/core/packet_thinner_calculator.pb.h"
|
#include "mediapipe/calculators/core/packet_thinner_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -70,7 +71,7 @@ class SimpleRunner : public CalculatorRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double GetFrameRate() const {
|
double GetFrameRate() const {
|
||||||
CHECK(!Outputs().Index(0).header.IsEmpty());
|
ABSL_CHECK(!Outputs().Index(0).header.IsEmpty());
|
||||||
return Outputs().Index(0).header.Get<VideoHeader>().frame_rate;
|
return Outputs().Index(0).header.Get<VideoHeader>().frame_rate;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/calculators/core/sequence_shift_calculator.pb.h"
|
#include "mediapipe/calculators/core/sequence_shift_calculator.pb.h"
|
||||||
#include "mediapipe/framework/api2/node.h"
|
#include "mediapipe/framework/api2/node.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -101,7 +102,7 @@ void SequenceShiftCalculator::ProcessPositiveOffset(CalculatorContext* cc) {
|
|||||||
kOut(cc).Send(packet_cache_.front().At(cc->InputTimestamp()));
|
kOut(cc).Send(packet_cache_.front().At(cc->InputTimestamp()));
|
||||||
packet_cache_.pop_front();
|
packet_cache_.pop_front();
|
||||||
} else if (emit_empty_packets_before_first_packet_) {
|
} else if (emit_empty_packets_before_first_packet_) {
|
||||||
LOG(FATAL) << "Not supported yet";
|
ABSL_LOG(FATAL) << "Not supported yet";
|
||||||
}
|
}
|
||||||
// Store current packet for later output.
|
// Store current packet for later output.
|
||||||
packet_cache_.push_back(kIn(cc).packet());
|
packet_cache_.push_back(kIn(cc).packet());
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "mediapipe/calculators/core/split_vector_calculator.pb.h"
|
#include "mediapipe/calculators/core/split_vector_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/formats/body_rig.pb.h"
|
||||||
#include "mediapipe/framework/formats/landmark.pb.h"
|
#include "mediapipe/framework/formats/landmark.pb.h"
|
||||||
#include "mediapipe/framework/port/canonical_errors.h"
|
#include "mediapipe/framework/port/canonical_errors.h"
|
||||||
#include "mediapipe/framework/port/ret_check.h"
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
@@ -196,6 +197,18 @@ class SplitLandmarkListCalculator
|
|||||||
};
|
};
|
||||||
REGISTER_CALCULATOR(SplitLandmarkListCalculator);
|
REGISTER_CALCULATOR(SplitLandmarkListCalculator);
|
||||||
|
|
||||||
|
class SplitJointListCalculator : public SplitListsCalculator<Joint, JointList> {
|
||||||
|
protected:
|
||||||
|
int ListSize(const JointList& list) const override {
|
||||||
|
return list.joint_size();
|
||||||
|
}
|
||||||
|
const Joint GetItem(const JointList& list, int idx) const override {
|
||||||
|
return list.joint(idx);
|
||||||
|
}
|
||||||
|
Joint* AddItem(JointList& list) const override { return list.add_joint(); }
|
||||||
|
};
|
||||||
|
REGISTER_CALCULATOR(SplitJointListCalculator);
|
||||||
|
|
||||||
} // namespace mediapipe
|
} // namespace mediapipe
|
||||||
|
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/port/status.h"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr char kInputValueTag[] = "IN";
|
||||||
|
constexpr char kTickerTag[] = "TICK";
|
||||||
|
constexpr char kOutputTag[] = "OUT";
|
||||||
|
constexpr char kIndicationTag[] = "FLAG";
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
// For every packet received on the TICK stream, if the IN stream is not
|
||||||
|
// empty - emit its value as is as OUT. Otherwise output a default packet.
|
||||||
|
// FLAG outputs true every time the default value has been used. It does not
|
||||||
|
// output anything when IN has a value.
|
||||||
|
//
|
||||||
|
// Example config:
|
||||||
|
// node {
|
||||||
|
// calculator: "ValueOrDefaultCalculator"
|
||||||
|
// input_stream: "IN:sometimes_missing_value"
|
||||||
|
// input_stream: "TICK:clock"
|
||||||
|
// output_stream: "OUT:value_or_default"
|
||||||
|
// output_stream: "FLAG:used_default"
|
||||||
|
// input_side_packet: "default"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// TODO: Consider adding an option for a default value as a input-stream
|
||||||
|
// instead of a side-packet, so it will enable using standard calculators
|
||||||
|
// instead of creating a new packet-generators. It will also allow a dynamic
|
||||||
|
// default value.
|
||||||
|
class ValueOrDefaultCalculator : public mediapipe::CalculatorBase {
|
||||||
|
public:
|
||||||
|
ValueOrDefaultCalculator() {}
|
||||||
|
|
||||||
|
ValueOrDefaultCalculator(const ValueOrDefaultCalculator&) = delete;
|
||||||
|
ValueOrDefaultCalculator& operator=(const ValueOrDefaultCalculator&) = delete;
|
||||||
|
|
||||||
|
static mediapipe::Status GetContract(mediapipe::CalculatorContract* cc) {
|
||||||
|
cc->Inputs().Tag(kInputValueTag).SetAny();
|
||||||
|
cc->Inputs().Tag(kTickerTag).SetAny();
|
||||||
|
cc->Outputs().Tag(kOutputTag).SetSameAs(&cc->Inputs().Tag(kInputValueTag));
|
||||||
|
cc->Outputs().Tag(kIndicationTag).Set<bool>();
|
||||||
|
cc->InputSidePackets().Index(0).SetSameAs(
|
||||||
|
&cc->Inputs().Tag(kInputValueTag));
|
||||||
|
|
||||||
|
return mediapipe::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
mediapipe::Status Open(mediapipe::CalculatorContext* cc) override {
|
||||||
|
if (!cc->Inputs().Tag(kInputValueTag).Header().IsEmpty()) {
|
||||||
|
cc->Outputs()
|
||||||
|
.Tag(kOutputTag)
|
||||||
|
.SetHeader(cc->Inputs().Tag(kInputValueTag).Header());
|
||||||
|
}
|
||||||
|
default_ = cc->InputSidePackets().Index(0);
|
||||||
|
cc->SetOffset(mediapipe::TimestampDiff(0));
|
||||||
|
return mediapipe::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
mediapipe::Status Process(mediapipe::CalculatorContext* cc) override {
|
||||||
|
// Output according to the TICK signal.
|
||||||
|
if (cc->Inputs().Tag(kTickerTag).IsEmpty()) {
|
||||||
|
return mediapipe::OkStatus();
|
||||||
|
}
|
||||||
|
if (!cc->Inputs().Tag(kInputValueTag).IsEmpty()) {
|
||||||
|
// Output the input as is:
|
||||||
|
cc->Outputs()
|
||||||
|
.Tag(kOutputTag)
|
||||||
|
.AddPacket(cc->Inputs().Tag(kInputValueTag).Value());
|
||||||
|
} else {
|
||||||
|
// Output default:
|
||||||
|
cc->Outputs()
|
||||||
|
.Tag(kOutputTag)
|
||||||
|
.AddPacket(default_.At(cc->InputTimestamp()));
|
||||||
|
cc->Outputs()
|
||||||
|
.Tag(kIndicationTag)
|
||||||
|
.Add(new bool(true), cc->InputTimestamp());
|
||||||
|
}
|
||||||
|
return mediapipe::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The default value to replicate every time there is no new value.
|
||||||
|
mediapipe::Packet default_;
|
||||||
|
};
|
||||||
|
|
||||||
|
REGISTER_CALCULATOR(ValueOrDefaultCalculator);
|
||||||
|
|
||||||
|
} // namespace mediapipe
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/calculator_runner.h"
|
||||||
|
#include "mediapipe/framework/packet.h"
|
||||||
|
#include "mediapipe/framework/port/gmock.h"
|
||||||
|
#include "mediapipe/framework/port/gtest.h"
|
||||||
|
#include "mediapipe/framework/port/status_matchers.h"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::testing::AllOf;
|
||||||
|
using ::testing::ContainerEq;
|
||||||
|
using ::testing::Each;
|
||||||
|
using ::testing::ElementsAre;
|
||||||
|
using ::testing::IsEmpty;
|
||||||
|
using ::testing::SizeIs;
|
||||||
|
using ::testing::Test;
|
||||||
|
|
||||||
|
const int kDefaultValue = 0;
|
||||||
|
|
||||||
|
// Utility to a create a mediapipe graph runner with the tested calculator and a
|
||||||
|
// default value, for all the tests.
|
||||||
|
class ValueOrDefaultRunner : public mediapipe::CalculatorRunner {
|
||||||
|
public:
|
||||||
|
ValueOrDefaultRunner()
|
||||||
|
: mediapipe::CalculatorRunner(R"pb(
|
||||||
|
calculator: "ValueOrDefaultCalculator"
|
||||||
|
input_stream: "IN:in"
|
||||||
|
input_stream: "TICK:tick"
|
||||||
|
input_side_packet: "default"
|
||||||
|
output_stream: "OUT:out"
|
||||||
|
output_stream: "FLAG:used_default"
|
||||||
|
)pb") {
|
||||||
|
MutableSidePackets()->Index(0) = mediapipe::MakePacket<int>(kDefaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility to push inputs to the runner to the TICK stream, so we could easily
|
||||||
|
// tick.
|
||||||
|
void TickAt(int64_t time) {
|
||||||
|
// The type or value of the stream isn't relevant, we use just a bool.
|
||||||
|
MutableInputs()->Tag("TICK").packets.push_back(
|
||||||
|
mediapipe::Adopt(new bool(false)).At(mediapipe::Timestamp(time)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility to push the real inputs to the runner (IN stream).
|
||||||
|
void ProvideInput(int64_t time, int value) {
|
||||||
|
MutableInputs()->Tag("IN").packets.push_back(
|
||||||
|
mediapipe::Adopt(new int(value)).At(mediapipe::Timestamp(time)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts the timestamps (as int64) of the output stream of the calculator.
|
||||||
|
std::vector<int64_t> GetOutputTimestamps() const {
|
||||||
|
std::vector<int64_t> timestamps;
|
||||||
|
for (const mediapipe::Packet& packet : Outputs().Tag("OUT").packets) {
|
||||||
|
timestamps.emplace_back(packet.Timestamp().Value());
|
||||||
|
}
|
||||||
|
return timestamps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts the values from the output stream of the calculator.
|
||||||
|
std::vector<int> GetOutputValues() const {
|
||||||
|
std::vector<int> values;
|
||||||
|
for (const mediapipe::Packet& packet : Outputs().Tag("OUT").packets) {
|
||||||
|
values.emplace_back(packet.Get<int>());
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts the timestamps (as int64) of the flag stream, which indicates on
|
||||||
|
// times without an input value (i.e. using the default value).
|
||||||
|
std::vector<int64_t> GetFlagTimestamps() const {
|
||||||
|
std::vector<int64_t> timestamps;
|
||||||
|
for (const mediapipe::Packet& packet : Outputs().Tag("FLAG").packets) {
|
||||||
|
timestamps.emplace_back(packet.Timestamp().Value());
|
||||||
|
}
|
||||||
|
return timestamps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts the output from the flags stream (which should always be true).
|
||||||
|
std::vector<bool> GetFlagValues() const {
|
||||||
|
std::vector<bool> flags;
|
||||||
|
for (const mediapipe::Packet& packet : Outputs().Tag("FLAG").packets) {
|
||||||
|
flags.emplace_back(packet.Get<bool>());
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// To be used as input values:
|
||||||
|
std::vector<int> GetIntegersRange(int size) {
|
||||||
|
std::vector<int> result;
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
// We start with default-value+1 so it won't contain the default value.
|
||||||
|
result.push_back(kDefaultValue + 1 + i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ValueOrDefaultCalculatorTest, NoInputs) {
|
||||||
|
// Check that when no real inputs are provided - we get the default value over
|
||||||
|
// and over, with the correct timestamps.
|
||||||
|
ValueOrDefaultRunner runner;
|
||||||
|
const std::vector<int64_t> ticks = {0, 1, 2, 5, 8, 12, 33, 231};
|
||||||
|
|
||||||
|
for (int tick : ticks) {
|
||||||
|
runner.TickAt(tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_EXPECT_OK(runner.Run());
|
||||||
|
|
||||||
|
// Make sure we get the right timestamps:
|
||||||
|
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
|
||||||
|
// All should be default value:
|
||||||
|
EXPECT_THAT(runner.GetOutputValues(),
|
||||||
|
AllOf(Each(kDefaultValue), SizeIs(ticks.size())));
|
||||||
|
// We should get the default indication all the time:
|
||||||
|
EXPECT_THAT(runner.GetFlagTimestamps(), ContainerEq(ticks));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ValueOrDefaultCalculatorTest, NeverDefault) {
|
||||||
|
// Check that when we provide the inputs on time - we get them as outputs.
|
||||||
|
ValueOrDefaultRunner runner;
|
||||||
|
const std::vector<int64_t> ticks = {0, 1, 2, 5, 8, 12, 33, 231};
|
||||||
|
const std::vector<int> values = GetIntegersRange(ticks.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < ticks.size(); ++i) {
|
||||||
|
runner.TickAt(ticks[i]);
|
||||||
|
runner.ProvideInput(ticks[i], values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_EXPECT_OK(runner.Run());
|
||||||
|
|
||||||
|
// Make sure we get the right timestamps:
|
||||||
|
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
|
||||||
|
// Should get the inputs values:
|
||||||
|
EXPECT_THAT(runner.GetOutputValues(), ContainerEq(values));
|
||||||
|
// We should never get the default indication:
|
||||||
|
EXPECT_THAT(runner.GetFlagTimestamps(), IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ValueOrDefaultCalculatorTest, DefaultAndValues) {
|
||||||
|
// Check that when we provide inputs only part of the time - we get them, but
|
||||||
|
// defaults at the missing times.
|
||||||
|
// That's the usual use case for this calculator.
|
||||||
|
ValueOrDefaultRunner runner;
|
||||||
|
const std::vector<int64_t> ticks = {0, 1, 5, 8, 12, 231};
|
||||||
|
// Provide inputs only part of the ticks.
|
||||||
|
// Chosen so there will be defaults before the first input, between the
|
||||||
|
// inputs and after the last input.
|
||||||
|
const std::vector<int64_t> in_ticks = {/*0,*/ 1, 5, /*8,*/ 12, /*, 231*/};
|
||||||
|
const std::vector<int> in_values = GetIntegersRange(in_ticks.size());
|
||||||
|
|
||||||
|
for (int tick : ticks) {
|
||||||
|
runner.TickAt(tick);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < in_ticks.size(); ++i) {
|
||||||
|
runner.ProvideInput(in_ticks[i], in_values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_EXPECT_OK(runner.Run());
|
||||||
|
|
||||||
|
// Make sure we get all the timestamps:
|
||||||
|
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
|
||||||
|
// The timestamps of the flag should be exactly the ones not in in_ticks.
|
||||||
|
EXPECT_THAT(runner.GetFlagTimestamps(), ElementsAre(0, 8, 231));
|
||||||
|
// And the values are default in these times, and the input values for
|
||||||
|
// in_ticks.
|
||||||
|
EXPECT_THAT(
|
||||||
|
runner.GetOutputValues(),
|
||||||
|
ElementsAre(kDefaultValue, 1, 2, kDefaultValue, 3, kDefaultValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ValueOrDefaultCalculatorTest, TimestampsMissmatch) {
|
||||||
|
// Check that when we provide the inputs not on time - we don't get them.
|
||||||
|
ValueOrDefaultRunner runner;
|
||||||
|
const std::vector<int64_t> ticks = {1, 2, 5, 8, 12, 33, 231};
|
||||||
|
// The timestamps chosen so it will be before the first tick, in between ticks
|
||||||
|
// and after the last one. Also - more inputs than ticks.
|
||||||
|
const std::vector<int64_t> in_ticks = {0, 3, 4, 6, 7, 9, 10,
|
||||||
|
11, 13, 14, 15, 16, 232};
|
||||||
|
const std::vector<int> in_values = GetIntegersRange(in_ticks.size());
|
||||||
|
for (int tick : ticks) {
|
||||||
|
runner.TickAt(tick);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < in_ticks.size(); ++i) {
|
||||||
|
runner.ProvideInput(in_ticks[i], in_values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_EXPECT_OK(runner.Run());
|
||||||
|
|
||||||
|
// Non of the in_ticks should be inserted:
|
||||||
|
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
|
||||||
|
EXPECT_THAT(runner.GetOutputValues(),
|
||||||
|
AllOf(Each(kDefaultValue), SizeIs(ticks.size())));
|
||||||
|
// All (and only) ticks should get the default.
|
||||||
|
EXPECT_THAT(runner.GetFlagTimestamps(), ContainerEq(ticks));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ValueOrDefaultCalculatorTest, FlagValue) {
|
||||||
|
// Since we anyway suppose that the Flag is a bool - there is nothing
|
||||||
|
// interesting to check, but we should check once that the value is the right
|
||||||
|
// (true) one.
|
||||||
|
ValueOrDefaultRunner runner;
|
||||||
|
runner.TickAt(0);
|
||||||
|
MP_EXPECT_OK(runner.Run());
|
||||||
|
EXPECT_THAT(runner.GetFlagValues(), ElementsAre(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ValueOrDefaultCalculatorTest, FullTest) {
|
||||||
|
// Make sure that nothing gets wrong with an input that have both right and
|
||||||
|
// wrong timestamps, some defaults etc.
|
||||||
|
ValueOrDefaultRunner runner;
|
||||||
|
const std::vector<int64_t> ticks = {1, 2, 5, 8, 12, 33, 231};
|
||||||
|
const std::vector<int64_t> in_ticks = {0, 2, 4, 6, 8, 9, 12, 33, 54, 232};
|
||||||
|
const std::vector<int> in_values = GetIntegersRange(in_ticks.size());
|
||||||
|
|
||||||
|
for (int tick : ticks) {
|
||||||
|
runner.TickAt(tick);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < in_ticks.size(); ++i) {
|
||||||
|
runner.ProvideInput(in_ticks[i], in_values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_EXPECT_OK(runner.Run());
|
||||||
|
|
||||||
|
EXPECT_THAT(runner.GetOutputTimestamps(), ContainerEq(ticks));
|
||||||
|
// Calculated by hand:
|
||||||
|
EXPECT_THAT(
|
||||||
|
runner.GetOutputValues(),
|
||||||
|
ElementsAre(kDefaultValue, 2, kDefaultValue, 5, 7, 8, kDefaultValue));
|
||||||
|
EXPECT_THAT(runner.GetFlagTimestamps(), ElementsAre(1, 5, 231));
|
||||||
|
EXPECT_THAT(runner.GetFlagValues(), AllOf(Each(true), SizeIs(3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace mediapipe
|
||||||
@@ -97,6 +97,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:source_location",
|
"//mediapipe/framework/port:source_location",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
@@ -125,6 +126,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:opencv_imgcodecs",
|
"//mediapipe/framework/port:opencv_imgcodecs",
|
||||||
"//mediapipe/framework/port:opencv_imgproc",
|
"//mediapipe/framework/port:opencv_imgproc",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
@@ -151,11 +153,11 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:image_format_cc_proto",
|
"//mediapipe/framework/formats:image_format_cc_proto",
|
||||||
"//mediapipe/framework/formats:image_frame",
|
"//mediapipe/framework/formats:image_frame",
|
||||||
"//mediapipe/framework/formats:image_frame_opencv",
|
"//mediapipe/framework/formats:image_frame_opencv",
|
||||||
"//mediapipe/framework/port:logging",
|
|
||||||
"//mediapipe/framework/port:opencv_core",
|
"//mediapipe/framework/port:opencv_core",
|
||||||
"//mediapipe/framework/port:opencv_imgproc",
|
"//mediapipe/framework/port:opencv_imgproc",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/port:vector",
|
"//mediapipe/framework/port:vector",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
] + select({
|
] + select({
|
||||||
"//mediapipe/gpu:disable_gpu": [],
|
"//mediapipe/gpu:disable_gpu": [],
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
@@ -202,6 +204,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:opencv_imgproc",
|
"//mediapipe/framework/port:opencv_imgproc",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/port:vector",
|
"//mediapipe/framework/port:vector",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
] + select({
|
] + select({
|
||||||
"//mediapipe/gpu:disable_gpu": [],
|
"//mediapipe/gpu:disable_gpu": [],
|
||||||
@@ -261,9 +264,12 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/gpu:scale_mode_cc_proto",
|
"//mediapipe/gpu:scale_mode_cc_proto",
|
||||||
|
"@com_google_absl//absl/status",
|
||||||
|
"@com_google_absl//absl/strings",
|
||||||
] + select({
|
] + select({
|
||||||
"//mediapipe/gpu:disable_gpu": [],
|
"//mediapipe/gpu:disable_gpu": [],
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
|
"//mediapipe/gpu:gl_base_hdr",
|
||||||
"//mediapipe/gpu:gl_calculator_helper",
|
"//mediapipe/gpu:gl_calculator_helper",
|
||||||
"//mediapipe/gpu:gl_quad_renderer",
|
"//mediapipe/gpu:gl_quad_renderer",
|
||||||
"//mediapipe/gpu:gl_simple_shaders",
|
"//mediapipe/gpu:gl_simple_shaders",
|
||||||
@@ -273,6 +279,36 @@ cc_library(
|
|||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "image_transformation_calculator_test",
|
||||||
|
srcs = ["image_transformation_calculator_test.cc"],
|
||||||
|
data = ["//mediapipe/calculators/image/testdata:test_images"],
|
||||||
|
tags = [
|
||||||
|
"desktop_only_test",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
":image_transformation_calculator",
|
||||||
|
"//mediapipe/framework:calculator_cc_proto",
|
||||||
|
"//mediapipe/framework:calculator_framework",
|
||||||
|
"//mediapipe/framework:calculator_runner",
|
||||||
|
"//mediapipe/framework/deps:file_path",
|
||||||
|
"//mediapipe/framework/formats:image_format_cc_proto",
|
||||||
|
"//mediapipe/framework/formats:image_frame",
|
||||||
|
"//mediapipe/framework/formats:image_frame_opencv",
|
||||||
|
"//mediapipe/framework/port:gtest",
|
||||||
|
"//mediapipe/framework/port:opencv_imgcodecs",
|
||||||
|
"//mediapipe/framework/port:opencv_imgproc",
|
||||||
|
"//mediapipe/framework/port:parse_text_proto",
|
||||||
|
"//mediapipe/gpu:gpu_buffer_to_image_frame_calculator",
|
||||||
|
"//mediapipe/gpu:image_frame_to_gpu_buffer_calculator",
|
||||||
|
"//third_party:opencv",
|
||||||
|
"@com_google_absl//absl/container:flat_hash_set",
|
||||||
|
"@com_google_absl//absl/flags:flag",
|
||||||
|
"@com_google_absl//absl/strings",
|
||||||
|
"@com_google_googletest//:gtest_main",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "image_cropping_calculator",
|
name = "image_cropping_calculator",
|
||||||
srcs = ["image_cropping_calculator.cc"],
|
srcs = ["image_cropping_calculator.cc"],
|
||||||
@@ -300,6 +336,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:opencv_imgproc",
|
"//mediapipe/framework/port:opencv_imgproc",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
] + select({
|
] + select({
|
||||||
"//mediapipe/gpu:disable_gpu": [],
|
"//mediapipe/gpu:disable_gpu": [],
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
@@ -396,6 +433,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:logging",
|
"//mediapipe/framework/port:logging",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -420,6 +458,8 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/util:image_frame_util",
|
"//mediapipe/util:image_frame_util",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@libyuv",
|
"@libyuv",
|
||||||
],
|
],
|
||||||
@@ -625,9 +665,9 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:image",
|
"//mediapipe/framework/formats:image",
|
||||||
"//mediapipe/framework/formats:image_format_cc_proto",
|
"//mediapipe/framework/formats:image_format_cc_proto",
|
||||||
"//mediapipe/framework/formats:image_frame",
|
"//mediapipe/framework/formats:image_frame",
|
||||||
"//mediapipe/framework/port:logging",
|
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/port:vector",
|
"//mediapipe/framework/port:vector",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
] + select({
|
] + select({
|
||||||
"//mediapipe/gpu:disable_gpu": [],
|
"//mediapipe/gpu:disable_gpu": [],
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
@@ -665,6 +705,7 @@ cc_test(
|
|||||||
"//mediapipe/framework/port:opencv_imgcodecs",
|
"//mediapipe/framework/port:opencv_imgcodecs",
|
||||||
"//mediapipe/framework/port:opencv_imgproc",
|
"//mediapipe/framework/port:opencv_imgproc",
|
||||||
"//mediapipe/framework/port:parse_text_proto",
|
"//mediapipe/framework/port:parse_text_proto",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -687,6 +728,7 @@ cc_library(
|
|||||||
"//mediapipe/gpu:gpu_buffer",
|
"//mediapipe/gpu:gpu_buffer",
|
||||||
"//mediapipe/gpu:gpu_origin_cc_proto",
|
"//mediapipe/gpu:gpu_origin_cc_proto",
|
||||||
"//mediapipe/gpu:shader_util",
|
"//mediapipe/gpu:shader_util",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
"@com_google_absl//absl/status",
|
"@com_google_absl//absl/status",
|
||||||
"@com_google_absl//absl/status:statusor",
|
"@com_google_absl//absl/status:statusor",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "Eigen/Core"
|
#include "Eigen/Core"
|
||||||
#include "Eigen/Geometry"
|
#include "Eigen/Geometry"
|
||||||
#include "Eigen/LU"
|
#include "Eigen/LU"
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/status/status.h"
|
#include "absl/status/status.h"
|
||||||
#include "absl/status/statusor.h"
|
#include "absl/status/statusor.h"
|
||||||
@@ -53,6 +54,10 @@ bool IsMatrixVerticalFlipNeeded(GpuOrigin::Mode gpu_origin) {
|
|||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
case GpuOrigin::TOP_LEFT:
|
case GpuOrigin::TOP_LEFT:
|
||||||
return false;
|
return false;
|
||||||
|
default:
|
||||||
|
ABSL_LOG(ERROR) << "Incorrect GpuOrigin: "
|
||||||
|
<< static_cast<int>(gpu_origin);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +223,7 @@ class GlTextureWarpAffineRunner
|
|||||||
absl::StrCat(mediapipe::kMediaPipeFragmentShaderPreamble,
|
absl::StrCat(mediapipe::kMediaPipeFragmentShaderPreamble,
|
||||||
interpolation_def, kFragShader);
|
interpolation_def, kFragShader);
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(program_, create_fn(vert_src, frag_src));
|
MP_ASSIGN_OR_RETURN(program_, create_fn(vert_src, frag_src));
|
||||||
|
|
||||||
auto create_custom_zero_fn = [&]() -> absl::StatusOr<Program> {
|
auto create_custom_zero_fn = [&]() -> absl::StatusOr<Program> {
|
||||||
std::string custom_zero_border_mode_def = R"(
|
std::string custom_zero_border_mode_def = R"(
|
||||||
@@ -231,10 +236,10 @@ class GlTextureWarpAffineRunner
|
|||||||
};
|
};
|
||||||
#if GL_CLAMP_TO_BORDER_MAY_BE_SUPPORTED
|
#if GL_CLAMP_TO_BORDER_MAY_BE_SUPPORTED
|
||||||
if (!IsGlClampToBorderSupported(gl_helper_->GetGlContext())) {
|
if (!IsGlClampToBorderSupported(gl_helper_->GetGlContext())) {
|
||||||
ASSIGN_OR_RETURN(program_custom_zero_, create_custom_zero_fn());
|
MP_ASSIGN_OR_RETURN(program_custom_zero_, create_custom_zero_fn());
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ASSIGN_OR_RETURN(program_custom_zero_, create_custom_zero_fn());
|
MP_ASSIGN_OR_RETURN(program_custom_zero_, create_custom_zero_fn());
|
||||||
#endif // GL_CLAMP_TO_BORDER_MAY_BE_SUPPORTED
|
#endif // GL_CLAMP_TO_BORDER_MAY_BE_SUPPORTED
|
||||||
|
|
||||||
glGenFramebuffers(1, &framebuffer_);
|
glGenFramebuffers(1, &framebuffer_);
|
||||||
@@ -384,6 +389,8 @@ class GlTextureWarpAffineRunner
|
|||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "absl/strings/str_replace.h"
|
#include "absl/strings/str_replace.h"
|
||||||
#include "mediapipe/calculators/image/bilateral_filter_calculator.pb.h"
|
#include "mediapipe/calculators/image/bilateral_filter_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -183,8 +184,8 @@ absl::Status BilateralFilterCalculator::Open(CalculatorContext* cc) {
|
|||||||
|
|
||||||
sigma_color_ = options_.sigma_color();
|
sigma_color_ = options_.sigma_color();
|
||||||
sigma_space_ = options_.sigma_space();
|
sigma_space_ = options_.sigma_space();
|
||||||
CHECK_GE(sigma_color_, 0.0);
|
ABSL_CHECK_GE(sigma_color_, 0.0);
|
||||||
CHECK_GE(sigma_space_, 0.0);
|
ABSL_CHECK_GE(sigma_space_, 0.0);
|
||||||
if (!use_gpu_) sigma_color_ *= 255.0;
|
if (!use_gpu_) sigma_color_ *= 255.0;
|
||||||
|
|
||||||
if (use_gpu_) {
|
if (use_gpu_) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/formats/image_frame.h"
|
#include "mediapipe/framework/formats/image_frame.h"
|
||||||
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
||||||
@@ -25,8 +26,8 @@
|
|||||||
namespace mediapipe {
|
namespace mediapipe {
|
||||||
namespace {
|
namespace {
|
||||||
void SetColorChannel(int channel, uint8 value, cv::Mat* mat) {
|
void SetColorChannel(int channel, uint8 value, cv::Mat* mat) {
|
||||||
CHECK(mat->depth() == CV_8U);
|
ABSL_CHECK(mat->depth() == CV_8U);
|
||||||
CHECK(channel < mat->channels());
|
ABSL_CHECK(channel < mat->channels());
|
||||||
const int step = mat->channels();
|
const int step = mat->channels();
|
||||||
for (int r = 0; r < mat->rows; ++r) {
|
for (int r = 0; r < mat->rows; ++r) {
|
||||||
uint8* row_ptr = mat->ptr<uint8>(r);
|
uint8* row_ptr = mat->ptr<uint8>(r);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/framework/formats/image_frame.h"
|
#include "mediapipe/framework/formats/image_frame.h"
|
||||||
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
||||||
#include "mediapipe/framework/formats/rect.pb.h"
|
#include "mediapipe/framework/formats/rect.pb.h"
|
||||||
@@ -202,8 +203,9 @@ absl::Status ImageCroppingCalculator::ValidateBorderModeForGPU(
|
|||||||
|
|
||||||
switch (options.border_mode()) {
|
switch (options.border_mode()) {
|
||||||
case mediapipe::ImageCroppingCalculatorOptions::BORDER_ZERO:
|
case mediapipe::ImageCroppingCalculatorOptions::BORDER_ZERO:
|
||||||
LOG(WARNING) << "BORDER_ZERO mode is not supported by GPU "
|
ABSL_LOG(WARNING)
|
||||||
<< "implementation and will fall back into BORDER_REPLICATE";
|
<< "BORDER_ZERO mode is not supported by GPU "
|
||||||
|
<< "implementation and will fall back into BORDER_REPLICATE";
|
||||||
break;
|
break;
|
||||||
case mediapipe::ImageCroppingCalculatorOptions::BORDER_REPLICATE:
|
case mediapipe::ImageCroppingCalculatorOptions::BORDER_REPLICATE:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -92,11 +92,11 @@ absl::StatusOr<ImageFileProperties> GetImageFileProperites(
|
|||||||
properties.set_focal_length_mm(result.FocalLength);
|
properties.set_focal_length_mm(result.FocalLength);
|
||||||
properties.set_focal_length_35mm(result.FocalLengthIn35mm);
|
properties.set_focal_length_35mm(result.FocalLengthIn35mm);
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(auto focal_length_pixels,
|
MP_ASSIGN_OR_RETURN(auto focal_length_pixels,
|
||||||
ComputeFocalLengthInPixels(properties.image_width(),
|
ComputeFocalLengthInPixels(properties.image_width(),
|
||||||
properties.image_height(),
|
properties.image_height(),
|
||||||
properties.focal_length_35mm(),
|
properties.focal_length_35mm(),
|
||||||
properties.focal_length_mm()));
|
properties.focal_length_mm()));
|
||||||
properties.set_focal_length_pixels(focal_length_pixels);
|
properties.set_focal_length_pixels(focal_length_pixels);
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
@@ -151,7 +151,7 @@ class ImageFilePropertiesCalculator : public CalculatorBase {
|
|||||||
if (cc->InputSidePackets().NumEntries() == 1) {
|
if (cc->InputSidePackets().NumEntries() == 1) {
|
||||||
const std::string& image_bytes =
|
const std::string& image_bytes =
|
||||||
cc->InputSidePackets().Index(0).Get<std::string>();
|
cc->InputSidePackets().Index(0).Get<std::string>();
|
||||||
ASSIGN_OR_RETURN(properties_, GetImageFileProperites(image_bytes));
|
MP_ASSIGN_OR_RETURN(properties_, GetImageFileProperites(image_bytes));
|
||||||
read_properties_ = true;
|
read_properties_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ class ImageFilePropertiesCalculator : public CalculatorBase {
|
|||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
const std::string& image_bytes = cc->Inputs().Index(0).Get<std::string>();
|
const std::string& image_bytes = cc->Inputs().Index(0).Get<std::string>();
|
||||||
ASSIGN_OR_RETURN(properties_, GetImageFileProperites(image_bytes));
|
MP_ASSIGN_OR_RETURN(properties_, GetImageFileProperites(image_bytes));
|
||||||
read_properties_ = true;
|
read_properties_ = true;
|
||||||
}
|
}
|
||||||
if (read_properties_) {
|
if (read_properties_) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/status/status.h"
|
||||||
#include "mediapipe/calculators/image/image_transformation_calculator.pb.h"
|
#include "mediapipe/calculators/image/image_transformation_calculator.pb.h"
|
||||||
#include "mediapipe/calculators/image/rotation_mode.pb.h"
|
#include "mediapipe/calculators/image/rotation_mode.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
#include "mediapipe/gpu/scale_mode.pb.h"
|
#include "mediapipe/gpu/scale_mode.pb.h"
|
||||||
|
|
||||||
#if !MEDIAPIPE_DISABLE_GPU
|
#if !MEDIAPIPE_DISABLE_GPU
|
||||||
|
#include "mediapipe/gpu/gl_base.h"
|
||||||
#include "mediapipe/gpu/gl_calculator_helper.h"
|
#include "mediapipe/gpu/gl_calculator_helper.h"
|
||||||
#include "mediapipe/gpu/gl_quad_renderer.h"
|
#include "mediapipe/gpu/gl_quad_renderer.h"
|
||||||
#include "mediapipe/gpu/gl_simple_shaders.h"
|
#include "mediapipe/gpu/gl_simple_shaders.h"
|
||||||
@@ -60,42 +62,42 @@ constexpr char kVideoPrestreamTag[] = "VIDEO_PRESTREAM";
|
|||||||
|
|
||||||
int RotationModeToDegrees(mediapipe::RotationMode_Mode rotation) {
|
int RotationModeToDegrees(mediapipe::RotationMode_Mode rotation) {
|
||||||
switch (rotation) {
|
switch (rotation) {
|
||||||
case mediapipe::RotationMode_Mode_UNKNOWN:
|
case mediapipe::RotationMode::UNKNOWN:
|
||||||
case mediapipe::RotationMode_Mode_ROTATION_0:
|
case mediapipe::RotationMode::ROTATION_0:
|
||||||
return 0;
|
return 0;
|
||||||
case mediapipe::RotationMode_Mode_ROTATION_90:
|
case mediapipe::RotationMode::ROTATION_90:
|
||||||
return 90;
|
return 90;
|
||||||
case mediapipe::RotationMode_Mode_ROTATION_180:
|
case mediapipe::RotationMode::ROTATION_180:
|
||||||
return 180;
|
return 180;
|
||||||
case mediapipe::RotationMode_Mode_ROTATION_270:
|
case mediapipe::RotationMode::ROTATION_270:
|
||||||
return 270;
|
return 270;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mediapipe::RotationMode_Mode DegreesToRotationMode(int degrees) {
|
mediapipe::RotationMode_Mode DegreesToRotationMode(int degrees) {
|
||||||
switch (degrees) {
|
switch (degrees) {
|
||||||
case 0:
|
case 0:
|
||||||
return mediapipe::RotationMode_Mode_ROTATION_0;
|
return mediapipe::RotationMode::ROTATION_0;
|
||||||
case 90:
|
case 90:
|
||||||
return mediapipe::RotationMode_Mode_ROTATION_90;
|
return mediapipe::RotationMode::ROTATION_90;
|
||||||
case 180:
|
case 180:
|
||||||
return mediapipe::RotationMode_Mode_ROTATION_180;
|
return mediapipe::RotationMode::ROTATION_180;
|
||||||
case 270:
|
case 270:
|
||||||
return mediapipe::RotationMode_Mode_ROTATION_270;
|
return mediapipe::RotationMode::ROTATION_270;
|
||||||
default:
|
default:
|
||||||
return mediapipe::RotationMode_Mode_UNKNOWN;
|
return mediapipe::RotationMode::UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mediapipe::ScaleMode_Mode ParseScaleMode(
|
mediapipe::ScaleMode_Mode ParseScaleMode(
|
||||||
mediapipe::ScaleMode_Mode scale_mode,
|
mediapipe::ScaleMode_Mode scale_mode,
|
||||||
mediapipe::ScaleMode_Mode default_mode) {
|
mediapipe::ScaleMode_Mode default_mode) {
|
||||||
switch (scale_mode) {
|
switch (scale_mode) {
|
||||||
case mediapipe::ScaleMode_Mode_DEFAULT:
|
case mediapipe::ScaleMode::DEFAULT:
|
||||||
return default_mode;
|
return default_mode;
|
||||||
case mediapipe::ScaleMode_Mode_STRETCH:
|
case mediapipe::ScaleMode::STRETCH:
|
||||||
return scale_mode;
|
return scale_mode;
|
||||||
case mediapipe::ScaleMode_Mode_FIT:
|
case mediapipe::ScaleMode::FIT:
|
||||||
return scale_mode;
|
return scale_mode;
|
||||||
case mediapipe::ScaleMode_Mode_FILL_AND_CROP:
|
case mediapipe::ScaleMode::FILL_AND_CROP:
|
||||||
return scale_mode;
|
return scale_mode;
|
||||||
default:
|
default:
|
||||||
return default_mode;
|
return default_mode;
|
||||||
@@ -208,6 +210,8 @@ class ImageTransformationCalculator : public CalculatorBase {
|
|||||||
|
|
||||||
bool use_gpu_ = false;
|
bool use_gpu_ = false;
|
||||||
cv::Scalar padding_color_;
|
cv::Scalar padding_color_;
|
||||||
|
ImageTransformationCalculatorOptions::InterpolationMode interpolation_mode_;
|
||||||
|
|
||||||
#if !MEDIAPIPE_DISABLE_GPU
|
#if !MEDIAPIPE_DISABLE_GPU
|
||||||
GlCalculatorHelper gpu_helper_;
|
GlCalculatorHelper gpu_helper_;
|
||||||
std::unique_ptr<QuadRenderer> rgb_renderer_;
|
std::unique_ptr<QuadRenderer> rgb_renderer_;
|
||||||
@@ -343,6 +347,11 @@ absl::Status ImageTransformationCalculator::Open(CalculatorContext* cc) {
|
|||||||
options_.padding_color().green(),
|
options_.padding_color().green(),
|
||||||
options_.padding_color().blue());
|
options_.padding_color().blue());
|
||||||
|
|
||||||
|
interpolation_mode_ = options_.interpolation_mode();
|
||||||
|
if (options_.interpolation_mode() ==
|
||||||
|
ImageTransformationCalculatorOptions::DEFAULT) {
|
||||||
|
interpolation_mode_ = ImageTransformationCalculatorOptions::LINEAR;
|
||||||
|
}
|
||||||
if (use_gpu_) {
|
if (use_gpu_) {
|
||||||
#if !MEDIAPIPE_DISABLE_GPU
|
#if !MEDIAPIPE_DISABLE_GPU
|
||||||
// Let the helper access the GL context information.
|
// Let the helper access the GL context information.
|
||||||
@@ -457,26 +466,48 @@ absl::Status ImageTransformationCalculator::RenderCpu(CalculatorContext* cc) {
|
|||||||
ComputeOutputDimensions(input_width, input_height, &output_width,
|
ComputeOutputDimensions(input_width, input_height, &output_width,
|
||||||
&output_height);
|
&output_height);
|
||||||
|
|
||||||
|
int opencv_interpolation_mode = cv::INTER_LINEAR;
|
||||||
if (output_width_ > 0 && output_height_ > 0) {
|
if (output_width_ > 0 && output_height_ > 0) {
|
||||||
cv::Mat scaled_mat;
|
cv::Mat scaled_mat;
|
||||||
if (scale_mode_ == mediapipe::ScaleMode_Mode_STRETCH) {
|
if (scale_mode_ == mediapipe::ScaleMode::STRETCH) {
|
||||||
int scale_flag =
|
if (interpolation_mode_ == ImageTransformationCalculatorOptions::LINEAR) {
|
||||||
input_mat.cols > output_width_ && input_mat.rows > output_height_
|
// Use INTER_AREA for downscaling if interpolation mode is set to
|
||||||
? cv::INTER_AREA
|
// LINEAR.
|
||||||
: cv::INTER_LINEAR;
|
if (input_mat.cols > output_width_ && input_mat.rows > output_height_) {
|
||||||
|
opencv_interpolation_mode = cv::INTER_AREA;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
opencv_interpolation_mode = cv::INTER_LINEAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opencv_interpolation_mode = cv::INTER_NEAREST;
|
||||||
|
}
|
||||||
cv::resize(input_mat, scaled_mat, cv::Size(output_width_, output_height_),
|
cv::resize(input_mat, scaled_mat, cv::Size(output_width_, output_height_),
|
||||||
0, 0, scale_flag);
|
0, 0, opencv_interpolation_mode);
|
||||||
} else {
|
} else {
|
||||||
const float scale =
|
const float scale =
|
||||||
std::min(static_cast<float>(output_width_) / input_width,
|
std::min(static_cast<float>(output_width_) / input_width,
|
||||||
static_cast<float>(output_height_) / input_height);
|
static_cast<float>(output_height_) / input_height);
|
||||||
const int target_width = std::round(input_width * scale);
|
const int target_width = std::round(input_width * scale);
|
||||||
const int target_height = std::round(input_height * scale);
|
const int target_height = std::round(input_height * scale);
|
||||||
int scale_flag = scale < 1.0f ? cv::INTER_AREA : cv::INTER_LINEAR;
|
|
||||||
if (scale_mode_ == mediapipe::ScaleMode_Mode_FIT) {
|
if (interpolation_mode_ == ImageTransformationCalculatorOptions::LINEAR) {
|
||||||
|
// Use INTER_AREA for downscaling if interpolation mode is set to
|
||||||
|
// LINEAR.
|
||||||
|
if (scale < 1.0f) {
|
||||||
|
opencv_interpolation_mode = cv::INTER_AREA;
|
||||||
|
} else {
|
||||||
|
opencv_interpolation_mode = cv::INTER_LINEAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opencv_interpolation_mode = cv::INTER_NEAREST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale_mode_ == mediapipe::ScaleMode::FIT) {
|
||||||
cv::Mat intermediate_mat;
|
cv::Mat intermediate_mat;
|
||||||
cv::resize(input_mat, intermediate_mat,
|
cv::resize(input_mat, intermediate_mat,
|
||||||
cv::Size(target_width, target_height), 0, 0, scale_flag);
|
cv::Size(target_width, target_height), 0, 0,
|
||||||
|
opencv_interpolation_mode);
|
||||||
const int top = (output_height_ - target_height) / 2;
|
const int top = (output_height_ - target_height) / 2;
|
||||||
const int bottom = output_height_ - target_height - top;
|
const int bottom = output_height_ - target_height - top;
|
||||||
const int left = (output_width_ - target_width) / 2;
|
const int left = (output_width_ - target_width) / 2;
|
||||||
@@ -488,7 +519,7 @@ absl::Status ImageTransformationCalculator::RenderCpu(CalculatorContext* cc) {
|
|||||||
padding_color_);
|
padding_color_);
|
||||||
} else {
|
} else {
|
||||||
cv::resize(input_mat, scaled_mat, cv::Size(target_width, target_height),
|
cv::resize(input_mat, scaled_mat, cv::Size(target_width, target_height),
|
||||||
0, 0, scale_flag);
|
0, 0, opencv_interpolation_mode);
|
||||||
output_width = target_width;
|
output_width = target_width;
|
||||||
output_height = target_height;
|
output_height = target_height;
|
||||||
}
|
}
|
||||||
@@ -514,17 +545,17 @@ absl::Status ImageTransformationCalculator::RenderCpu(CalculatorContext* cc) {
|
|||||||
cv::warpAffine(input_mat, rotated_mat, rotation_mat, rotated_size);
|
cv::warpAffine(input_mat, rotated_mat, rotation_mat, rotated_size);
|
||||||
} else {
|
} else {
|
||||||
switch (rotation_) {
|
switch (rotation_) {
|
||||||
case mediapipe::RotationMode_Mode_UNKNOWN:
|
case mediapipe::RotationMode::UNKNOWN:
|
||||||
case mediapipe::RotationMode_Mode_ROTATION_0:
|
case mediapipe::RotationMode::ROTATION_0:
|
||||||
rotated_mat = input_mat;
|
rotated_mat = input_mat;
|
||||||
break;
|
break;
|
||||||
case mediapipe::RotationMode_Mode_ROTATION_90:
|
case mediapipe::RotationMode::ROTATION_90:
|
||||||
cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_COUNTERCLOCKWISE);
|
cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_COUNTERCLOCKWISE);
|
||||||
break;
|
break;
|
||||||
case mediapipe::RotationMode_Mode_ROTATION_180:
|
case mediapipe::RotationMode::ROTATION_180:
|
||||||
cv::rotate(input_mat, rotated_mat, cv::ROTATE_180);
|
cv::rotate(input_mat, rotated_mat, cv::ROTATE_180);
|
||||||
break;
|
break;
|
||||||
case mediapipe::RotationMode_Mode_ROTATION_270:
|
case mediapipe::RotationMode::ROTATION_270:
|
||||||
cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_CLOCKWISE);
|
cv::rotate(input_mat, rotated_mat, cv::ROTATE_90_CLOCKWISE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -561,7 +592,7 @@ absl::Status ImageTransformationCalculator::RenderGpu(CalculatorContext* cc) {
|
|||||||
ComputeOutputDimensions(input_width, input_height, &output_width,
|
ComputeOutputDimensions(input_width, input_height, &output_width,
|
||||||
&output_height);
|
&output_height);
|
||||||
|
|
||||||
if (scale_mode_ == mediapipe::ScaleMode_Mode_FILL_AND_CROP) {
|
if (scale_mode_ == mediapipe::ScaleMode::FILL_AND_CROP) {
|
||||||
const float scale =
|
const float scale =
|
||||||
std::min(static_cast<float>(output_width_) / input_width,
|
std::min(static_cast<float>(output_width_) / input_width,
|
||||||
static_cast<float>(output_height_) / input_height);
|
static_cast<float>(output_height_) / input_height);
|
||||||
@@ -628,6 +659,12 @@ absl::Status ImageTransformationCalculator::RenderGpu(CalculatorContext* cc) {
|
|||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(src1.target(), src1.name());
|
glBindTexture(src1.target(), src1.name());
|
||||||
|
|
||||||
|
if (interpolation_mode_ == ImageTransformationCalculatorOptions::NEAREST) {
|
||||||
|
// TODO: revert texture params.
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
|
||||||
MP_RETURN_IF_ERROR(renderer->GlRender(
|
MP_RETURN_IF_ERROR(renderer->GlRender(
|
||||||
src1.width(), src1.height(), dst.width(), dst.height(), scale_mode,
|
src1.width(), src1.height(), dst.width(), dst.height(), scale_mode,
|
||||||
rotation, flip_horizontally_, flip_vertically_,
|
rotation, flip_horizontally_, flip_vertically_,
|
||||||
@@ -652,8 +689,8 @@ void ImageTransformationCalculator::ComputeOutputDimensions(
|
|||||||
if (output_width_ > 0 && output_height_ > 0) {
|
if (output_width_ > 0 && output_height_ > 0) {
|
||||||
*output_width = output_width_;
|
*output_width = output_width_;
|
||||||
*output_height = output_height_;
|
*output_height = output_height_;
|
||||||
} else if (rotation_ == mediapipe::RotationMode_Mode_ROTATION_90 ||
|
} else if (rotation_ == mediapipe::RotationMode::ROTATION_90 ||
|
||||||
rotation_ == mediapipe::RotationMode_Mode_ROTATION_270) {
|
rotation_ == mediapipe::RotationMode::ROTATION_270) {
|
||||||
*output_width = input_height;
|
*output_width = input_height;
|
||||||
*output_height = input_width;
|
*output_height = input_width;
|
||||||
} else {
|
} else {
|
||||||
@@ -666,9 +703,9 @@ void ImageTransformationCalculator::ComputeOutputLetterboxPadding(
|
|||||||
int input_width, int input_height, int output_width, int output_height,
|
int input_width, int input_height, int output_width, int output_height,
|
||||||
std::array<float, 4>* padding) {
|
std::array<float, 4>* padding) {
|
||||||
padding->fill(0.f);
|
padding->fill(0.f);
|
||||||
if (scale_mode_ == mediapipe::ScaleMode_Mode_FIT) {
|
if (scale_mode_ == mediapipe::ScaleMode::FIT) {
|
||||||
if (rotation_ == mediapipe::RotationMode_Mode_ROTATION_90 ||
|
if (rotation_ == mediapipe::RotationMode::ROTATION_90 ||
|
||||||
rotation_ == mediapipe::RotationMode_Mode_ROTATION_270) {
|
rotation_ == mediapipe::RotationMode::ROTATION_270) {
|
||||||
std::swap(input_width, input_height);
|
std::swap(input_width, input_height);
|
||||||
}
|
}
|
||||||
const float input_aspect_ratio =
|
const float input_aspect_ratio =
|
||||||
|
|||||||
@@ -54,4 +54,15 @@ message ImageTransformationCalculatorOptions {
|
|||||||
// The color for the padding. This option is only used when the scale mode is
|
// The color for the padding. This option is only used when the scale mode is
|
||||||
// FIT. Default is black. This is for CPU only.
|
// FIT. Default is black. This is for CPU only.
|
||||||
optional Color padding_color = 8;
|
optional Color padding_color = 8;
|
||||||
|
|
||||||
|
// Interpolation method to use. Note that on CPU when LINEAR is specified,
|
||||||
|
// INTER_LINEAR is used for upscaling and INTER_AREA is used for downscaling.
|
||||||
|
enum InterpolationMode {
|
||||||
|
DEFAULT = 0;
|
||||||
|
LINEAR = 1;
|
||||||
|
NEAREST = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode DEFAULT will use LINEAR interpolation.
|
||||||
|
optional InterpolationMode interpolation_mode = 9;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,315 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/container/flat_hash_set.h"
|
||||||
|
#include "absl/flags/flag.h"
|
||||||
|
#include "absl/strings/substitute.h"
|
||||||
|
#include "mediapipe/framework/calculator.pb.h"
|
||||||
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/calculator_runner.h"
|
||||||
|
#include "mediapipe/framework/deps/file_path.h"
|
||||||
|
#include "mediapipe/framework/formats/image_format.pb.h"
|
||||||
|
#include "mediapipe/framework/formats/image_frame.h"
|
||||||
|
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
||||||
|
#include "mediapipe/framework/port/gtest.h"
|
||||||
|
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
|
||||||
|
#include "mediapipe/framework/port/opencv_imgproc_inc.h"
|
||||||
|
#include "mediapipe/framework/port/parse_text_proto.h"
|
||||||
|
#include "testing/base/public/gmock.h"
|
||||||
|
#include "testing/base/public/googletest.h"
|
||||||
|
#include "third_party/OpenCV/core.hpp" // IWYU pragma: keep
|
||||||
|
#include "third_party/OpenCV/core/mat.hpp"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
absl::flat_hash_set<int> computeUniqueValues(const cv::Mat& mat) {
|
||||||
|
// Compute the unique values in cv::Mat
|
||||||
|
absl::flat_hash_set<int> unique_values;
|
||||||
|
for (int i = 0; i < mat.rows; i++) {
|
||||||
|
for (int j = 0; j < mat.cols; j++) {
|
||||||
|
unique_values.insert(mat.at<unsigned char>(i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unique_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageTransformationCalculatorTest, NearestNeighborResizing) {
|
||||||
|
cv::Mat input_mat;
|
||||||
|
cv::cvtColor(cv::imread(file::JoinPath("./",
|
||||||
|
"/mediapipe/calculators/"
|
||||||
|
"image/testdata/binary_mask.png")),
|
||||||
|
input_mat, cv::COLOR_BGR2GRAY);
|
||||||
|
Packet input_image_packet = MakePacket<ImageFrame>(
|
||||||
|
ImageFormat::GRAY8, input_mat.size().width, input_mat.size().height);
|
||||||
|
input_mat.copyTo(formats::MatView(&(input_image_packet.Get<ImageFrame>())));
|
||||||
|
|
||||||
|
std::vector<std::pair<int, int>> output_dims{
|
||||||
|
{256, 333}, {512, 512}, {1024, 1024}};
|
||||||
|
|
||||||
|
for (auto& output_dim : output_dims) {
|
||||||
|
Packet input_output_dim_packet =
|
||||||
|
MakePacket<std::pair<int, int>>(output_dim);
|
||||||
|
std::vector<std::string> scale_modes{"FIT", "STRETCH"};
|
||||||
|
for (const auto& scale_mode : scale_modes) {
|
||||||
|
CalculatorGraphConfig::Node node_config =
|
||||||
|
ParseTextProtoOrDie<CalculatorGraphConfig::Node>(
|
||||||
|
absl::Substitute(R"(
|
||||||
|
calculator: "ImageTransformationCalculator"
|
||||||
|
input_stream: "IMAGE:input_image"
|
||||||
|
input_stream: "OUTPUT_DIMENSIONS:image_size"
|
||||||
|
output_stream: "IMAGE:output_image"
|
||||||
|
options: {
|
||||||
|
[mediapipe.ImageTransformationCalculatorOptions.ext]: {
|
||||||
|
scale_mode: $0
|
||||||
|
interpolation_mode: NEAREST
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
scale_mode));
|
||||||
|
|
||||||
|
CalculatorRunner runner(node_config);
|
||||||
|
runner.MutableInputs()->Tag("IMAGE").packets.push_back(
|
||||||
|
input_image_packet.At(Timestamp(0)));
|
||||||
|
runner.MutableInputs()
|
||||||
|
->Tag("OUTPUT_DIMENSIONS")
|
||||||
|
.packets.push_back(input_output_dim_packet.At(Timestamp(0)));
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner.Run());
|
||||||
|
const auto& outputs = runner.Outputs();
|
||||||
|
ASSERT_EQ(outputs.NumEntries(), 1);
|
||||||
|
const std::vector<Packet>& packets = outputs.Tag("IMAGE").packets;
|
||||||
|
ASSERT_EQ(packets.size(), 1);
|
||||||
|
const auto& result = packets[0].Get<ImageFrame>();
|
||||||
|
ASSERT_EQ(output_dim.first, result.Width());
|
||||||
|
ASSERT_EQ(output_dim.second, result.Height());
|
||||||
|
|
||||||
|
auto unique_input_values = computeUniqueValues(input_mat);
|
||||||
|
auto unique_output_values =
|
||||||
|
computeUniqueValues(formats::MatView(&result));
|
||||||
|
EXPECT_THAT(unique_input_values,
|
||||||
|
::testing::ContainerEq(unique_output_values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageTransformationCalculatorTest,
|
||||||
|
NearestNeighborResizingWorksForFloatInput) {
|
||||||
|
cv::Mat input_mat;
|
||||||
|
cv::cvtColor(cv::imread(file::JoinPath("./",
|
||||||
|
"/mediapipe/calculators/"
|
||||||
|
"image/testdata/binary_mask.png")),
|
||||||
|
input_mat, cv::COLOR_BGR2GRAY);
|
||||||
|
Packet input_image_packet = MakePacket<ImageFrame>(
|
||||||
|
ImageFormat::VEC32F1, input_mat.size().width, input_mat.size().height);
|
||||||
|
cv::Mat packet_mat_view =
|
||||||
|
formats::MatView(&(input_image_packet.Get<ImageFrame>()));
|
||||||
|
input_mat.convertTo(packet_mat_view, CV_32FC1, 1 / 255.f);
|
||||||
|
|
||||||
|
std::vector<std::pair<int, int>> output_dims{
|
||||||
|
{256, 333}, {512, 512}, {1024, 1024}};
|
||||||
|
|
||||||
|
for (auto& output_dim : output_dims) {
|
||||||
|
Packet input_output_dim_packet =
|
||||||
|
MakePacket<std::pair<int, int>>(output_dim);
|
||||||
|
std::vector<std::string> scale_modes{"FIT", "STRETCH"};
|
||||||
|
for (const auto& scale_mode : scale_modes) {
|
||||||
|
CalculatorGraphConfig::Node node_config =
|
||||||
|
ParseTextProtoOrDie<CalculatorGraphConfig::Node>(
|
||||||
|
absl::Substitute(R"(
|
||||||
|
calculator: "ImageTransformationCalculator"
|
||||||
|
input_stream: "IMAGE:input_image"
|
||||||
|
input_stream: "OUTPUT_DIMENSIONS:image_size"
|
||||||
|
output_stream: "IMAGE:output_image"
|
||||||
|
options: {
|
||||||
|
[mediapipe.ImageTransformationCalculatorOptions.ext]: {
|
||||||
|
scale_mode: $0
|
||||||
|
interpolation_mode: NEAREST
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
scale_mode));
|
||||||
|
|
||||||
|
CalculatorRunner runner(node_config);
|
||||||
|
runner.MutableInputs()->Tag("IMAGE").packets.push_back(
|
||||||
|
input_image_packet.At(Timestamp(0)));
|
||||||
|
runner.MutableInputs()
|
||||||
|
->Tag("OUTPUT_DIMENSIONS")
|
||||||
|
.packets.push_back(input_output_dim_packet.At(Timestamp(0)));
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner.Run());
|
||||||
|
const auto& outputs = runner.Outputs();
|
||||||
|
ASSERT_EQ(outputs.NumEntries(), 1);
|
||||||
|
const std::vector<Packet>& packets = outputs.Tag("IMAGE").packets;
|
||||||
|
ASSERT_EQ(packets.size(), 1);
|
||||||
|
const auto& result = packets[0].Get<ImageFrame>();
|
||||||
|
ASSERT_EQ(output_dim.first, result.Width());
|
||||||
|
ASSERT_EQ(output_dim.second, result.Height());
|
||||||
|
|
||||||
|
auto unique_input_values = computeUniqueValues(packet_mat_view);
|
||||||
|
auto unique_output_values =
|
||||||
|
computeUniqueValues(formats::MatView(&result));
|
||||||
|
EXPECT_THAT(unique_input_values,
|
||||||
|
::testing::ContainerEq(unique_output_values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageTransformationCalculatorTest, NearestNeighborResizingGpu) {
|
||||||
|
cv::Mat input_mat;
|
||||||
|
cv::cvtColor(cv::imread(file::JoinPath("./",
|
||||||
|
"/mediapipe/calculators/"
|
||||||
|
"image/testdata/binary_mask.png")),
|
||||||
|
input_mat, cv::COLOR_BGR2RGBA);
|
||||||
|
|
||||||
|
std::vector<std::pair<int, int>> output_dims{
|
||||||
|
{256, 333}, {512, 512}, {1024, 1024}};
|
||||||
|
|
||||||
|
for (auto& output_dim : output_dims) {
|
||||||
|
std::vector<std::string> scale_modes{"FIT"}; //, "STRETCH"};
|
||||||
|
for (const auto& scale_mode : scale_modes) {
|
||||||
|
CalculatorGraphConfig graph_config =
|
||||||
|
ParseTextProtoOrDie<CalculatorGraphConfig>(
|
||||||
|
absl::Substitute(R"(
|
||||||
|
input_stream: "input_image"
|
||||||
|
input_stream: "image_size"
|
||||||
|
output_stream: "output_image"
|
||||||
|
|
||||||
|
node {
|
||||||
|
calculator: "ImageFrameToGpuBufferCalculator"
|
||||||
|
input_stream: "input_image"
|
||||||
|
output_stream: "input_image_gpu"
|
||||||
|
}
|
||||||
|
|
||||||
|
node {
|
||||||
|
calculator: "ImageTransformationCalculator"
|
||||||
|
input_stream: "IMAGE_GPU:input_image_gpu"
|
||||||
|
input_stream: "OUTPUT_DIMENSIONS:image_size"
|
||||||
|
output_stream: "IMAGE_GPU:output_image_gpu"
|
||||||
|
options: {
|
||||||
|
[mediapipe.ImageTransformationCalculatorOptions.ext]: {
|
||||||
|
scale_mode: $0
|
||||||
|
interpolation_mode: NEAREST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
calculator: "GpuBufferToImageFrameCalculator"
|
||||||
|
input_stream: "output_image_gpu"
|
||||||
|
output_stream: "output_image"
|
||||||
|
})",
|
||||||
|
scale_mode));
|
||||||
|
ImageFrame input_image(ImageFormat::SRGBA, input_mat.size().width,
|
||||||
|
input_mat.size().height);
|
||||||
|
input_mat.copyTo(formats::MatView(&input_image));
|
||||||
|
|
||||||
|
std::vector<Packet> output_image_packets;
|
||||||
|
tool::AddVectorSink("output_image", &graph_config, &output_image_packets);
|
||||||
|
|
||||||
|
CalculatorGraph graph(graph_config);
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
|
||||||
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
|
"input_image",
|
||||||
|
MakePacket<ImageFrame>(std::move(input_image)).At(Timestamp(0))));
|
||||||
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
|
"image_size",
|
||||||
|
MakePacket<std::pair<int, int>>(output_dim).At(Timestamp(0))));
|
||||||
|
|
||||||
|
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||||
|
ASSERT_THAT(output_image_packets, testing::SizeIs(1));
|
||||||
|
|
||||||
|
const auto& output_image = output_image_packets[0].Get<ImageFrame>();
|
||||||
|
ASSERT_EQ(output_dim.first, output_image.Width());
|
||||||
|
ASSERT_EQ(output_dim.second, output_image.Height());
|
||||||
|
|
||||||
|
auto unique_input_values = computeUniqueValues(input_mat);
|
||||||
|
auto unique_output_values =
|
||||||
|
computeUniqueValues(formats::MatView(&output_image));
|
||||||
|
EXPECT_THAT(unique_input_values,
|
||||||
|
::testing::ContainerEq(unique_output_values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageTransformationCalculatorTest,
|
||||||
|
NearestNeighborResizingWorksForFloatTexture) {
|
||||||
|
cv::Mat input_mat;
|
||||||
|
cv::cvtColor(cv::imread(file::JoinPath("./",
|
||||||
|
"/mediapipe/calculators/"
|
||||||
|
"image/testdata/binary_mask.png")),
|
||||||
|
input_mat, cv::COLOR_BGR2GRAY);
|
||||||
|
Packet input_image_packet = MakePacket<ImageFrame>(
|
||||||
|
ImageFormat::VEC32F1, input_mat.size().width, input_mat.size().height);
|
||||||
|
cv::Mat packet_mat_view =
|
||||||
|
formats::MatView(&(input_image_packet.Get<ImageFrame>()));
|
||||||
|
input_mat.convertTo(packet_mat_view, CV_32FC1, 1 / 255.f);
|
||||||
|
|
||||||
|
std::vector<std::pair<int, int>> output_dims{
|
||||||
|
{256, 333}, {512, 512}, {1024, 1024}};
|
||||||
|
|
||||||
|
for (auto& output_dim : output_dims) {
|
||||||
|
std::vector<std::string> scale_modes{"FIT"}; //, "STRETCH"};
|
||||||
|
for (const auto& scale_mode : scale_modes) {
|
||||||
|
CalculatorGraphConfig graph_config =
|
||||||
|
ParseTextProtoOrDie<CalculatorGraphConfig>(
|
||||||
|
absl::Substitute(R"(
|
||||||
|
input_stream: "input_image"
|
||||||
|
input_stream: "image_size"
|
||||||
|
output_stream: "output_image"
|
||||||
|
|
||||||
|
node {
|
||||||
|
calculator: "ImageFrameToGpuBufferCalculator"
|
||||||
|
input_stream: "input_image"
|
||||||
|
output_stream: "input_image_gpu"
|
||||||
|
}
|
||||||
|
|
||||||
|
node {
|
||||||
|
calculator: "ImageTransformationCalculator"
|
||||||
|
input_stream: "IMAGE_GPU:input_image_gpu"
|
||||||
|
input_stream: "OUTPUT_DIMENSIONS:image_size"
|
||||||
|
output_stream: "IMAGE_GPU:output_image_gpu"
|
||||||
|
options: {
|
||||||
|
[mediapipe.ImageTransformationCalculatorOptions.ext]: {
|
||||||
|
scale_mode: $0
|
||||||
|
interpolation_mode: NEAREST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
calculator: "GpuBufferToImageFrameCalculator"
|
||||||
|
input_stream: "output_image_gpu"
|
||||||
|
output_stream: "output_image"
|
||||||
|
})",
|
||||||
|
scale_mode));
|
||||||
|
|
||||||
|
std::vector<Packet> output_image_packets;
|
||||||
|
tool::AddVectorSink("output_image", &graph_config, &output_image_packets);
|
||||||
|
|
||||||
|
CalculatorGraph graph(graph_config);
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
|
||||||
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
|
"input_image", input_image_packet.At(Timestamp(0))));
|
||||||
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
|
"image_size",
|
||||||
|
MakePacket<std::pair<int, int>>(output_dim).At(Timestamp(0))));
|
||||||
|
|
||||||
|
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||||
|
ASSERT_THAT(output_image_packets, testing::SizeIs(1));
|
||||||
|
|
||||||
|
const auto& output_image = output_image_packets[0].Get<ImageFrame>();
|
||||||
|
ASSERT_EQ(output_dim.first, output_image.Width());
|
||||||
|
ASSERT_EQ(output_dim.second, output_image.Height());
|
||||||
|
|
||||||
|
auto unique_input_values = computeUniqueValues(packet_mat_view);
|
||||||
|
auto unique_output_values =
|
||||||
|
computeUniqueValues(formats::MatView(&output_image));
|
||||||
|
EXPECT_THAT(unique_input_values,
|
||||||
|
::testing::ContainerEq(unique_output_values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace mediapipe
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
|
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
||||||
@@ -61,7 +62,7 @@ absl::Status OpenCvImageEncoderCalculator::Open(CalculatorContext* cc) {
|
|||||||
|
|
||||||
absl::Status OpenCvImageEncoderCalculator::Process(CalculatorContext* cc) {
|
absl::Status OpenCvImageEncoderCalculator::Process(CalculatorContext* cc) {
|
||||||
const ImageFrame& image_frame = cc->Inputs().Index(0).Get<ImageFrame>();
|
const ImageFrame& image_frame = cc->Inputs().Index(0).Get<ImageFrame>();
|
||||||
CHECK_EQ(1, image_frame.ByteDepth());
|
ABSL_CHECK_EQ(1, image_frame.ByteDepth());
|
||||||
|
|
||||||
std::unique_ptr<OpenCvImageEncoderCalculatorResults> encoded_result =
|
std::unique_ptr<OpenCvImageEncoderCalculatorResults> encoded_result =
|
||||||
absl::make_unique<OpenCvImageEncoderCalculatorResults>();
|
absl::make_unique<OpenCvImageEncoderCalculatorResults>();
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
#include "absl/strings/substitute.h"
|
#include "absl/strings/substitute.h"
|
||||||
#include "libyuv/scale.h"
|
#include "libyuv/scale.h"
|
||||||
@@ -293,7 +295,7 @@ absl::Status ScaleImageCalculator::InitializeFrameInfo(CalculatorContext* cc) {
|
|||||||
header->width = output_width_;
|
header->width = output_width_;
|
||||||
header->height = output_height_;
|
header->height = output_height_;
|
||||||
header->format = output_format_;
|
header->format = output_format_;
|
||||||
LOG(INFO) << "OUTPUTTING HEADER on stream";
|
ABSL_LOG(INFO) << "OUTPUTTING HEADER on stream";
|
||||||
cc->Outputs()
|
cc->Outputs()
|
||||||
.Tag("VIDEO_HEADER")
|
.Tag("VIDEO_HEADER")
|
||||||
.Add(header.release(), Timestamp::PreStream());
|
.Add(header.release(), Timestamp::PreStream());
|
||||||
@@ -393,10 +395,11 @@ absl::Status ScaleImageCalculator::Open(CalculatorContext* cc) {
|
|||||||
.SetHeader(Adopt(output_header.release()));
|
.SetHeader(Adopt(output_header.release()));
|
||||||
has_header_ = true;
|
has_header_ = true;
|
||||||
} else {
|
} else {
|
||||||
LOG(WARNING) << "Stream had a VideoHeader which didn't have sufficient "
|
ABSL_LOG(WARNING)
|
||||||
"information. "
|
<< "Stream had a VideoHeader which didn't have sufficient "
|
||||||
"Dropping VideoHeader and trying to deduce needed "
|
"information. "
|
||||||
"information.";
|
"Dropping VideoHeader and trying to deduce needed "
|
||||||
|
"information.";
|
||||||
input_width_ = 0;
|
input_width_ = 0;
|
||||||
input_height_ = 0;
|
input_height_ = 0;
|
||||||
if (!options_.has_input_format()) {
|
if (!options_.has_input_format()) {
|
||||||
@@ -507,7 +510,7 @@ absl::Status ScaleImageCalculator::ValidateImageFrame(
|
|||||||
|
|
||||||
absl::Status ScaleImageCalculator::ValidateYUVImage(CalculatorContext* cc,
|
absl::Status ScaleImageCalculator::ValidateYUVImage(CalculatorContext* cc,
|
||||||
const YUVImage& yuv_image) {
|
const YUVImage& yuv_image) {
|
||||||
CHECK_EQ(input_format_, ImageFormat::YCBCR420P);
|
ABSL_CHECK_EQ(input_format_, ImageFormat::YCBCR420P);
|
||||||
if (!has_header_) {
|
if (!has_header_) {
|
||||||
if (input_width_ != yuv_image.width() ||
|
if (input_width_ != yuv_image.width() ||
|
||||||
input_height_ != yuv_image.height()) {
|
input_height_ != yuv_image.height()) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "absl/strings/str_split.h"
|
#include "absl/strings/str_split.h"
|
||||||
#include "mediapipe/framework/port/logging.h"
|
#include "mediapipe/framework/port/logging.h"
|
||||||
#include "mediapipe/framework/port/ret_check.h"
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
@@ -40,10 +41,10 @@ absl::Status FindCropDimensions(int input_width, int input_height, //
|
|||||||
const std::string& max_aspect_ratio, //
|
const std::string& max_aspect_ratio, //
|
||||||
int* crop_width, int* crop_height, //
|
int* crop_width, int* crop_height, //
|
||||||
int* col_start, int* row_start) {
|
int* col_start, int* row_start) {
|
||||||
CHECK(crop_width);
|
ABSL_CHECK(crop_width);
|
||||||
CHECK(crop_height);
|
ABSL_CHECK(crop_height);
|
||||||
CHECK(col_start);
|
ABSL_CHECK(col_start);
|
||||||
CHECK(row_start);
|
ABSL_CHECK(row_start);
|
||||||
|
|
||||||
double min_aspect_ratio_q = 0.0;
|
double min_aspect_ratio_q = 0.0;
|
||||||
double max_aspect_ratio_q = 0.0;
|
double max_aspect_ratio_q = 0.0;
|
||||||
@@ -83,8 +84,8 @@ absl::Status FindCropDimensions(int input_width, int input_height, //
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_LE(*crop_width, input_width);
|
ABSL_CHECK_LE(*crop_width, input_width);
|
||||||
CHECK_LE(*crop_height, input_height);
|
ABSL_CHECK_LE(*crop_height, input_height);
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,8 +97,8 @@ absl::Status FindOutputDimensions(int input_width, //
|
|||||||
bool preserve_aspect_ratio, //
|
bool preserve_aspect_ratio, //
|
||||||
int scale_to_multiple_of, //
|
int scale_to_multiple_of, //
|
||||||
int* output_width, int* output_height) {
|
int* output_width, int* output_height) {
|
||||||
CHECK(output_width);
|
ABSL_CHECK(output_width);
|
||||||
CHECK(output_height);
|
ABSL_CHECK(output_height);
|
||||||
|
|
||||||
if (target_max_area > 0 && input_width * input_height > target_max_area) {
|
if (target_max_area > 0 && input_width * input_height > target_max_area) {
|
||||||
preserve_aspect_ratio = true;
|
preserve_aspect_ratio = true;
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h"
|
#include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/calculator_options.pb.h"
|
#include "mediapipe/framework/calculator_options.pb.h"
|
||||||
#include "mediapipe/framework/formats/image.h"
|
#include "mediapipe/framework/formats/image.h"
|
||||||
#include "mediapipe/framework/formats/image_format.pb.h"
|
#include "mediapipe/framework/formats/image_format.pb.h"
|
||||||
#include "mediapipe/framework/formats/image_frame.h"
|
#include "mediapipe/framework/formats/image_frame.h"
|
||||||
#include "mediapipe/framework/port/logging.h"
|
|
||||||
#include "mediapipe/framework/port/status.h"
|
#include "mediapipe/framework/port/status.h"
|
||||||
#include "mediapipe/framework/port/vector.h"
|
#include "mediapipe/framework/port/vector.h"
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ absl::Status SegmentationSmoothingCalculator::RenderGpu(CalculatorContext* cc) {
|
|||||||
|
|
||||||
const auto& previous_frame = cc->Inputs().Tag(kPreviousMaskTag).Get<Image>();
|
const auto& previous_frame = cc->Inputs().Tag(kPreviousMaskTag).Get<Image>();
|
||||||
if (previous_frame.format() != current_frame.format()) {
|
if (previous_frame.format() != current_frame.format()) {
|
||||||
LOG(ERROR) << "Warning: mixing input format types. ";
|
ABSL_LOG(ERROR) << "Warning: mixing input format types. ";
|
||||||
}
|
}
|
||||||
auto previous_texture = gpu_helper_.CreateSourceTexture(previous_frame);
|
auto previous_texture = gpu_helper_.CreateSourceTexture(previous_frame);
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h"
|
#include "mediapipe/calculators/image/segmentation_smoothing_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/calculator_runner.h"
|
#include "mediapipe/framework/calculator_runner.h"
|
||||||
@@ -169,7 +170,7 @@ void RunTest(bool use_gpu, float mix_ratio, cv::Mat& test_result) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG(ERROR) << "invalid ratio";
|
ABSL_LOG(ERROR) << "invalid ratio";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,13 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/calculators/image/set_alpha_calculator.pb.h"
|
#include "mediapipe/calculators/image/set_alpha_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/calculator_options.pb.h"
|
#include "mediapipe/framework/calculator_options.pb.h"
|
||||||
#include "mediapipe/framework/formats/image_format.pb.h"
|
#include "mediapipe/framework/formats/image_format.pb.h"
|
||||||
#include "mediapipe/framework/formats/image_frame.h"
|
#include "mediapipe/framework/formats/image_frame.h"
|
||||||
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
||||||
#include "mediapipe/framework/port/logging.h"
|
|
||||||
#include "mediapipe/framework/port/opencv_core_inc.h"
|
#include "mediapipe/framework/port/opencv_core_inc.h"
|
||||||
#include "mediapipe/framework/port/opencv_imgproc_inc.h"
|
#include "mediapipe/framework/port/opencv_imgproc_inc.h"
|
||||||
#include "mediapipe/framework/port/status.h"
|
#include "mediapipe/framework/port/status.h"
|
||||||
@@ -268,7 +268,7 @@ absl::Status SetAlphaCalculator::RenderCpu(CalculatorContext* cc) {
|
|||||||
const auto& input_frame = cc->Inputs().Tag(kInputFrameTag).Get<ImageFrame>();
|
const auto& input_frame = cc->Inputs().Tag(kInputFrameTag).Get<ImageFrame>();
|
||||||
const cv::Mat input_mat = formats::MatView(&input_frame);
|
const cv::Mat input_mat = formats::MatView(&input_frame);
|
||||||
if (!(input_mat.type() == CV_8UC3 || input_mat.type() == CV_8UC4)) {
|
if (!(input_mat.type() == CV_8UC3 || input_mat.type() == CV_8UC4)) {
|
||||||
LOG(ERROR) << "Only 3 or 4 channel 8-bit input image supported";
|
ABSL_LOG(ERROR) << "Only 3 or 4 channel 8-bit input image supported";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup destination image
|
// Setup destination image
|
||||||
@@ -328,7 +328,7 @@ absl::Status SetAlphaCalculator::RenderGpu(CalculatorContext* cc) {
|
|||||||
cc->Inputs().Tag(kInputFrameTagGpu).Get<mediapipe::GpuBuffer>();
|
cc->Inputs().Tag(kInputFrameTagGpu).Get<mediapipe::GpuBuffer>();
|
||||||
if (!(input_frame.format() == mediapipe::GpuBufferFormat::kBGRA32 ||
|
if (!(input_frame.format() == mediapipe::GpuBufferFormat::kBGRA32 ||
|
||||||
input_frame.format() == mediapipe::GpuBufferFormat::kRGB24)) {
|
input_frame.format() == mediapipe::GpuBufferFormat::kRGB24)) {
|
||||||
LOG(ERROR) << "Only RGB or RGBA input image supported";
|
ABSL_LOG(ERROR) << "Only RGB or RGBA input image supported";
|
||||||
}
|
}
|
||||||
auto input_texture = gpu_helper_.CreateSourceTexture(input_frame);
|
auto input_texture = gpu_helper_.CreateSourceTexture(input_frame);
|
||||||
|
|
||||||
|
|||||||
+1
@@ -18,6 +18,7 @@ licenses(["notice"])
|
|||||||
filegroup(
|
filegroup(
|
||||||
name = "test_images",
|
name = "test_images",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"binary_mask.png",
|
||||||
"dino.jpg",
|
"dino.jpg",
|
||||||
"dino_quality_50.jpg",
|
"dino_quality_50.jpg",
|
||||||
"dino_quality_80.jpg",
|
"dino_quality_80.jpg",
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 771 B |
@@ -79,8 +79,8 @@ class WarpAffineRunnerHolder<ImageFrame> {
|
|||||||
}
|
}
|
||||||
absl::StatusOr<RunnerType*> GetRunner() {
|
absl::StatusOr<RunnerType*> GetRunner() {
|
||||||
if (!runner_) {
|
if (!runner_) {
|
||||||
ASSIGN_OR_RETURN(runner_,
|
MP_ASSIGN_OR_RETURN(
|
||||||
CreateAffineTransformationOpenCvRunner(interpolation_));
|
runner_, CreateAffineTransformationOpenCvRunner(interpolation_));
|
||||||
}
|
}
|
||||||
return runner_.get();
|
return runner_.get();
|
||||||
}
|
}
|
||||||
@@ -108,8 +108,9 @@ class WarpAffineRunnerHolder<mediapipe::GpuBuffer> {
|
|||||||
}
|
}
|
||||||
absl::StatusOr<RunnerType*> GetRunner() {
|
absl::StatusOr<RunnerType*> GetRunner() {
|
||||||
if (!runner_) {
|
if (!runner_) {
|
||||||
ASSIGN_OR_RETURN(runner_, CreateAffineTransformationGlRunner(
|
MP_ASSIGN_OR_RETURN(
|
||||||
gl_helper_, gpu_origin_, interpolation_));
|
runner_, CreateAffineTransformationGlRunner(gl_helper_, gpu_origin_,
|
||||||
|
interpolation_));
|
||||||
}
|
}
|
||||||
return runner_.get();
|
return runner_.get();
|
||||||
}
|
}
|
||||||
@@ -151,24 +152,25 @@ class WarpAffineRunnerHolder<mediapipe::Image> {
|
|||||||
AffineTransformation::BorderMode border_mode) override {
|
AffineTransformation::BorderMode border_mode) override {
|
||||||
if (input.UsesGpu()) {
|
if (input.UsesGpu()) {
|
||||||
#if !MEDIAPIPE_DISABLE_GPU
|
#if !MEDIAPIPE_DISABLE_GPU
|
||||||
ASSIGN_OR_RETURN(auto* runner, gpu_holder_.GetRunner());
|
MP_ASSIGN_OR_RETURN(auto* runner, gpu_holder_.GetRunner());
|
||||||
ASSIGN_OR_RETURN(auto result, runner->Run(input.GetGpuBuffer(), matrix,
|
MP_ASSIGN_OR_RETURN(
|
||||||
size, border_mode));
|
auto result,
|
||||||
|
runner->Run(input.GetGpuBuffer(), matrix, size, border_mode));
|
||||||
return mediapipe::Image(*result);
|
return mediapipe::Image(*result);
|
||||||
#else
|
#else
|
||||||
return absl::UnavailableError("GPU support is disabled");
|
return absl::UnavailableError("GPU support is disabled");
|
||||||
#endif // !MEDIAPIPE_DISABLE_GPU
|
#endif // !MEDIAPIPE_DISABLE_GPU
|
||||||
}
|
}
|
||||||
#if !MEDIAPIPE_DISABLE_OPENCV
|
#if !MEDIAPIPE_DISABLE_OPENCV
|
||||||
ASSIGN_OR_RETURN(auto* runner, cpu_holder_.GetRunner());
|
MP_ASSIGN_OR_RETURN(auto* runner, cpu_holder_.GetRunner());
|
||||||
const auto& frame_ptr = input.GetImageFrameSharedPtr();
|
const auto& frame_ptr = input.GetImageFrameSharedPtr();
|
||||||
// Wrap image into image frame.
|
// Wrap image into image frame.
|
||||||
const ImageFrame image_frame(frame_ptr->Format(), frame_ptr->Width(),
|
const ImageFrame image_frame(frame_ptr->Format(), frame_ptr->Width(),
|
||||||
frame_ptr->Height(), frame_ptr->WidthStep(),
|
frame_ptr->Height(), frame_ptr->WidthStep(),
|
||||||
const_cast<uint8_t*>(frame_ptr->PixelData()),
|
const_cast<uint8_t*>(frame_ptr->PixelData()),
|
||||||
[](uint8_t* data){});
|
[](uint8_t* data){});
|
||||||
ASSIGN_OR_RETURN(auto result,
|
MP_ASSIGN_OR_RETURN(auto result,
|
||||||
runner->Run(image_frame, matrix, size, border_mode));
|
runner->Run(image_frame, matrix, size, border_mode));
|
||||||
return mediapipe::Image(std::make_shared<ImageFrame>(std::move(result)));
|
return mediapipe::Image(std::make_shared<ImageFrame>(std::move(result)));
|
||||||
#else
|
#else
|
||||||
return absl::UnavailableError("OpenCV support is disabled");
|
return absl::UnavailableError("OpenCV support is disabled");
|
||||||
@@ -213,8 +215,8 @@ class WarpAffineCalculatorImpl : public mediapipe::api2::NodeImpl<InterfaceT> {
|
|||||||
AffineTransformation::Size output_size;
|
AffineTransformation::Size output_size;
|
||||||
output_size.width = out_width;
|
output_size.width = out_width;
|
||||||
output_size.height = out_height;
|
output_size.height = out_height;
|
||||||
ASSIGN_OR_RETURN(auto* runner, holder_.GetRunner());
|
MP_ASSIGN_OR_RETURN(auto* runner, holder_.GetRunner());
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
auto result,
|
auto result,
|
||||||
runner->Run(
|
runner->Run(
|
||||||
*InterfaceT::kInImage(cc), transform, output_size,
|
*InterfaceT::kInImage(cc), transform, output_size,
|
||||||
|
|||||||
@@ -31,12 +31,14 @@ mediapipe_proto_library(
|
|||||||
cc_library(
|
cc_library(
|
||||||
name = "callback_packet_calculator",
|
name = "callback_packet_calculator",
|
||||||
srcs = ["callback_packet_calculator.cc"],
|
srcs = ["callback_packet_calculator.cc"],
|
||||||
|
hdrs = ["callback_packet_calculator.h"],
|
||||||
visibility = ["//mediapipe/framework:__subpackages__"],
|
visibility = ["//mediapipe/framework:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
":callback_packet_calculator_cc_proto",
|
":callback_packet_calculator_cc_proto",
|
||||||
"//mediapipe/framework:calculator_base",
|
"//mediapipe/framework:calculator_base",
|
||||||
"//mediapipe/framework:calculator_registry",
|
"//mediapipe/framework:calculator_registry",
|
||||||
"//mediapipe/framework:output_side_packet",
|
"//mediapipe/framework:output_side_packet",
|
||||||
|
"@com_google_absl//absl/status",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,10 +11,12 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
#include "mediapipe/calculators/internal/callback_packet_calculator.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/status/status.h"
|
||||||
#include "mediapipe/calculators/internal/callback_packet_calculator.pb.h" // NOLINT
|
#include "mediapipe/calculators/internal/callback_packet_calculator.pb.h" // NOLINT
|
||||||
#include "mediapipe/framework/calculator_base.h"
|
#include "mediapipe/framework/calculator_base.h"
|
||||||
#include "mediapipe/framework/calculator_registry.h"
|
#include "mediapipe/framework/calculator_registry.h"
|
||||||
@@ -39,64 +41,55 @@ void DumpPostStreamPacket(Packet* post_stream_packet, const Packet& packet) {
|
|||||||
*post_stream_packet = packet;
|
*post_stream_packet = packet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Creates a callback which takes a packet and stores it either in a
|
absl::Status CallbackPacketCalculator::GetContract(CalculatorContract* cc) {
|
||||||
// vector of packets or stores only the packet at PostStream timestamp.
|
const auto& options = cc->Options<CallbackPacketCalculatorOptions>();
|
||||||
// The kind of callback is controlled by an option. The callback is
|
switch (options.type()) {
|
||||||
// a std::function and is directly usable by CallbackCalculator.
|
case CallbackPacketCalculatorOptions::VECTOR_PACKET:
|
||||||
// Since the options for the packet generator include a serialized pointer
|
case CallbackPacketCalculatorOptions::POST_STREAM_PACKET:
|
||||||
// value, the resulting callback is only valid on the original machine
|
cc->OutputSidePackets()
|
||||||
// while that pointer is still alive.
|
.Index(0)
|
||||||
class CallbackPacketCalculator : public CalculatorBase {
|
.Set<std::function<void(const Packet&)>>();
|
||||||
public:
|
break;
|
||||||
static absl::Status GetContract(CalculatorContract* cc) {
|
default:
|
||||||
const auto& options = cc->Options<CallbackPacketCalculatorOptions>();
|
|
||||||
switch (options.type()) {
|
|
||||||
case CallbackPacketCalculatorOptions::VECTOR_PACKET:
|
|
||||||
case CallbackPacketCalculatorOptions::POST_STREAM_PACKET:
|
|
||||||
cc->OutputSidePackets()
|
|
||||||
.Index(0)
|
|
||||||
.Set<std::function<void(const Packet&)>>();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
|
|
||||||
<< "Invalid type of callback to produce.";
|
|
||||||
}
|
|
||||||
return absl::OkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
absl::Status Open(CalculatorContext* cc) override {
|
|
||||||
const auto& options = cc->Options<CallbackPacketCalculatorOptions>();
|
|
||||||
void* ptr;
|
|
||||||
if (sscanf(options.pointer().c_str(), "%p", &ptr) != 1) {
|
|
||||||
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
|
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
|
||||||
<< "Stored pointer value in options is invalid.";
|
<< "Invalid type of callback to produce.";
|
||||||
}
|
|
||||||
switch (options.type()) {
|
|
||||||
case CallbackPacketCalculatorOptions::VECTOR_PACKET:
|
|
||||||
cc->OutputSidePackets().Index(0).Set(
|
|
||||||
MakePacket<std::function<void(const Packet&)>>(std::bind(
|
|
||||||
&DumpToVector, reinterpret_cast<std::vector<Packet>*>(ptr),
|
|
||||||
std::placeholders::_1)));
|
|
||||||
break;
|
|
||||||
case CallbackPacketCalculatorOptions::POST_STREAM_PACKET:
|
|
||||||
cc->OutputSidePackets().Index(0).Set(
|
|
||||||
MakePacket<std::function<void(const Packet&)>>(
|
|
||||||
std::bind(&DumpPostStreamPacket, reinterpret_cast<Packet*>(ptr),
|
|
||||||
std::placeholders::_1)));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
|
|
||||||
<< "Invalid type to dump into.";
|
|
||||||
}
|
|
||||||
return absl::OkStatus();
|
|
||||||
}
|
}
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
absl::Status Process(CalculatorContext* cc) override {
|
absl::Status CallbackPacketCalculator::Open(CalculatorContext* cc) {
|
||||||
return absl::OkStatus();
|
const auto& options = cc->Options<CallbackPacketCalculatorOptions>();
|
||||||
|
void* ptr;
|
||||||
|
if (sscanf(options.pointer().c_str(), "%p", &ptr) != 1) {
|
||||||
|
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
|
||||||
|
<< "Stored pointer value in options is invalid.";
|
||||||
}
|
}
|
||||||
};
|
switch (options.type()) {
|
||||||
|
case CallbackPacketCalculatorOptions::VECTOR_PACKET:
|
||||||
|
cc->OutputSidePackets().Index(0).Set(
|
||||||
|
MakePacket<std::function<void(const Packet&)>>(std::bind(
|
||||||
|
&DumpToVector, reinterpret_cast<std::vector<Packet>*>(ptr),
|
||||||
|
std::placeholders::_1)));
|
||||||
|
break;
|
||||||
|
case CallbackPacketCalculatorOptions::POST_STREAM_PACKET:
|
||||||
|
cc->OutputSidePackets().Index(0).Set(
|
||||||
|
MakePacket<std::function<void(const Packet&)>>(
|
||||||
|
std::bind(&DumpPostStreamPacket, reinterpret_cast<Packet*>(ptr),
|
||||||
|
std::placeholders::_1)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
|
||||||
|
<< "Invalid type to dump into.";
|
||||||
|
}
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
absl::Status CallbackPacketCalculator::Process(CalculatorContext* cc) {
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_CALCULATOR(CallbackPacketCalculator);
|
REGISTER_CALCULATOR(CallbackPacketCalculator);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2023 The MediaPipe Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef MEDIAPIPE_CALCULATORS_INTERNAL_CALLBACK_PACKET_CALCULATOR_H_
|
||||||
|
#define MEDIAPIPE_CALCULATORS_INTERNAL_CALLBACK_PACKET_CALCULATOR_H_
|
||||||
|
|
||||||
|
#include "absl/status/status.h"
|
||||||
|
#include "mediapipe/framework/calculator_base.h"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
|
||||||
|
// Creates a callback which takes a packet and stores it either in a
|
||||||
|
// vector of packets or stores only the packet at PostStream timestamp.
|
||||||
|
// The kind of callback is controlled by an option. The callback is
|
||||||
|
// a std::function and is directly usable by CallbackCalculator.
|
||||||
|
// Since the options for the packet generator include a serialized pointer
|
||||||
|
// value, the resulting callback is only valid on the original machine
|
||||||
|
// while that pointer is still alive.
|
||||||
|
class CallbackPacketCalculator : public CalculatorBase {
|
||||||
|
public:
|
||||||
|
static absl::Status GetContract(CalculatorContract* cc);
|
||||||
|
absl::Status Open(CalculatorContext* cc) override;
|
||||||
|
absl::Status Process(CalculatorContext* cc) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mediapipe
|
||||||
|
|
||||||
|
#endif // MEDIAPIPE_CALCULATORS_INTERNAL_CALLBACK_PACKET_CALCULATOR_H_
|
||||||
@@ -87,6 +87,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/util:time_series_util",
|
"//mediapipe/util:time_series_util",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
"@com_google_absl//absl/status",
|
"@com_google_absl//absl/status",
|
||||||
"@com_google_absl//absl/status:statusor",
|
"@com_google_absl//absl/status:statusor",
|
||||||
@@ -181,6 +182,7 @@ cc_library(
|
|||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/api2:node",
|
"//mediapipe/framework/api2:node",
|
||||||
"//mediapipe/framework/formats:tensor",
|
"//mediapipe/framework/formats:tensor",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_absl//absl/status",
|
"@com_google_absl//absl/status",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
@@ -198,6 +200,7 @@ cc_test(
|
|||||||
"//mediapipe/framework/formats:tensor",
|
"//mediapipe/framework/formats:tensor",
|
||||||
"//mediapipe/framework/port:gtest_main",
|
"//mediapipe/framework/port:gtest_main",
|
||||||
"//mediapipe/framework/port:parse_text_proto",
|
"//mediapipe/framework/port:parse_text_proto",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@org_tensorflow//tensorflow/lite/c:common",
|
"@org_tensorflow//tensorflow/lite/c:common",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -445,6 +448,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/deps:file_path",
|
"//mediapipe/framework/deps:file_path",
|
||||||
"//mediapipe/gpu:gl_calculator_helper",
|
"//mediapipe/gpu:gl_calculator_helper",
|
||||||
"//mediapipe/util/tflite:tflite_gpu_runner",
|
"//mediapipe/util/tflite:tflite_gpu_runner",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
"@com_google_absl//absl/status",
|
"@com_google_absl//absl/status",
|
||||||
"@com_google_absl//absl/status:statusor",
|
"@com_google_absl//absl/status:statusor",
|
||||||
@@ -474,6 +478,7 @@ cc_library(
|
|||||||
"//mediapipe/gpu:gpu_buffer",
|
"//mediapipe/gpu:gpu_buffer",
|
||||||
"//mediapipe/objc:mediapipe_framework_ios",
|
"//mediapipe/objc:mediapipe_framework_ios",
|
||||||
"//mediapipe/util/tflite:config",
|
"//mediapipe/util/tflite:config",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
"@com_google_absl//absl/strings:str_format",
|
"@com_google_absl//absl/strings:str_format",
|
||||||
"@org_tensorflow//tensorflow/lite/delegates/gpu:metal_delegate",
|
"@org_tensorflow//tensorflow/lite/delegates/gpu:metal_delegate",
|
||||||
@@ -620,6 +625,7 @@ mediapipe_proto_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//mediapipe/framework:calculator_options_proto",
|
"//mediapipe/framework:calculator_options_proto",
|
||||||
"//mediapipe/framework:calculator_proto",
|
"//mediapipe/framework:calculator_proto",
|
||||||
|
"//mediapipe/gpu:gpu_origin_proto",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -649,7 +655,18 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:matrix",
|
"//mediapipe/framework/formats:matrix",
|
||||||
"//mediapipe/framework/formats:tensor",
|
"//mediapipe/framework/formats:tensor",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
|
"//mediapipe/framework/port:status",
|
||||||
|
"//mediapipe/framework/port:statusor",
|
||||||
|
"//mediapipe/gpu:gpu_buffer_format",
|
||||||
|
"//mediapipe/gpu:gpu_origin_cc_proto",
|
||||||
"//mediapipe/util:resource_util",
|
"//mediapipe/util:resource_util",
|
||||||
|
"@com_google_absl//absl/log",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
|
"@com_google_absl//absl/log:check",
|
||||||
|
"@com_google_absl//absl/status",
|
||||||
|
"@com_google_absl//absl/status:statusor",
|
||||||
|
"@com_google_absl//absl/strings:str_format",
|
||||||
] + select({
|
] + select({
|
||||||
"//mediapipe/gpu:disable_gpu": [],
|
"//mediapipe/gpu:disable_gpu": [],
|
||||||
"//conditions:default": ["tensor_converter_calculator_gpu_deps"],
|
"//conditions:default": ["tensor_converter_calculator_gpu_deps"],
|
||||||
@@ -699,9 +716,11 @@ cc_test(
|
|||||||
"//mediapipe/framework/formats:tensor",
|
"//mediapipe/framework/formats:tensor",
|
||||||
"//mediapipe/framework/port:gtest_main",
|
"//mediapipe/framework/port:gtest_main",
|
||||||
"//mediapipe/framework/port:integral_types",
|
"//mediapipe/framework/port:integral_types",
|
||||||
|
"//mediapipe/framework/port:opencv_core",
|
||||||
"//mediapipe/framework/port:parse_text_proto",
|
"//mediapipe/framework/port:parse_text_proto",
|
||||||
"//mediapipe/framework/tool:validate_type",
|
"//mediapipe/framework/tool:validate_type",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
|
"@com_google_absl//absl/status",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -737,6 +756,8 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:tensor",
|
"//mediapipe/framework/formats:tensor",
|
||||||
"//mediapipe/framework/formats/object_detection:anchor_cc_proto",
|
"//mediapipe/framework/formats/object_detection:anchor_cc_proto",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/strings:str_format",
|
"@com_google_absl//absl/strings:str_format",
|
||||||
"@com_google_absl//absl/types:span",
|
"@com_google_absl//absl/types:span",
|
||||||
] + selects.with_or({
|
] + selects.with_or({
|
||||||
@@ -793,6 +814,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:landmark_cc_proto",
|
"//mediapipe/framework/formats:landmark_cc_proto",
|
||||||
"//mediapipe/framework/formats:tensor",
|
"//mediapipe/framework/formats:tensor",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
@@ -958,6 +980,48 @@ cc_test(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "tensor_to_joints_calculator",
|
||||||
|
srcs = ["tensor_to_joints_calculator.cc"],
|
||||||
|
hdrs = ["tensor_to_joints_calculator.h"],
|
||||||
|
deps = [
|
||||||
|
":tensor_to_joints_calculator_cc_proto",
|
||||||
|
"//mediapipe/framework:calculator_framework",
|
||||||
|
"//mediapipe/framework/api2:node",
|
||||||
|
"//mediapipe/framework/formats:body_rig_cc_proto",
|
||||||
|
"//mediapipe/framework/formats:tensor",
|
||||||
|
"//mediapipe/framework/port:ret_check",
|
||||||
|
"//mediapipe/framework/port:status",
|
||||||
|
],
|
||||||
|
alwayslink = 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
mediapipe_proto_library(
|
||||||
|
name = "tensor_to_joints_calculator_proto",
|
||||||
|
srcs = ["tensor_to_joints_calculator.proto"],
|
||||||
|
deps = [
|
||||||
|
"//mediapipe/framework:calculator_options_proto",
|
||||||
|
"//mediapipe/framework:calculator_proto",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "tensor_to_joints_calculator_test",
|
||||||
|
srcs = ["tensor_to_joints_calculator_test.cc"],
|
||||||
|
deps = [
|
||||||
|
":tensor_to_joints_calculator",
|
||||||
|
":tensor_to_joints_calculator_cc_proto",
|
||||||
|
"//mediapipe/framework:calculator_framework",
|
||||||
|
"//mediapipe/framework:calculator_runner",
|
||||||
|
"//mediapipe/framework:timestamp",
|
||||||
|
"//mediapipe/framework/formats:body_rig_cc_proto",
|
||||||
|
"//mediapipe/framework/formats:tensor",
|
||||||
|
"//mediapipe/framework/port:gtest_main",
|
||||||
|
"//mediapipe/framework/port:parse_text_proto",
|
||||||
|
"@com_google_absl//absl/strings",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "image_to_tensor_calculator",
|
name = "image_to_tensor_calculator",
|
||||||
srcs = ["image_to_tensor_calculator.cc"],
|
srcs = ["image_to_tensor_calculator.cc"],
|
||||||
@@ -985,6 +1049,8 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/port:statusor",
|
"//mediapipe/framework/port:statusor",
|
||||||
"//mediapipe/gpu:gpu_origin_cc_proto",
|
"//mediapipe/gpu:gpu_origin_cc_proto",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
] + select({
|
] + select({
|
||||||
"//mediapipe/gpu:disable_gpu": [],
|
"//mediapipe/gpu:disable_gpu": [],
|
||||||
"//conditions:default": [":image_to_tensor_calculator_gpu_deps"],
|
"//conditions:default": [":image_to_tensor_calculator_gpu_deps"],
|
||||||
@@ -1077,6 +1143,7 @@ cc_test(
|
|||||||
"//mediapipe/framework/port:parse_text_proto",
|
"//mediapipe/framework/port:parse_text_proto",
|
||||||
"//mediapipe/util:image_test_utils",
|
"//mediapipe/util:image_test_utils",
|
||||||
"@com_google_absl//absl/flags:flag",
|
"@com_google_absl//absl/flags:flag",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@com_google_absl//absl/strings:str_format",
|
"@com_google_absl//absl/strings:str_format",
|
||||||
@@ -1204,6 +1271,7 @@ cc_library(
|
|||||||
"//mediapipe/gpu:gl_calculator_helper",
|
"//mediapipe/gpu:gl_calculator_helper",
|
||||||
"//mediapipe/gpu:gl_simple_shaders",
|
"//mediapipe/gpu:gl_simple_shaders",
|
||||||
"//mediapipe/gpu:shader_util",
|
"//mediapipe/gpu:shader_util",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/status/status.h"
|
#include "absl/status/status.h"
|
||||||
#include "absl/status/statusor.h"
|
#include "absl/status/statusor.h"
|
||||||
@@ -348,7 +349,7 @@ absl::Status AudioToTensorCalculator::Process(CalculatorContext* cc) {
|
|||||||
return absl::InvalidArgumentError(
|
return absl::InvalidArgumentError(
|
||||||
"The audio data should be stored in column-major.");
|
"The audio data should be stored in column-major.");
|
||||||
}
|
}
|
||||||
CHECK(channels_match || mono_output);
|
ABSL_CHECK(channels_match || mono_output);
|
||||||
const Matrix& input = channels_match ? input_frame
|
const Matrix& input = channels_match ? input_frame
|
||||||
// Mono mixdown.
|
// Mono mixdown.
|
||||||
: input_frame.colwise().mean();
|
: input_frame.colwise().mean();
|
||||||
@@ -457,7 +458,7 @@ absl::Status AudioToTensorCalculator::SetupStreamingResampler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioToTensorCalculator::AppendZerosToSampleBuffer(int num_samples) {
|
void AudioToTensorCalculator::AppendZerosToSampleBuffer(int num_samples) {
|
||||||
CHECK_GE(num_samples, 0); // Ensured by `UpdateContract`.
|
ABSL_CHECK_GE(num_samples, 0); // Ensured by `UpdateContract`.
|
||||||
if (num_samples == 0) {
|
if (num_samples == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -516,8 +517,8 @@ absl::Status AudioToTensorCalculator::OutputTensor(const Matrix& block,
|
|||||||
// The last two elements are Nyquist component.
|
// The last two elements are Nyquist component.
|
||||||
fft_output_matrix(fft_size_ - 2) = fft_output_[1]; // Nyquist real part
|
fft_output_matrix(fft_size_ - 2) = fft_output_[1]; // Nyquist real part
|
||||||
fft_output_matrix(fft_size_ - 1) = 0.0f; // Nyquist imagery part
|
fft_output_matrix(fft_size_ - 1) = 0.0f; // Nyquist imagery part
|
||||||
ASSIGN_OR_RETURN(output_tensor, ConvertToTensor(fft_output_matrix,
|
MP_ASSIGN_OR_RETURN(output_tensor, ConvertToTensor(fft_output_matrix,
|
||||||
{2, fft_size_ / 2}));
|
{2, fft_size_ / 2}));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Options::WITH_DC_AND_NYQUIST: {
|
case Options::WITH_DC_AND_NYQUIST: {
|
||||||
@@ -528,7 +529,7 @@ absl::Status AudioToTensorCalculator::OutputTensor(const Matrix& block,
|
|||||||
// The last two elements are Nyquist component.
|
// The last two elements are Nyquist component.
|
||||||
fft_output_matrix(fft_size_) = fft_output_[1]; // Nyquist real part
|
fft_output_matrix(fft_size_) = fft_output_[1]; // Nyquist real part
|
||||||
fft_output_matrix(fft_size_ + 1) = 0.0f; // Nyquist imagery part
|
fft_output_matrix(fft_size_ + 1) = 0.0f; // Nyquist imagery part
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
output_tensor,
|
output_tensor,
|
||||||
ConvertToTensor(fft_output_matrix, {2, (fft_size_ + 2) / 2}));
|
ConvertToTensor(fft_output_matrix, {2, (fft_size_ + 2) / 2}));
|
||||||
break;
|
break;
|
||||||
@@ -536,7 +537,7 @@ absl::Status AudioToTensorCalculator::OutputTensor(const Matrix& block,
|
|||||||
case Options::WITHOUT_DC_AND_NYQUIST: {
|
case Options::WITHOUT_DC_AND_NYQUIST: {
|
||||||
Matrix fft_output_matrix =
|
Matrix fft_output_matrix =
|
||||||
Eigen::Map<const Matrix>(fft_output_.data() + 2, 1, fft_size_ - 2);
|
Eigen::Map<const Matrix>(fft_output_.data() + 2, 1, fft_size_ - 2);
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
output_tensor,
|
output_tensor,
|
||||||
ConvertToTensor(fft_output_matrix, {2, (fft_size_ - 2) / 2}));
|
ConvertToTensor(fft_output_matrix, {2, (fft_size_ - 2) / 2}));
|
||||||
break;
|
break;
|
||||||
@@ -546,8 +547,8 @@ absl::Status AudioToTensorCalculator::OutputTensor(const Matrix& block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ASSIGN_OR_RETURN(output_tensor,
|
MP_ASSIGN_OR_RETURN(output_tensor,
|
||||||
ConvertToTensor(block, {num_channels_, num_samples_}));
|
ConvertToTensor(block, {num_channels_, num_samples_}));
|
||||||
}
|
}
|
||||||
kTensorsOut(cc).Send(std::move(output_tensor), timestamp);
|
kTensorsOut(cc).Send(std::move(output_tensor), timestamp);
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
|
|||||||
@@ -161,9 +161,9 @@ absl::Status BertPreprocessorCalculator::Open(CalculatorContext* cc) {
|
|||||||
&kMetadataExtractorSideIn(cc).Get();
|
&kMetadataExtractorSideIn(cc).Get();
|
||||||
const tflite::ProcessUnit* tokenizer_metadata =
|
const tflite::ProcessUnit* tokenizer_metadata =
|
||||||
metadata_extractor->GetInputProcessUnit(kTokenizerProcessUnitIndex);
|
metadata_extractor->GetInputProcessUnit(kTokenizerProcessUnitIndex);
|
||||||
ASSIGN_OR_RETURN(tokenizer_,
|
MP_ASSIGN_OR_RETURN(tokenizer_,
|
||||||
tasks::text::tokenizers::CreateTokenizerFromProcessUnit(
|
tasks::text::tokenizers::CreateTokenizerFromProcessUnit(
|
||||||
tokenizer_metadata, metadata_extractor));
|
tokenizer_metadata, metadata_extractor));
|
||||||
|
|
||||||
auto* input_tensors_metadata = metadata_extractor->GetInputTensorMetadata();
|
auto* input_tensors_metadata = metadata_extractor->GetInputTensorMetadata();
|
||||||
input_ids_tensor_index_ = FindTensorIndexByMetadataName(
|
input_ids_tensor_index_ = FindTensorIndexByMetadataName(
|
||||||
|
|||||||
@@ -67,9 +67,10 @@ absl::StatusOr<std::vector<std::vector<int>>> RunBertPreprocessorCalculator(
|
|||||||
tool::AddVectorSink("tensors", &graph_config, &output_packets);
|
tool::AddVectorSink("tensors", &graph_config, &output_packets);
|
||||||
|
|
||||||
std::string model_buffer = tasks::core::LoadBinaryContent(model_path.data());
|
std::string model_buffer = tasks::core::LoadBinaryContent(model_path.data());
|
||||||
ASSIGN_OR_RETURN(std::unique_ptr<ModelMetadataExtractor> metadata_extractor,
|
MP_ASSIGN_OR_RETURN(
|
||||||
ModelMetadataExtractor::CreateFromModelBuffer(
|
std::unique_ptr<ModelMetadataExtractor> metadata_extractor,
|
||||||
model_buffer.data(), model_buffer.size()));
|
ModelMetadataExtractor::CreateFromModelBuffer(model_buffer.data(),
|
||||||
|
model_buffer.size()));
|
||||||
// Run the graph.
|
// Run the graph.
|
||||||
CalculatorGraph graph;
|
CalculatorGraph graph;
|
||||||
MP_RETURN_IF_ERROR(graph.Initialize(
|
MP_RETURN_IF_ERROR(graph.Initialize(
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "mediapipe/calculators/tensor/feedback_tensors_calculator.pb.h"
|
#include "mediapipe/calculators/tensor/feedback_tensors_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator.pb.h"
|
#include "mediapipe/framework/calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
@@ -65,7 +66,7 @@ template <typename T>
|
|||||||
Tensor MakeTensor(std::initializer_list<int> shape,
|
Tensor MakeTensor(std::initializer_list<int> shape,
|
||||||
std::initializer_list<T> values) {
|
std::initializer_list<T> values) {
|
||||||
Tensor tensor(TensorElementType<T>::value, shape);
|
Tensor tensor(TensorElementType<T>::value, shape);
|
||||||
CHECK_EQ(values.size(), tensor.shape().num_elements())
|
ABSL_CHECK_EQ(values.size(), tensor.shape().num_elements())
|
||||||
<< "The size of `values` is incompatible with `shape`";
|
<< "The size of `values` is incompatible with `shape`";
|
||||||
absl::c_copy(values, tensor.GetCpuWriteView().buffer<T>());
|
absl::c_copy(values, tensor.GetCpuWriteView().buffer<T>());
|
||||||
return tensor;
|
return tensor;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/calculators/tensor/image_to_tensor_calculator.pb.h"
|
#include "mediapipe/calculators/tensor/image_to_tensor_calculator.pb.h"
|
||||||
#include "mediapipe/calculators/tensor/image_to_tensor_converter.h"
|
#include "mediapipe/calculators/tensor/image_to_tensor_converter.h"
|
||||||
#include "mediapipe/calculators/tensor/image_to_tensor_utils.h"
|
#include "mediapipe/calculators/tensor/image_to_tensor_utils.h"
|
||||||
@@ -191,18 +192,19 @@ class ImageToTensorCalculator : public Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if MEDIAPIPE_DISABLE_GPU
|
#if MEDIAPIPE_DISABLE_GPU
|
||||||
ASSIGN_OR_RETURN(auto image, GetInputImage(kIn(cc)));
|
MP_ASSIGN_OR_RETURN(auto image, GetInputImage(kIn(cc)));
|
||||||
#else
|
#else
|
||||||
const bool is_input_gpu = kInGpu(cc).IsConnected();
|
const bool is_input_gpu = kInGpu(cc).IsConnected();
|
||||||
ASSIGN_OR_RETURN(auto image, is_input_gpu ? GetInputImage(kInGpu(cc))
|
MP_ASSIGN_OR_RETURN(auto image, is_input_gpu ? GetInputImage(kInGpu(cc))
|
||||||
: GetInputImage(kIn(cc)));
|
: GetInputImage(kIn(cc)));
|
||||||
#endif // MEDIAPIPE_DISABLE_GPU
|
#endif // MEDIAPIPE_DISABLE_GPU
|
||||||
|
|
||||||
RotatedRect roi = GetRoi(image->width(), image->height(), norm_rect);
|
RotatedRect roi = GetRoi(image->width(), image->height(), norm_rect);
|
||||||
const int tensor_width = params_.output_width.value_or(image->width());
|
const int tensor_width = params_.output_width.value_or(image->width());
|
||||||
const int tensor_height = params_.output_height.value_or(image->height());
|
const int tensor_height = params_.output_height.value_or(image->height());
|
||||||
ASSIGN_OR_RETURN(auto padding, PadRoi(tensor_width, tensor_height,
|
MP_ASSIGN_OR_RETURN(auto padding,
|
||||||
options_.keep_aspect_ratio(), &roi));
|
PadRoi(tensor_width, tensor_height,
|
||||||
|
options_.keep_aspect_ratio(), &roi));
|
||||||
if (kOutLetterboxPadding(cc).IsConnected()) {
|
if (kOutLetterboxPadding(cc).IsConnected()) {
|
||||||
kOutLetterboxPadding(cc).Send(padding);
|
kOutLetterboxPadding(cc).Send(padding);
|
||||||
}
|
}
|
||||||
@@ -246,20 +248,20 @@ class ImageToTensorCalculator : public Node {
|
|||||||
if (!gpu_converter_) {
|
if (!gpu_converter_) {
|
||||||
#if !MEDIAPIPE_DISABLE_GPU
|
#if !MEDIAPIPE_DISABLE_GPU
|
||||||
#if MEDIAPIPE_METAL_ENABLED
|
#if MEDIAPIPE_METAL_ENABLED
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
gpu_converter_,
|
gpu_converter_,
|
||||||
CreateMetalConverter(cc, GetBorderMode(options_.border_mode())));
|
CreateMetalConverter(cc, GetBorderMode(options_.border_mode())));
|
||||||
#elif MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#elif MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
ASSIGN_OR_RETURN(gpu_converter_,
|
MP_ASSIGN_OR_RETURN(gpu_converter_,
|
||||||
CreateImageToGlBufferTensorConverter(
|
CreateImageToGlBufferTensorConverter(
|
||||||
cc, DoesGpuInputStartAtBottom(options_),
|
cc, DoesGpuInputStartAtBottom(options_),
|
||||||
GetBorderMode(options_.border_mode())));
|
GetBorderMode(options_.border_mode())));
|
||||||
#else
|
#else
|
||||||
if (!gpu_converter_) {
|
if (!gpu_converter_) {
|
||||||
ASSIGN_OR_RETURN(gpu_converter_,
|
MP_ASSIGN_OR_RETURN(gpu_converter_,
|
||||||
CreateImageToGlTextureTensorConverter(
|
CreateImageToGlTextureTensorConverter(
|
||||||
cc, DoesGpuInputStartAtBottom(options_),
|
cc, DoesGpuInputStartAtBottom(options_),
|
||||||
GetBorderMode(options_.border_mode())));
|
GetBorderMode(options_.border_mode())));
|
||||||
}
|
}
|
||||||
if (!gpu_converter_) {
|
if (!gpu_converter_) {
|
||||||
return absl::UnimplementedError(
|
return absl::UnimplementedError(
|
||||||
@@ -271,22 +273,24 @@ class ImageToTensorCalculator : public Node {
|
|||||||
} else {
|
} else {
|
||||||
if (!cpu_converter_) {
|
if (!cpu_converter_) {
|
||||||
#if !MEDIAPIPE_DISABLE_OPENCV
|
#if !MEDIAPIPE_DISABLE_OPENCV
|
||||||
ASSIGN_OR_RETURN(cpu_converter_,
|
MP_ASSIGN_OR_RETURN(
|
||||||
CreateOpenCvConverter(
|
cpu_converter_,
|
||||||
cc, GetBorderMode(options_.border_mode()),
|
CreateOpenCvConverter(
|
||||||
GetOutputTensorType(/*uses_gpu=*/false, params_)));
|
cc, GetBorderMode(options_.border_mode()),
|
||||||
|
GetOutputTensorType(/*uses_gpu=*/false, params_)));
|
||||||
// TODO: FrameBuffer-based converter needs to call GetGpuBuffer()
|
// TODO: FrameBuffer-based converter needs to call GetGpuBuffer()
|
||||||
// to get access to a FrameBuffer view. Investigate if GetGpuBuffer() can be
|
// to get access to a FrameBuffer view. Investigate if GetGpuBuffer() can be
|
||||||
// made available even with MEDIAPIPE_DISABLE_GPU set.
|
// made available even with MEDIAPIPE_DISABLE_GPU set.
|
||||||
#elif MEDIAPIPE_ENABLE_HALIDE
|
#elif MEDIAPIPE_ENABLE_HALIDE
|
||||||
ASSIGN_OR_RETURN(cpu_converter_,
|
MP_ASSIGN_OR_RETURN(
|
||||||
CreateFrameBufferConverter(
|
cpu_converter_,
|
||||||
cc, GetBorderMode(options_.border_mode()),
|
CreateFrameBufferConverter(
|
||||||
GetOutputTensorType(/*uses_gpu=*/false, params_)));
|
cc, GetBorderMode(options_.border_mode()),
|
||||||
|
GetOutputTensorType(/*uses_gpu=*/false, params_)));
|
||||||
#else
|
#else
|
||||||
LOG(FATAL) << "Cannot create image to tensor CPU converter since "
|
ABSL_LOG(FATAL) << "Cannot create image to tensor CPU converter since "
|
||||||
"MEDIAPIPE_DISABLE_OPENCV is defined and "
|
"MEDIAPIPE_DISABLE_OPENCV is defined and "
|
||||||
"MEDIAPIPE_ENABLE_HALIDE is not defined.";
|
"MEDIAPIPE_ENABLE_HALIDE is not defined.";
|
||||||
#endif // !MEDIAPIPE_DISABLE_HALIDE
|
#endif // !MEDIAPIPE_DISABLE_HALIDE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/flags/flag.h"
|
#include "absl/flags/flag.h"
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/strings/str_format.h"
|
#include "absl/strings/str_format.h"
|
||||||
#include "absl/strings/substitute.h"
|
#include "absl/strings/substitute.h"
|
||||||
@@ -205,7 +206,7 @@ mediapipe::ImageFormat::Format GetImageFormat(int image_channels) {
|
|||||||
} else if (image_channels == 1) {
|
} else if (image_channels == 1) {
|
||||||
return ImageFormat::GRAY8;
|
return ImageFormat::GRAY8;
|
||||||
}
|
}
|
||||||
CHECK(false) << "Unsupported input image channles: " << image_channels;
|
ABSL_CHECK(false) << "Unsupported input image channles: " << image_channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet MakeImageFramePacket(cv::Mat input) {
|
Packet MakeImageFramePacket(cv::Mat input) {
|
||||||
|
|||||||
@@ -175,9 +175,9 @@ absl::Status FrameBufferProcessor::CropRotateResize90Degrees(
|
|||||||
cropped_buffer_ = std::make_unique<uint8_t[]>(cropped_buffer_size);
|
cropped_buffer_ = std::make_unique<uint8_t[]>(cropped_buffer_size);
|
||||||
cropped_buffer_size_ = cropped_buffer_size;
|
cropped_buffer_size_ = cropped_buffer_size;
|
||||||
}
|
}
|
||||||
ASSIGN_OR_RETURN(cropped,
|
MP_ASSIGN_OR_RETURN(
|
||||||
frame_buffer::CreateFromRawBuffer(
|
cropped, frame_buffer::CreateFromRawBuffer(
|
||||||
cropped_buffer_.get(), cropped_dims, input->format()));
|
cropped_buffer_.get(), cropped_dims, input->format()));
|
||||||
}
|
}
|
||||||
MP_RETURN_IF_ERROR(
|
MP_RETURN_IF_ERROR(
|
||||||
frame_buffer::Crop(*input, left, top, right, bottom, cropped.get()));
|
frame_buffer::Crop(*input, left, top, right, bottom, cropped.get()));
|
||||||
@@ -194,9 +194,9 @@ absl::Status FrameBufferProcessor::CropRotateResize90Degrees(
|
|||||||
rotated_buffer_ = std::make_unique<uint8_t[]>(rotated_buffer_size);
|
rotated_buffer_ = std::make_unique<uint8_t[]>(rotated_buffer_size);
|
||||||
rotated_buffer_size_ = rotated_buffer_size;
|
rotated_buffer_size_ = rotated_buffer_size;
|
||||||
}
|
}
|
||||||
ASSIGN_OR_RETURN(auto rotated, frame_buffer::CreateFromRawBuffer(
|
MP_ASSIGN_OR_RETURN(auto rotated, frame_buffer::CreateFromRawBuffer(
|
||||||
rotated_buffer_.get(), rotated_dims,
|
rotated_buffer_.get(), rotated_dims,
|
||||||
cropped->format()));
|
cropped->format()));
|
||||||
}
|
}
|
||||||
MP_RETURN_IF_ERROR(
|
MP_RETURN_IF_ERROR(
|
||||||
frame_buffer::Rotate(*cropped, rotation_degrees, rotated.get()));
|
frame_buffer::Rotate(*cropped, rotation_degrees, rotated.get()));
|
||||||
@@ -217,9 +217,10 @@ absl::Status FrameBufferProcessor::ConvertToFloatTensor(
|
|||||||
RET_CHECK(output_tensor.element_type() == Tensor::ElementType::kFloat32);
|
RET_CHECK(output_tensor.element_type() == Tensor::ElementType::kFloat32);
|
||||||
constexpr float kInputImageRangeMin = 0.0f;
|
constexpr float kInputImageRangeMin = 0.0f;
|
||||||
constexpr float kInputImageRangeMax = 255.0f;
|
constexpr float kInputImageRangeMax = 255.0f;
|
||||||
ASSIGN_OR_RETURN(auto transform, GetValueRangeTransformation(
|
MP_ASSIGN_OR_RETURN(
|
||||||
kInputImageRangeMin, kInputImageRangeMax,
|
auto transform,
|
||||||
range_min, range_max));
|
GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax,
|
||||||
|
range_min, range_max));
|
||||||
return frame_buffer::ToFloatTensor(*input_frame, transform.scale,
|
return frame_buffer::ToFloatTensor(*input_frame, transform.scale,
|
||||||
transform.offset, output_tensor);
|
transform.offset, output_tensor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ class GlProcessor : public ImageToTensorConverter {
|
|||||||
<< "OpenGL ES 3.1 is required.";
|
<< "OpenGL ES 3.1 is required.";
|
||||||
command_queue_ = tflite::gpu::gl::NewCommandQueue(gpu_info);
|
command_queue_ = tflite::gpu::gl::NewCommandQueue(gpu_info);
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
auto extractor,
|
auto extractor,
|
||||||
SubRectExtractorGl::Create(gl_helper_.GetGlContext(),
|
SubRectExtractorGl::Create(gl_helper_.GetGlContext(),
|
||||||
input_starts_at_bottom, border_mode));
|
input_starts_at_bottom, border_mode));
|
||||||
@@ -293,10 +293,10 @@ class GlProcessor : public ImageToTensorConverter {
|
|||||||
|
|
||||||
constexpr float kInputImageRangeMin = 0.0f;
|
constexpr float kInputImageRangeMin = 0.0f;
|
||||||
constexpr float kInputImageRangeMax = 1.0f;
|
constexpr float kInputImageRangeMax = 1.0f;
|
||||||
ASSIGN_OR_RETURN(auto transform,
|
MP_ASSIGN_OR_RETURN(auto transform,
|
||||||
GetValueRangeTransformation(kInputImageRangeMin,
|
GetValueRangeTransformation(
|
||||||
kInputImageRangeMax,
|
kInputImageRangeMin, kInputImageRangeMax,
|
||||||
range_min, range_max));
|
range_min, range_max));
|
||||||
|
|
||||||
const int output_size = output_tensor.bytes() / output_shape.dims[0];
|
const int output_size = output_tensor.bytes() / output_shape.dims[0];
|
||||||
auto buffer_view = output_tensor.GetOpenGlBufferWriteView();
|
auto buffer_view = output_tensor.GetOpenGlBufferWriteView();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
#include "mediapipe/calculators/tensor/image_to_tensor_converter.h"
|
#include "mediapipe/calculators/tensor/image_to_tensor_converter.h"
|
||||||
#include "mediapipe/calculators/tensor/image_to_tensor_converter_gl_utils.h"
|
#include "mediapipe/calculators/tensor/image_to_tensor_converter_gl_utils.h"
|
||||||
@@ -192,10 +193,10 @@ class GlProcessor : public ImageToTensorConverter {
|
|||||||
|
|
||||||
constexpr float kInputImageRangeMin = 0.0f;
|
constexpr float kInputImageRangeMin = 0.0f;
|
||||||
constexpr float kInputImageRangeMax = 1.0f;
|
constexpr float kInputImageRangeMax = 1.0f;
|
||||||
ASSIGN_OR_RETURN(auto transform,
|
MP_ASSIGN_OR_RETURN(auto transform,
|
||||||
GetValueRangeTransformation(kInputImageRangeMin,
|
GetValueRangeTransformation(
|
||||||
kInputImageRangeMax,
|
kInputImageRangeMin, kInputImageRangeMax,
|
||||||
range_min, range_max));
|
range_min, range_max));
|
||||||
auto tensor_view = output_tensor.GetOpenGlTexture2dWriteView();
|
auto tensor_view = output_tensor.GetOpenGlTexture2dWriteView();
|
||||||
MP_RETURN_IF_ERROR(ExtractSubRect(input_texture, roi,
|
MP_RETURN_IF_ERROR(ExtractSubRect(input_texture, roi,
|
||||||
/*flip_horizontaly=*/false,
|
/*flip_horizontaly=*/false,
|
||||||
@@ -259,7 +260,7 @@ class GlProcessor : public ImageToTensorConverter {
|
|||||||
// error. So in that case, we'll grab the transpose of our original matrix
|
// error. So in that case, we'll grab the transpose of our original matrix
|
||||||
// and send that instead.
|
// and send that instead.
|
||||||
const auto gl_context = mediapipe::GlContext::GetCurrent();
|
const auto gl_context = mediapipe::GlContext::GetCurrent();
|
||||||
LOG_IF(FATAL, !gl_context) << "GlContext is not bound to the thread.";
|
ABSL_LOG_IF(FATAL, !gl_context) << "GlContext is not bound to the thread.";
|
||||||
if (gl_context->GetGlVersion() == mediapipe::GlVersion::kGLES2) {
|
if (gl_context->GetGlVersion() == mediapipe::GlVersion::kGLES2) {
|
||||||
GetTransposedRotatedSubRectToRectTransformMatrix(
|
GetTransposedRotatedSubRectToRectTransformMatrix(
|
||||||
sub_rect, texture.width(), texture.height(), flip_horizontaly,
|
sub_rect, texture.width(), texture.height(), flip_horizontaly,
|
||||||
@@ -303,6 +304,7 @@ class GlProcessor : public ImageToTensorConverter {
|
|||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glFlush();
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -345,9 +345,9 @@ class MetalProcessor : public ImageToTensorConverter {
|
|||||||
absl::Status Init(CalculatorContext* cc, BorderMode border_mode) {
|
absl::Status Init(CalculatorContext* cc, BorderMode border_mode) {
|
||||||
metal_helper_ = [[MPPMetalHelper alloc] initWithCalculatorContext:cc];
|
metal_helper_ = [[MPPMetalHelper alloc] initWithCalculatorContext:cc];
|
||||||
RET_CHECK(metal_helper_);
|
RET_CHECK(metal_helper_);
|
||||||
ASSIGN_OR_RETURN(extractor_, SubRectExtractorMetal::Make(
|
MP_ASSIGN_OR_RETURN(extractor_, SubRectExtractorMetal::Make(
|
||||||
metal_helper_.mtlDevice,
|
metal_helper_.mtlDevice,
|
||||||
OutputFormat::kF32C4, border_mode));
|
OutputFormat::kF32C4, border_mode));
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,7 +373,7 @@ class MetalProcessor : public ImageToTensorConverter {
|
|||||||
|
|
||||||
constexpr float kInputImageRangeMin = 0.0f;
|
constexpr float kInputImageRangeMin = 0.0f;
|
||||||
constexpr float kInputImageRangeMax = 1.0f;
|
constexpr float kInputImageRangeMax = 1.0f;
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
auto transform,
|
auto transform,
|
||||||
GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax,
|
GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax,
|
||||||
range_min, range_max));
|
range_min, range_max));
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ class OpenCvProcessor : public ImageToTensorConverter {
|
|||||||
|
|
||||||
constexpr float kInputImageRangeMin = 0.0f;
|
constexpr float kInputImageRangeMin = 0.0f;
|
||||||
constexpr float kInputImageRangeMax = 255.0f;
|
constexpr float kInputImageRangeMax = 255.0f;
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
auto transform,
|
auto transform,
|
||||||
GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax,
|
GetValueRangeTransformation(kInputImageRangeMin, kInputImageRangeMax,
|
||||||
range_min, range_max));
|
range_min, range_max));
|
||||||
|
|||||||
@@ -88,6 +88,20 @@ message InferenceCalculatorOptions {
|
|||||||
// serialized model is invalid or missing.
|
// serialized model is invalid or missing.
|
||||||
optional string serialized_model_dir = 7;
|
optional string serialized_model_dir = 7;
|
||||||
|
|
||||||
|
enum CacheWritingBehavior {
|
||||||
|
// Do not write any caches.
|
||||||
|
NO_WRITE = 0;
|
||||||
|
|
||||||
|
// Try to write caches, log on failure.
|
||||||
|
TRY_WRITE = 1;
|
||||||
|
|
||||||
|
// Write caches or return an error if write fails.
|
||||||
|
WRITE_OR_ERROR = 2;
|
||||||
|
}
|
||||||
|
// Specifies how GPU caches are written to disk.
|
||||||
|
optional CacheWritingBehavior cache_writing_behavior = 10
|
||||||
|
[default = WRITE_OR_ERROR];
|
||||||
|
|
||||||
// Unique token identifying the model. Used in conjunction with
|
// Unique token identifying the model. Used in conjunction with
|
||||||
// "serialized_model_dir". It is the caller's responsibility to ensure
|
// "serialized_model_dir". It is the caller's responsibility to ensure
|
||||||
// there is no clash of the tokens.
|
// there is no clash of the tokens.
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ absl::Status InferenceCalculatorCpuImpl::UpdateContract(
|
|||||||
}
|
}
|
||||||
|
|
||||||
absl::Status InferenceCalculatorCpuImpl::Open(CalculatorContext* cc) {
|
absl::Status InferenceCalculatorCpuImpl::Open(CalculatorContext* cc) {
|
||||||
ASSIGN_OR_RETURN(inference_runner_, CreateInferenceRunner(cc));
|
MP_ASSIGN_OR_RETURN(inference_runner_, CreateInferenceRunner(cc));
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,8 +71,8 @@ absl::Status InferenceCalculatorCpuImpl::Process(CalculatorContext* cc) {
|
|||||||
const auto& input_tensors = *kInTensors(cc);
|
const auto& input_tensors = *kInTensors(cc);
|
||||||
RET_CHECK(!input_tensors.empty());
|
RET_CHECK(!input_tensors.empty());
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(std::vector<Tensor> output_tensors,
|
MP_ASSIGN_OR_RETURN(std::vector<Tensor> output_tensors,
|
||||||
inference_runner_->Run(cc, input_tensors));
|
inference_runner_->Run(cc, input_tensors));
|
||||||
kOutTensors(cc).Send(std::move(output_tensors));
|
kOutTensors(cc).Send(std::move(output_tensors));
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
@@ -84,11 +84,11 @@ absl::Status InferenceCalculatorCpuImpl::Close(CalculatorContext* cc) {
|
|||||||
|
|
||||||
absl::StatusOr<std::unique_ptr<InferenceRunner>>
|
absl::StatusOr<std::unique_ptr<InferenceRunner>>
|
||||||
InferenceCalculatorCpuImpl::CreateInferenceRunner(CalculatorContext* cc) {
|
InferenceCalculatorCpuImpl::CreateInferenceRunner(CalculatorContext* cc) {
|
||||||
ASSIGN_OR_RETURN(auto model_packet, GetModelAsPacket(cc));
|
MP_ASSIGN_OR_RETURN(auto model_packet, GetModelAsPacket(cc));
|
||||||
ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc));
|
MP_ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc));
|
||||||
const int interpreter_num_threads =
|
const int interpreter_num_threads =
|
||||||
cc->Options<mediapipe::InferenceCalculatorOptions>().cpu_num_thread();
|
cc->Options<mediapipe::InferenceCalculatorOptions>().cpu_num_thread();
|
||||||
ASSIGN_OR_RETURN(TfLiteDelegatePtr delegate, MaybeCreateDelegate(cc));
|
MP_ASSIGN_OR_RETURN(TfLiteDelegatePtr delegate, MaybeCreateDelegate(cc));
|
||||||
return CreateInferenceInterpreterDelegateRunner(
|
return CreateInferenceInterpreterDelegateRunner(
|
||||||
std::move(model_packet), std::move(op_resolver_packet),
|
std::move(model_packet), std::move(op_resolver_packet),
|
||||||
std::move(delegate), interpreter_num_threads);
|
std::move(delegate), interpreter_num_threads);
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ absl::Status InferenceCalculatorGlImpl::GpuInferenceRunner::Init(
|
|||||||
|
|
||||||
absl::Status InferenceCalculatorGlImpl::GpuInferenceRunner::LoadModel(
|
absl::Status InferenceCalculatorGlImpl::GpuInferenceRunner::LoadModel(
|
||||||
CalculatorContext* cc) {
|
CalculatorContext* cc) {
|
||||||
ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc));
|
MP_ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc));
|
||||||
const auto& model = *model_packet_.Get();
|
const auto& model = *model_packet_.Get();
|
||||||
if (kSideInOpResolver(cc).IsConnected()) {
|
if (kSideInOpResolver(cc).IsConnected()) {
|
||||||
const tflite::OpResolver& op_resolver = kSideInOpResolver(cc).Get();
|
const tflite::OpResolver& op_resolver = kSideInOpResolver(cc).Get();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
#include "mediapipe/util/tflite/tflite_gpu_runner.h"
|
#include "mediapipe/util/tflite/tflite_gpu_runner.h"
|
||||||
|
|
||||||
#if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS)
|
#if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS)
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/framework/deps/file_path.h"
|
#include "mediapipe/framework/deps/file_path.h"
|
||||||
#include "mediapipe/util/android/file/base/file.h"
|
#include "mediapipe/util/android/file/base/file.h"
|
||||||
#include "mediapipe/util/android/file/base/filesystem.h"
|
#include "mediapipe/util/android/file/base/filesystem.h"
|
||||||
@@ -68,14 +70,21 @@ class InferenceCalculatorGlAdvancedImpl
|
|||||||
const mediapipe::InferenceCalculatorOptions::Delegate::Gpu&
|
const mediapipe::InferenceCalculatorOptions::Delegate::Gpu&
|
||||||
gpu_delegate_options);
|
gpu_delegate_options);
|
||||||
absl::Status ReadGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const;
|
absl::Status ReadGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const;
|
||||||
absl::Status SaveGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const;
|
// Writes caches to disk based on |cache_writing_behavior_|.
|
||||||
|
absl::Status SaveGpuCachesBasedOnBehavior(
|
||||||
|
tflite::gpu::TFLiteGPURunner* gpu_runner) const;
|
||||||
bool UseSerializedModel() const { return use_serialized_model_; }
|
bool UseSerializedModel() const { return use_serialized_model_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Writes caches to disk, returns error on failure.
|
||||||
|
absl::Status SaveGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const;
|
||||||
|
|
||||||
bool use_kernel_caching_ = false;
|
bool use_kernel_caching_ = false;
|
||||||
std::string cached_kernel_filename_;
|
std::string cached_kernel_filename_;
|
||||||
bool use_serialized_model_ = false;
|
bool use_serialized_model_ = false;
|
||||||
std::string serialized_model_path_;
|
std::string serialized_model_path_;
|
||||||
|
mediapipe::InferenceCalculatorOptions::Delegate::Gpu::CacheWritingBehavior
|
||||||
|
cache_writing_behavior_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper class that wraps everything related to GPU inference acceleration.
|
// Helper class that wraps everything related to GPU inference acceleration.
|
||||||
@@ -161,7 +170,7 @@ absl::Status
|
|||||||
InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::InitTFLiteGPURunner(
|
InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::InitTFLiteGPURunner(
|
||||||
CalculatorContext* cc,
|
CalculatorContext* cc,
|
||||||
const mediapipe::InferenceCalculatorOptions::Delegate& delegate) {
|
const mediapipe::InferenceCalculatorOptions::Delegate& delegate) {
|
||||||
ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc));
|
MP_ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc));
|
||||||
const auto& model = *model_packet_.Get();
|
const auto& model = *model_packet_.Get();
|
||||||
|
|
||||||
bool allow_precision_loss = delegate.gpu().allow_precision_loss();
|
bool allow_precision_loss = delegate.gpu().allow_precision_loss();
|
||||||
@@ -232,7 +241,8 @@ InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::InitTFLiteGPURunner(
|
|||||||
MP_RETURN_IF_ERROR(
|
MP_RETURN_IF_ERROR(
|
||||||
on_disk_cache_helper_.ReadGpuCaches(tflite_gpu_runner_.get()));
|
on_disk_cache_helper_.ReadGpuCaches(tflite_gpu_runner_.get()));
|
||||||
MP_RETURN_IF_ERROR(tflite_gpu_runner_->Build());
|
MP_RETURN_IF_ERROR(tflite_gpu_runner_->Build());
|
||||||
return on_disk_cache_helper_.SaveGpuCaches(tflite_gpu_runner_.get());
|
return on_disk_cache_helper_.SaveGpuCachesBasedOnBehavior(
|
||||||
|
tflite_gpu_runner_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS)
|
#if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS)
|
||||||
@@ -261,24 +271,51 @@ absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::Init(
|
|||||||
mediapipe::file::JoinPath(gpu_delegate_options.serialized_model_dir(),
|
mediapipe::file::JoinPath(gpu_delegate_options.serialized_model_dir(),
|
||||||
gpu_delegate_options.model_token());
|
gpu_delegate_options.model_token());
|
||||||
}
|
}
|
||||||
|
cache_writing_behavior_ = gpu_delegate_options.has_cache_writing_behavior()
|
||||||
|
? gpu_delegate_options.cache_writing_behavior()
|
||||||
|
: mediapipe::InferenceCalculatorOptions::
|
||||||
|
Delegate::Gpu::WRITE_OR_ERROR;
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::
|
||||||
|
SaveGpuCachesBasedOnBehavior(
|
||||||
|
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
|
||||||
|
switch (cache_writing_behavior_) {
|
||||||
|
case mediapipe::InferenceCalculatorOptions::Delegate::Gpu::NO_WRITE:
|
||||||
|
return absl::OkStatus();
|
||||||
|
case mediapipe::InferenceCalculatorOptions::Delegate::Gpu::TRY_WRITE: {
|
||||||
|
auto status = SaveGpuCaches(gpu_runner);
|
||||||
|
if (!status.ok()) {
|
||||||
|
ABSL_LOG_FIRST_N(WARNING, 1) << "Failed to save gpu caches: " << status;
|
||||||
|
}
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
case mediapipe::InferenceCalculatorOptions::Delegate::Gpu::WRITE_OR_ERROR:
|
||||||
|
return SaveGpuCaches(gpu_runner);
|
||||||
|
default:
|
||||||
|
ABSL_LOG_FIRST_N(ERROR, 1)
|
||||||
|
<< "Unknown cache writing behavior: "
|
||||||
|
<< static_cast<uint32_t>(cache_writing_behavior_);
|
||||||
|
return absl::InvalidArgumentError("Unknown cache writing behavior.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
absl::Status
|
absl::Status
|
||||||
InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::SaveGpuCaches(
|
InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::SaveGpuCaches(
|
||||||
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
|
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
|
||||||
if (use_kernel_caching_) {
|
if (use_kernel_caching_) {
|
||||||
// Save kernel file.
|
// Save kernel file.
|
||||||
ASSIGN_OR_RETURN(std::vector<uint8_t> kernel_cache,
|
MP_ASSIGN_OR_RETURN(std::vector<uint8_t> kernel_cache,
|
||||||
gpu_runner->GetSerializedBinaryCache());
|
gpu_runner->GetSerializedBinaryCache());
|
||||||
std::string cache_str(kernel_cache.begin(), kernel_cache.end());
|
std::string cache_str(kernel_cache.begin(), kernel_cache.end());
|
||||||
MP_RETURN_IF_ERROR(
|
MP_RETURN_IF_ERROR(
|
||||||
mediapipe::file::SetContents(cached_kernel_filename_, cache_str));
|
mediapipe::file::SetContents(cached_kernel_filename_, cache_str));
|
||||||
}
|
}
|
||||||
if (use_serialized_model_) {
|
if (use_serialized_model_) {
|
||||||
// Save serialized model file.
|
// Save serialized model file.
|
||||||
ASSIGN_OR_RETURN(std::vector<uint8_t> serialized_model_vec,
|
MP_ASSIGN_OR_RETURN(std::vector<uint8_t> serialized_model_vec,
|
||||||
gpu_runner->GetSerializedModel());
|
gpu_runner->GetSerializedModel());
|
||||||
absl::string_view serialized_model(
|
absl::string_view serialized_model(
|
||||||
reinterpret_cast<char*>(serialized_model_vec.data()),
|
reinterpret_cast<char*>(serialized_model_vec.data()),
|
||||||
serialized_model_vec.size());
|
serialized_model_vec.size());
|
||||||
@@ -318,6 +355,12 @@ absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::Init(
|
|||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::Status InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::
|
||||||
|
SaveGpuCachesBasedOnBehavior(
|
||||||
|
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
absl::Status
|
absl::Status
|
||||||
InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::ReadGpuCaches(
|
InferenceCalculatorGlAdvancedImpl::OnDiskCacheHelper::ReadGpuCaches(
|
||||||
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
|
tflite::gpu::TFLiteGPURunner* gpu_runner) const {
|
||||||
@@ -369,8 +412,8 @@ absl::Status InferenceCalculatorGlAdvancedImpl::Process(CalculatorContext* cc) {
|
|||||||
RET_CHECK(!input_tensors.empty());
|
RET_CHECK(!input_tensors.empty());
|
||||||
auto output_tensors = absl::make_unique<std::vector<Tensor>>();
|
auto output_tensors = absl::make_unique<std::vector<Tensor>>();
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(*output_tensors,
|
MP_ASSIGN_OR_RETURN(*output_tensors,
|
||||||
gpu_inference_runner_->Process(cc, input_tensors));
|
gpu_inference_runner_->Process(cc, input_tensors));
|
||||||
|
|
||||||
kOutTensors(cc).Send(std::move(output_tensors));
|
kOutTensors(cc).Send(std::move(output_tensors));
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/strings/str_format.h"
|
#include "absl/strings/str_format.h"
|
||||||
#include "mediapipe/calculators/tensor/inference_calculator.h"
|
#include "mediapipe/calculators/tensor/inference_calculator.h"
|
||||||
@@ -74,7 +75,7 @@ tflite::gpu::BHWC BhwcFromTensorShape(const Tensor::Shape& shape) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Handles 0 and >4.
|
// Handles 0 and >4.
|
||||||
LOG(FATAL)
|
ABSL_LOG(FATAL)
|
||||||
<< "Dimensions size must be in range [1,4] for GPU inference, but "
|
<< "Dimensions size must be in range [1,4] for GPU inference, but "
|
||||||
<< shape.dims.size() << " is provided";
|
<< shape.dims.size() << " is provided";
|
||||||
}
|
}
|
||||||
@@ -207,9 +208,9 @@ absl::Status InferenceCalculatorMetalImpl::Close(CalculatorContext* cc) {
|
|||||||
|
|
||||||
absl::Status InferenceCalculatorMetalImpl::InitInterpreter(
|
absl::Status InferenceCalculatorMetalImpl::InitInterpreter(
|
||||||
CalculatorContext* cc) {
|
CalculatorContext* cc) {
|
||||||
ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc));
|
MP_ASSIGN_OR_RETURN(model_packet_, GetModelAsPacket(cc));
|
||||||
const auto& model = *model_packet_.Get();
|
const auto& model = *model_packet_.Get();
|
||||||
ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc));
|
MP_ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc));
|
||||||
const auto& op_resolver = op_resolver_packet.Get();
|
const auto& op_resolver = op_resolver_packet.Get();
|
||||||
tflite::InterpreterBuilder interpreter_builder(model, op_resolver);
|
tflite::InterpreterBuilder interpreter_builder(model, op_resolver);
|
||||||
AddDelegate(cc, &interpreter_builder);
|
AddDelegate(cc, &interpreter_builder);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/log/check.h"
|
#include "absl/log/absl_check.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
#include "absl/strings/str_replace.h"
|
#include "absl/strings/str_replace.h"
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ absl::Status InferenceCalculatorXnnpackImpl::UpdateContract(
|
|||||||
}
|
}
|
||||||
|
|
||||||
absl::Status InferenceCalculatorXnnpackImpl::Open(CalculatorContext* cc) {
|
absl::Status InferenceCalculatorXnnpackImpl::Open(CalculatorContext* cc) {
|
||||||
ASSIGN_OR_RETURN(inference_runner_, CreateInferenceRunner(cc));
|
MP_ASSIGN_OR_RETURN(inference_runner_, CreateInferenceRunner(cc));
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,8 +69,8 @@ absl::Status InferenceCalculatorXnnpackImpl::Process(CalculatorContext* cc) {
|
|||||||
const auto& input_tensors = *kInTensors(cc);
|
const auto& input_tensors = *kInTensors(cc);
|
||||||
RET_CHECK(!input_tensors.empty());
|
RET_CHECK(!input_tensors.empty());
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(std::vector<Tensor> output_tensors,
|
MP_ASSIGN_OR_RETURN(std::vector<Tensor> output_tensors,
|
||||||
inference_runner_->Run(cc, input_tensors));
|
inference_runner_->Run(cc, input_tensors));
|
||||||
kOutTensors(cc).Send(std::move(output_tensors));
|
kOutTensors(cc).Send(std::move(output_tensors));
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
@@ -82,11 +82,11 @@ absl::Status InferenceCalculatorXnnpackImpl::Close(CalculatorContext* cc) {
|
|||||||
|
|
||||||
absl::StatusOr<std::unique_ptr<InferenceRunner>>
|
absl::StatusOr<std::unique_ptr<InferenceRunner>>
|
||||||
InferenceCalculatorXnnpackImpl::CreateInferenceRunner(CalculatorContext* cc) {
|
InferenceCalculatorXnnpackImpl::CreateInferenceRunner(CalculatorContext* cc) {
|
||||||
ASSIGN_OR_RETURN(auto model_packet, GetModelAsPacket(cc));
|
MP_ASSIGN_OR_RETURN(auto model_packet, GetModelAsPacket(cc));
|
||||||
ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc));
|
MP_ASSIGN_OR_RETURN(auto op_resolver_packet, GetOpResolverAsPacket(cc));
|
||||||
const int interpreter_num_threads =
|
const int interpreter_num_threads =
|
||||||
cc->Options<mediapipe::InferenceCalculatorOptions>().cpu_num_thread();
|
cc->Options<mediapipe::InferenceCalculatorOptions>().cpu_num_thread();
|
||||||
ASSIGN_OR_RETURN(TfLiteDelegatePtr delegate, CreateDelegate(cc));
|
MP_ASSIGN_OR_RETURN(TfLiteDelegatePtr delegate, CreateDelegate(cc));
|
||||||
return CreateInferenceInterpreterDelegateRunner(
|
return CreateInferenceInterpreterDelegateRunner(
|
||||||
std::move(model_packet), std::move(op_resolver_packet),
|
std::move(model_packet), std::move(op_resolver_packet),
|
||||||
std::move(delegate), interpreter_num_threads);
|
std::move(delegate), interpreter_num_threads);
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ absl::Status RegexPreprocessorCalculator::Open(CalculatorContext* cc) {
|
|||||||
return absl::InvalidArgumentError("No tensor metadata found");
|
return absl::InvalidArgumentError("No tensor metadata found");
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
const auto* tokenizer_metadata,
|
const auto* tokenizer_metadata,
|
||||||
metadata_extractor->FindFirstProcessUnit(
|
metadata_extractor->FindFirstProcessUnit(
|
||||||
*tensor_metadata, tflite::ProcessUnitOptions_RegexTokenizerOptions));
|
*tensor_metadata, tflite::ProcessUnitOptions_RegexTokenizerOptions));
|
||||||
@@ -115,9 +115,9 @@ absl::Status RegexPreprocessorCalculator::Open(CalculatorContext* cc) {
|
|||||||
}
|
}
|
||||||
const tflite::RegexTokenizerOptions* regex_tokenizer_options =
|
const tflite::RegexTokenizerOptions* regex_tokenizer_options =
|
||||||
tokenizer_metadata->options_as<tflite::RegexTokenizerOptions>();
|
tokenizer_metadata->options_as<tflite::RegexTokenizerOptions>();
|
||||||
ASSIGN_OR_RETURN(tokenizer_,
|
MP_ASSIGN_OR_RETURN(tokenizer_,
|
||||||
tasks::text::tokenizers::CreateRegexTokenizerFromOptions(
|
tasks::text::tokenizers::CreateRegexTokenizerFromOptions(
|
||||||
regex_tokenizer_options, metadata_extractor));
|
regex_tokenizer_options, metadata_extractor));
|
||||||
|
|
||||||
const auto& options =
|
const auto& options =
|
||||||
cc->Options<mediapipe::RegexPreprocessorCalculatorOptions>();
|
cc->Options<mediapipe::RegexPreprocessorCalculatorOptions>();
|
||||||
|
|||||||
@@ -67,9 +67,10 @@ absl::StatusOr<std::vector<int>> RunRegexPreprocessorCalculator(
|
|||||||
tool::AddVectorSink("tensors", &graph_config, &output_packets);
|
tool::AddVectorSink("tensors", &graph_config, &output_packets);
|
||||||
|
|
||||||
std::string model_buffer = tasks::core::LoadBinaryContent(kTestModelPath);
|
std::string model_buffer = tasks::core::LoadBinaryContent(kTestModelPath);
|
||||||
ASSIGN_OR_RETURN(std::unique_ptr<ModelMetadataExtractor> metadata_extractor,
|
MP_ASSIGN_OR_RETURN(
|
||||||
ModelMetadataExtractor::CreateFromModelBuffer(
|
std::unique_ptr<ModelMetadataExtractor> metadata_extractor,
|
||||||
model_buffer.data(), model_buffer.size()));
|
ModelMetadataExtractor::CreateFromModelBuffer(model_buffer.data(),
|
||||||
|
model_buffer.size()));
|
||||||
// Run the graph.
|
// Run the graph.
|
||||||
CalculatorGraph graph;
|
CalculatorGraph graph;
|
||||||
MP_RETURN_IF_ERROR(graph.Initialize(
|
MP_RETURN_IF_ERROR(graph.Initialize(
|
||||||
|
|||||||
@@ -12,9 +12,15 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
|
#include "absl/status/status.h"
|
||||||
|
#include "absl/status/statusor.h"
|
||||||
|
#include "absl/strings/str_format.h"
|
||||||
#include "mediapipe/calculators/tensor/tensor_converter_calculator.pb.h"
|
#include "mediapipe/calculators/tensor/tensor_converter_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/formats/image_frame.h"
|
#include "mediapipe/framework/formats/image_frame.h"
|
||||||
@@ -22,7 +28,8 @@
|
|||||||
#include "mediapipe/framework/formats/tensor.h"
|
#include "mediapipe/framework/formats/tensor.h"
|
||||||
#include "mediapipe/framework/port.h"
|
#include "mediapipe/framework/port.h"
|
||||||
#include "mediapipe/framework/port/ret_check.h"
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
#include "mediapipe/util/resource_util.h"
|
#include "mediapipe/gpu/gpu_buffer_format.h"
|
||||||
|
#include "mediapipe/gpu/gpu_origin.pb.h"
|
||||||
|
|
||||||
#if !MEDIAPIPE_DISABLE_GPU
|
#if !MEDIAPIPE_DISABLE_GPU
|
||||||
#include "mediapipe/gpu/gpu_buffer.h"
|
#include "mediapipe/gpu/gpu_buffer.h"
|
||||||
@@ -43,12 +50,50 @@
|
|||||||
#endif // !MEDIAPIPE_DISABLE_GPU
|
#endif // !MEDIAPIPE_DISABLE_GPU
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr int kWorkgroupSize = 8; // Block size for GPU shader.
|
constexpr int kWorkgroupSize = 8; // Block size for GPU shader.
|
||||||
// Commonly used to compute the number of blocks to launch in a kernel.
|
// Commonly used to compute the number of blocks to launch in a kernel.
|
||||||
int NumGroups(const int size, const int group_size) { // NOLINT
|
int NumGroups(const int size, const int group_size) { // NOLINT
|
||||||
return (size + group_size - 1) / group_size;
|
return (size + group_size - 1) / group_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::StatusOr<bool> ShouldFlipVertically(
|
||||||
|
const mediapipe::TensorConverterCalculatorOptions& options, bool use_gpu) {
|
||||||
|
if (options.has_flip_vertically() && options.has_gpu_origin()) {
|
||||||
|
return absl::FailedPreconditionError(absl::StrFormat(
|
||||||
|
"Cannot specify both flip_vertically and gpu_origin options"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.has_gpu_origin()) {
|
||||||
|
// Fall back to flip_vertically.
|
||||||
|
return options.flip_vertically();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn if gpu_origin is specified with a CPU input image.
|
||||||
|
// Those are always TOP_LEFT, so no flipping is necessary.
|
||||||
|
if (!use_gpu) {
|
||||||
|
ABSL_LOG(WARNING)
|
||||||
|
<< "Ignoring gpu_origin option since IMAGE_GPU input is not specified";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (options.gpu_origin()) {
|
||||||
|
case mediapipe::GpuOrigin::TOP_LEFT:
|
||||||
|
return false;
|
||||||
|
case mediapipe::GpuOrigin::DEFAULT:
|
||||||
|
case mediapipe::GpuOrigin::CONVENTIONAL:
|
||||||
|
// TOP_LEFT on Metal, BOTTOM_LEFT on OpenGL.
|
||||||
|
#ifdef __APPLE__
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return absl::InvalidArgumentError(
|
||||||
|
absl::StrFormat("Unhandled GPU origin %i", options.gpu_origin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
|
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
|
||||||
RowMajorMatrixXf;
|
RowMajorMatrixXf;
|
||||||
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>
|
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>
|
||||||
@@ -58,6 +103,7 @@ constexpr char kImageFrameTag[] = "IMAGE";
|
|||||||
constexpr char kGpuBufferTag[] = "IMAGE_GPU";
|
constexpr char kGpuBufferTag[] = "IMAGE_GPU";
|
||||||
constexpr char kTensorsTag[] = "TENSORS";
|
constexpr char kTensorsTag[] = "TENSORS";
|
||||||
constexpr char kMatrixTag[] = "MATRIX";
|
constexpr char kMatrixTag[] = "MATRIX";
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace mediapipe {
|
namespace mediapipe {
|
||||||
@@ -109,7 +155,7 @@ class TensorConverterCalculator : public CalculatorBase {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
absl::Status InitGpu(CalculatorContext* cc);
|
absl::Status InitGpu(CalculatorContext* cc);
|
||||||
absl::Status LoadOptions(CalculatorContext* cc);
|
absl::Status LoadOptions(CalculatorContext* cc, bool use_gpu);
|
||||||
template <class T>
|
template <class T>
|
||||||
absl::Status NormalizeImage(const ImageFrame& image_frame,
|
absl::Status NormalizeImage(const ImageFrame& image_frame,
|
||||||
bool flip_vertically, float* tensor_ptr);
|
bool flip_vertically, float* tensor_ptr);
|
||||||
@@ -145,7 +191,8 @@ absl::Status TensorConverterCalculator::GetContract(CalculatorContract* cc) {
|
|||||||
RET_CHECK(static_cast<int>(cc->Inputs().HasTag(kImageFrameTag)) +
|
RET_CHECK(static_cast<int>(cc->Inputs().HasTag(kImageFrameTag)) +
|
||||||
static_cast<int>(cc->Inputs().HasTag(kGpuBufferTag)) +
|
static_cast<int>(cc->Inputs().HasTag(kGpuBufferTag)) +
|
||||||
static_cast<int>(cc->Inputs().HasTag(kMatrixTag)) ==
|
static_cast<int>(cc->Inputs().HasTag(kMatrixTag)) ==
|
||||||
1);
|
1)
|
||||||
|
<< "Only one input tag of {IMAGE, IMAGE_GPU, MATRIX} may be specified";
|
||||||
|
|
||||||
if (cc->Inputs().HasTag(kImageFrameTag)) {
|
if (cc->Inputs().HasTag(kImageFrameTag)) {
|
||||||
cc->Inputs().Tag(kImageFrameTag).Set<ImageFrame>();
|
cc->Inputs().Tag(kImageFrameTag).Set<ImageFrame>();
|
||||||
@@ -173,8 +220,6 @@ absl::Status TensorConverterCalculator::GetContract(CalculatorContract* cc) {
|
|||||||
absl::Status TensorConverterCalculator::Open(CalculatorContext* cc) {
|
absl::Status TensorConverterCalculator::Open(CalculatorContext* cc) {
|
||||||
cc->SetOffset(TimestampDiff(0));
|
cc->SetOffset(TimestampDiff(0));
|
||||||
|
|
||||||
MP_RETURN_IF_ERROR(LoadOptions(cc));
|
|
||||||
|
|
||||||
#if !MEDIAPIPE_DISABLE_GPU
|
#if !MEDIAPIPE_DISABLE_GPU
|
||||||
if (cc->Inputs().HasTag(kGpuBufferTag)) {
|
if (cc->Inputs().HasTag(kGpuBufferTag)) {
|
||||||
use_gpu_ = true;
|
use_gpu_ = true;
|
||||||
@@ -187,6 +232,8 @@ absl::Status TensorConverterCalculator::Open(CalculatorContext* cc) {
|
|||||||
}
|
}
|
||||||
#endif // !MEDIAPIPE_DISABLE_GPU
|
#endif // !MEDIAPIPE_DISABLE_GPU
|
||||||
|
|
||||||
|
MP_RETURN_IF_ERROR(LoadOptions(cc, use_gpu_));
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,6 +406,7 @@ absl::Status TensorConverterCalculator::ProcessGPU(CalculatorContext* cc) {
|
|||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
|
glFlush();
|
||||||
src.Release();
|
src.Release();
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}));
|
}));
|
||||||
@@ -378,23 +426,34 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
|
|||||||
// Get input image sizes.
|
// Get input image sizes.
|
||||||
const auto& input =
|
const auto& input =
|
||||||
cc->Inputs().Tag(kGpuBufferTag).Get<mediapipe::GpuBuffer>();
|
cc->Inputs().Tag(kGpuBufferTag).Get<mediapipe::GpuBuffer>();
|
||||||
mediapipe::ImageFormat::Format format =
|
mediapipe::GpuBufferFormat format = input.format();
|
||||||
mediapipe::ImageFormatForGpuBufferFormat(input.format());
|
|
||||||
const bool include_alpha = (max_num_channels_ == 4);
|
const bool include_alpha = (max_num_channels_ == 4);
|
||||||
const bool single_channel = (max_num_channels_ == 1);
|
const bool single_channel = (max_num_channels_ == 1);
|
||||||
if (!(format == mediapipe::ImageFormat::GRAY8 ||
|
|
||||||
format == mediapipe::ImageFormat::SRGB ||
|
RET_CHECK(format == mediapipe::GpuBufferFormat::kBGRA32 ||
|
||||||
format == mediapipe::ImageFormat::SRGBA))
|
format == mediapipe::GpuBufferFormat::kRGB24 ||
|
||||||
RET_CHECK_FAIL() << "Unsupported GPU input format.";
|
format == mediapipe::GpuBufferFormat::kRGBA32 ||
|
||||||
if (include_alpha && (format != mediapipe::ImageFormat::SRGBA))
|
format == mediapipe::GpuBufferFormat::kRGBAFloat128 ||
|
||||||
RET_CHECK_FAIL() << "Num input channels is less than desired output.";
|
format == mediapipe::GpuBufferFormat::kRGBAHalf64 ||
|
||||||
|
format == mediapipe::GpuBufferFormat::kGrayFloat32 ||
|
||||||
|
format == mediapipe::GpuBufferFormat::kGrayHalf16 ||
|
||||||
|
format == mediapipe::GpuBufferFormat::kOneComponent8)
|
||||||
|
<< "Unsupported GPU input format: " << static_cast<uint32_t>(format);
|
||||||
|
if (include_alpha) {
|
||||||
|
RET_CHECK(format == mediapipe::GpuBufferFormat::kBGRA32 ||
|
||||||
|
format == mediapipe::GpuBufferFormat::kRGBA32 ||
|
||||||
|
format == mediapipe::GpuBufferFormat::kRGBAFloat128 ||
|
||||||
|
format == mediapipe::GpuBufferFormat::kRGBAHalf64)
|
||||||
|
<< "Num input channels is less than desired output, input format: "
|
||||||
|
<< static_cast<uint32_t>(format);
|
||||||
|
}
|
||||||
|
|
||||||
#if MEDIAPIPE_METAL_ENABLED
|
#if MEDIAPIPE_METAL_ENABLED
|
||||||
id<MTLDevice> device = gpu_helper_.mtlDevice;
|
id<MTLDevice> device = gpu_helper_.mtlDevice;
|
||||||
// Shader to convert GL Texture to Metal Buffer,
|
// Shader to convert GL Texture to Metal Buffer,
|
||||||
// with normalization to either: [0,1] or [-1,1].
|
// with normalization to either: [0,1] or [-1,1].
|
||||||
const std::string shader_source = absl::Substitute(
|
const std::string shader_source = absl::Substitute(
|
||||||
R"(
|
R"glsl(
|
||||||
#include <metal_stdlib>
|
#include <metal_stdlib>
|
||||||
|
|
||||||
using namespace metal;
|
using namespace metal;
|
||||||
@@ -413,7 +472,7 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
|
|||||||
$3 // g & b channels
|
$3 // g & b channels
|
||||||
$4 // alpha channel
|
$4 // alpha channel
|
||||||
}
|
}
|
||||||
)",
|
)glsl",
|
||||||
/*$0=*/
|
/*$0=*/
|
||||||
output_range_.has_value()
|
output_range_.has_value()
|
||||||
? absl::Substitute("pixel = pixel * half($0) + half($1);",
|
? absl::Substitute("pixel = pixel * half($0) + half($1);",
|
||||||
@@ -423,8 +482,8 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
|
|||||||
/*$1=*/max_num_channels_,
|
/*$1=*/max_num_channels_,
|
||||||
/*$2=*/flip_vertically_ ? "(in_tex.get_height() - 1 - gid.y)" : "gid.y",
|
/*$2=*/flip_vertically_ ? "(in_tex.get_height() - 1 - gid.y)" : "gid.y",
|
||||||
/*$3=*/
|
/*$3=*/
|
||||||
single_channel ? "" : R"(out_buf[linear_index + 1] = pixel.y;
|
single_channel ? "" : R"glsl(out_buf[linear_index + 1] = pixel.y;
|
||||||
out_buf[linear_index + 2] = pixel.z;)",
|
out_buf[linear_index + 2] = pixel.z;)glsl",
|
||||||
/*$4=*/include_alpha ? "out_buf[linear_index + 3] = pixel.w;" : "");
|
/*$4=*/include_alpha ? "out_buf[linear_index + 3] = pixel.w;" : "");
|
||||||
|
|
||||||
NSString* library_source =
|
NSString* library_source =
|
||||||
@@ -442,17 +501,17 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
|
|||||||
RET_CHECK(to_buffer_program_ != nil) << "Couldn't create pipeline state " <<
|
RET_CHECK(to_buffer_program_ != nil) << "Couldn't create pipeline state " <<
|
||||||
[[error localizedDescription] UTF8String];
|
[[error localizedDescription] UTF8String];
|
||||||
#elif MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
|
#elif MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
|
||||||
MP_RETURN_IF_ERROR(gpu_helper_.RunInGlContext([this, &include_alpha,
|
MP_RETURN_IF_ERROR(
|
||||||
|
gpu_helper_.RunInGlContext([this, &include_alpha,
|
||||||
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
&input,
|
&input,
|
||||||
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
&single_channel]()
|
&single_channel]() -> absl::Status {
|
||||||
-> absl::Status {
|
|
||||||
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
// Shader to convert GL Texture to Shader Storage Buffer Object (SSBO),
|
// Shader to convert GL Texture to Shader Storage Buffer Object (SSBO),
|
||||||
// with normalization to either: [0,1] or [-1,1].
|
// with normalization to either: [0,1] or [-1,1].
|
||||||
const std::string shader_source = absl::Substitute(
|
const std::string shader_source = absl::Substitute(
|
||||||
R"( #version 310 es
|
R"glsl( #version 310 es
|
||||||
layout(local_size_x = $0, local_size_y = $0) in;
|
layout(local_size_x = $0, local_size_y = $0) in;
|
||||||
layout(binding = 0) uniform sampler2D input_texture;
|
layout(binding = 0) uniform sampler2D input_texture;
|
||||||
layout(std430, binding = 1) buffer Output {float elements[];} output_data;
|
layout(std430, binding = 1) buffer Output {float elements[];} output_data;
|
||||||
@@ -466,38 +525,40 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
|
|||||||
output_data.elements[linear_index + 0] = pixel.x; // r channel
|
output_data.elements[linear_index + 0] = pixel.x; // r channel
|
||||||
$5 // g & b channels
|
$5 // g & b channels
|
||||||
$6 // alpha channel
|
$6 // alpha channel
|
||||||
})",
|
})glsl",
|
||||||
/*$0=*/kWorkgroupSize, /*$1=*/input.width(), /*$2=*/input.height(),
|
/*$0=*/kWorkgroupSize, /*$1=*/input.width(), /*$2=*/input.height(),
|
||||||
/*$3=*/
|
/*$3=*/
|
||||||
output_range_.has_value()
|
output_range_.has_value()
|
||||||
? absl::Substitute("pixel = pixel * float($0) + float($1);",
|
? absl::Substitute(
|
||||||
(output_range_->second - output_range_->first),
|
"pixel = pixel * float($0) + float($1);",
|
||||||
output_range_->first)
|
(output_range_->second - output_range_->first),
|
||||||
: "",
|
output_range_->first)
|
||||||
/*$4=*/flip_vertically_ ? "(width_height.y - 1 - gid.y)" : "gid.y",
|
: "",
|
||||||
/*$5=*/
|
/*$4=*/flip_vertically_ ? "(width_height.y - 1 - gid.y)" : "gid.y",
|
||||||
single_channel ? ""
|
/*$5=*/
|
||||||
: R"(output_data.elements[linear_index + 1] = pixel.y;
|
single_channel
|
||||||
output_data.elements[linear_index + 2] = pixel.z;)",
|
? ""
|
||||||
/*$6=*/
|
: R"glsl(output_data.elements[linear_index + 1] = pixel.y;
|
||||||
include_alpha ? "output_data.elements[linear_index + 3] = pixel.w;"
|
output_data.elements[linear_index + 2] = pixel.z;)glsl",
|
||||||
: "",
|
/*$6=*/
|
||||||
/*$7=*/max_num_channels_);
|
include_alpha ? "output_data.elements[linear_index + 3] = pixel.w;"
|
||||||
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
|
: "",
|
||||||
const GLchar* sources[] = {shader_source.c_str()};
|
/*$7=*/max_num_channels_);
|
||||||
glShaderSource(shader, 1, sources, NULL);
|
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
|
||||||
glCompileShader(shader);
|
const GLchar* sources[] = {shader_source.c_str()};
|
||||||
GLint compiled = GL_FALSE;
|
glShaderSource(shader, 1, sources, NULL);
|
||||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
|
glCompileShader(shader);
|
||||||
RET_CHECK(compiled == GL_TRUE);
|
GLint compiled = GL_FALSE;
|
||||||
to_buffer_program_ = glCreateProgram();
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
|
||||||
glAttachShader(to_buffer_program_, shader);
|
RET_CHECK(compiled == GL_TRUE);
|
||||||
glDeleteShader(shader);
|
to_buffer_program_ = glCreateProgram();
|
||||||
glLinkProgram(to_buffer_program_);
|
glAttachShader(to_buffer_program_, shader);
|
||||||
|
glDeleteShader(shader);
|
||||||
|
glLinkProgram(to_buffer_program_);
|
||||||
#else
|
#else
|
||||||
// OpenGL ES 3.0 fragment shader Texture2d -> Texture2d conversion.
|
// OpenGL ES 3.0 fragment shader Texture2d -> Texture2d conversion.
|
||||||
const std::string shader_source = absl::Substitute(
|
const std::string shader_source = absl::Substitute(
|
||||||
R"(
|
R"glsl(
|
||||||
#if __VERSION__ < 130
|
#if __VERSION__ < 130
|
||||||
#define in varying
|
#define in varying
|
||||||
#endif // __VERSION__ < 130
|
#endif // __VERSION__ < 130
|
||||||
@@ -523,49 +584,51 @@ absl::Status TensorConverterCalculator::InitGpu(CalculatorContext* cc) {
|
|||||||
fragColor.r = pixel.r; // r channel
|
fragColor.r = pixel.r; // r channel
|
||||||
$3 // g & b channels
|
$3 // g & b channels
|
||||||
$4 // alpha channel
|
$4 // alpha channel
|
||||||
})",
|
})glsl",
|
||||||
/*$0=*/single_channel ? "vec1" : "vec4",
|
/*$0=*/single_channel ? "vec1" : "vec4",
|
||||||
/*$1=*/
|
/*$1=*/
|
||||||
flip_vertically_
|
flip_vertically_
|
||||||
? "vec2(sample_coordinate.x, 1.0 - sample_coordinate.y);"
|
? "vec2(sample_coordinate.x, 1.0 - sample_coordinate.y);"
|
||||||
: "sample_coordinate;",
|
: "sample_coordinate;",
|
||||||
/*$2=*/output_range_.has_value()
|
/*$2=*/output_range_.has_value()
|
||||||
? absl::Substitute("pixel = pixel * float($0) + float($1);",
|
? absl::Substitute(
|
||||||
(output_range_->second - output_range_->first),
|
"pixel = pixel * float($0) + float($1);",
|
||||||
output_range_->first)
|
(output_range_->second - output_range_->first),
|
||||||
: "",
|
output_range_->first)
|
||||||
/*$3=*/single_channel ? "" : R"(fragColor.g = pixel.g;
|
: "",
|
||||||
fragColor.b = pixel.b;)",
|
/*$3=*/single_channel ? "" : R"glsl(fragColor.g = pixel.g;
|
||||||
/*$4=*/
|
fragColor.b = pixel.b;)glsl",
|
||||||
include_alpha ? "fragColor.a = pixel.a;"
|
/*$4=*/
|
||||||
: (single_channel ? "" : "fragColor.a = 1.0;"));
|
include_alpha ? "fragColor.a = pixel.a;"
|
||||||
|
: (single_channel ? "" : "fragColor.a = 1.0;"));
|
||||||
|
|
||||||
const GLint attr_location[NUM_ATTRIBUTES] = {
|
const GLint attr_location[NUM_ATTRIBUTES] = {
|
||||||
ATTRIB_VERTEX,
|
ATTRIB_VERTEX,
|
||||||
ATTRIB_TEXTURE_POSITION,
|
ATTRIB_TEXTURE_POSITION,
|
||||||
};
|
};
|
||||||
const GLchar* attr_name[NUM_ATTRIBUTES] = {
|
const GLchar* attr_name[NUM_ATTRIBUTES] = {
|
||||||
"position",
|
"position",
|
||||||
"texture_coordinate",
|
"texture_coordinate",
|
||||||
};
|
};
|
||||||
// shader program and params
|
// shader program and params
|
||||||
mediapipe::GlhCreateProgram(
|
mediapipe::GlhCreateProgram(
|
||||||
mediapipe::kBasicVertexShader, shader_source.c_str(), NUM_ATTRIBUTES,
|
mediapipe::kBasicVertexShader, shader_source.c_str(),
|
||||||
&attr_name[0], attr_location, &to_tex2d_program_);
|
NUM_ATTRIBUTES, &attr_name[0], attr_location, &to_tex2d_program_);
|
||||||
RET_CHECK(to_tex2d_program_) << "Problem initializing the program.";
|
RET_CHECK(to_tex2d_program_) << "Problem initializing the program.";
|
||||||
glUseProgram(to_tex2d_program_);
|
glUseProgram(to_tex2d_program_);
|
||||||
glUniform1i(glGetUniformLocation(to_tex2d_program_, "frame"), 1);
|
glUniform1i(glGetUniformLocation(to_tex2d_program_, "frame"), 1);
|
||||||
glGenFramebuffers(1, &framebuffer_);
|
glGenFramebuffers(1, &framebuffer_);
|
||||||
|
|
||||||
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}));
|
}));
|
||||||
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
|
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
|
||||||
#endif // !MEDIAPIPE_DISABLE_GPU
|
#endif // !MEDIAPIPE_DISABLE_GPU
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc) {
|
absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc,
|
||||||
|
bool use_gpu) {
|
||||||
// Get calculator options specified in the graph.
|
// Get calculator options specified in the graph.
|
||||||
const auto& options =
|
const auto& options =
|
||||||
cc->Options<::mediapipe::TensorConverterCalculatorOptions>();
|
cc->Options<::mediapipe::TensorConverterCalculatorOptions>();
|
||||||
@@ -582,7 +645,7 @@ absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc) {
|
|||||||
if (options.has_output_tensor_float_range()) {
|
if (options.has_output_tensor_float_range()) {
|
||||||
output_range_.emplace(options.output_tensor_float_range().min(),
|
output_range_.emplace(options.output_tensor_float_range().min(),
|
||||||
options.output_tensor_float_range().max());
|
options.output_tensor_float_range().max());
|
||||||
CHECK_GT(output_range_->second, output_range_->first);
|
ABSL_CHECK_GT(output_range_->second, output_range_->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom div and sub values.
|
// Custom div and sub values.
|
||||||
@@ -593,16 +656,16 @@ absl::Status TensorConverterCalculator::LoadOptions(CalculatorContext* cc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get y-flip mode.
|
// Get y-flip mode.
|
||||||
flip_vertically_ = options.flip_vertically();
|
MP_ASSIGN_OR_RETURN(flip_vertically_, ShouldFlipVertically(options, use_gpu));
|
||||||
|
|
||||||
// Get row_major_matrix mode.
|
// Get row_major_matrix mode.
|
||||||
row_major_matrix_ = options.row_major_matrix();
|
row_major_matrix_ = options.row_major_matrix();
|
||||||
|
|
||||||
// Get desired way to handle input channels.
|
// Get desired way to handle input channels.
|
||||||
max_num_channels_ = options.max_num_channels();
|
max_num_channels_ = options.max_num_channels();
|
||||||
CHECK_GE(max_num_channels_, 1);
|
ABSL_CHECK_GE(max_num_channels_, 1);
|
||||||
CHECK_LE(max_num_channels_, 4);
|
ABSL_CHECK_LE(max_num_channels_, 4);
|
||||||
CHECK_NE(max_num_channels_, 2);
|
ABSL_CHECK_NE(max_num_channels_, 2);
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ syntax = "proto2";
|
|||||||
package mediapipe;
|
package mediapipe;
|
||||||
|
|
||||||
import "mediapipe/framework/calculator.proto";
|
import "mediapipe/framework/calculator.proto";
|
||||||
|
import "mediapipe/gpu/gpu_origin.proto";
|
||||||
|
|
||||||
// Full Example:
|
// Full Example:
|
||||||
//
|
//
|
||||||
@@ -43,8 +44,16 @@ message TensorConverterCalculatorOptions {
|
|||||||
// with a coordinate system where the origin is at the bottom-left corner
|
// with a coordinate system where the origin is at the bottom-left corner
|
||||||
// (e.g., in OpenGL) whereas the ML model expects an image with a top-left
|
// (e.g., in OpenGL) whereas the ML model expects an image with a top-left
|
||||||
// origin.
|
// origin.
|
||||||
|
// Prefer gpu_origin over this field when using GPU input images.
|
||||||
optional bool flip_vertically = 2 [default = false];
|
optional bool flip_vertically = 2 [default = false];
|
||||||
|
|
||||||
|
// Determines when the input GPU image should be flipped vertically.
|
||||||
|
// See GpuOrigin.Mode for more information.
|
||||||
|
// Affects only IMAGE_GPU inputs.
|
||||||
|
// If unset, falls back to flip_vertically for backwards compatibility.
|
||||||
|
// Cannot set both gpu_origin and flip_vertically.
|
||||||
|
optional GpuOrigin.Mode gpu_origin = 10;
|
||||||
|
|
||||||
// Controls how many channels of the input image get passed through to the
|
// Controls how many channels of the input image get passed through to the
|
||||||
// tensor. Valid values are 1,3,4 only. Ignored for iOS GPU.
|
// tensor. Valid values are 1,3,4 only. Ignored for iOS GPU.
|
||||||
optional int32 max_num_channels = 3 [default = 3];
|
optional int32 max_num_channels = 3 [default = 3];
|
||||||
|
|||||||
@@ -12,10 +12,15 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
|
#include "absl/status/status.h"
|
||||||
#include "absl/strings/substitute.h"
|
#include "absl/strings/substitute.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/calculator_runner.h"
|
#include "mediapipe/framework/calculator_runner.h"
|
||||||
@@ -24,8 +29,10 @@
|
|||||||
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
||||||
#include "mediapipe/framework/formats/matrix.h"
|
#include "mediapipe/framework/formats/matrix.h"
|
||||||
#include "mediapipe/framework/formats/tensor.h"
|
#include "mediapipe/framework/formats/tensor.h"
|
||||||
|
#include "mediapipe/framework/port/gmock.h"
|
||||||
#include "mediapipe/framework/port/gtest.h"
|
#include "mediapipe/framework/port/gtest.h"
|
||||||
#include "mediapipe/framework/port/integral_types.h"
|
#include "mediapipe/framework/port/integral_types.h"
|
||||||
|
#include "mediapipe/framework/port/opencv_core_inc.h"
|
||||||
#include "mediapipe/framework/port/parse_text_proto.h"
|
#include "mediapipe/framework/port/parse_text_proto.h"
|
||||||
#include "mediapipe/framework/port/status_matchers.h" // NOLINT
|
#include "mediapipe/framework/port/status_matchers.h" // NOLINT
|
||||||
#include "mediapipe/framework/tool/validate_type.h"
|
#include "mediapipe/framework/tool/validate_type.h"
|
||||||
@@ -40,7 +47,7 @@ constexpr char kTransposeOptionsString[] =
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
using RandomEngine = std::mt19937_64;
|
using RandomEngine = std::mt19937_64;
|
||||||
using testing::Eq;
|
using ::testing::HasSubstr;
|
||||||
const uint32_t kSeed = 1234;
|
const uint32_t kSeed = 1234;
|
||||||
const int kNumSizes = 8;
|
const int kNumSizes = 8;
|
||||||
const int sizes[kNumSizes][2] = {{1, 1}, {12, 1}, {1, 9}, {2, 2},
|
const int sizes[kNumSizes][2] = {{1, 1}, {12, 1}, {1, 9}, {2, 2},
|
||||||
@@ -53,7 +60,7 @@ class TensorConverterCalculatorTest : public ::testing::Test {
|
|||||||
bool row_major_matrix = false) {
|
bool row_major_matrix = false) {
|
||||||
RandomEngine random(kSeed);
|
RandomEngine random(kSeed);
|
||||||
std::uniform_real_distribution<> uniform_dist(0, 1.0);
|
std::uniform_real_distribution<> uniform_dist(0, 1.0);
|
||||||
auto matrix = ::absl::make_unique<Matrix>();
|
auto matrix = std::make_unique<Matrix>();
|
||||||
matrix->resize(num_rows, num_columns);
|
matrix->resize(num_rows, num_columns);
|
||||||
if (row_major_matrix) {
|
if (row_major_matrix) {
|
||||||
for (int y = 0; y < num_rows; ++y) {
|
for (int y = 0; y < num_rows; ++y) {
|
||||||
@@ -101,7 +108,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixColMajor) {
|
|||||||
tool::AddVectorSink("tensor", &graph_config, &output_packets);
|
tool::AddVectorSink("tensor", &graph_config, &output_packets);
|
||||||
|
|
||||||
// Run the graph.
|
// Run the graph.
|
||||||
graph_ = absl::make_unique<CalculatorGraph>();
|
graph_ = std::make_unique<CalculatorGraph>();
|
||||||
MP_ASSERT_OK(graph_->Initialize(graph_config));
|
MP_ASSERT_OK(graph_->Initialize(graph_config));
|
||||||
MP_ASSERT_OK(graph_->StartRun({}));
|
MP_ASSERT_OK(graph_->StartRun({}));
|
||||||
|
|
||||||
@@ -110,12 +117,12 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixColMajor) {
|
|||||||
|
|
||||||
// Wait until the calculator done processing.
|
// Wait until the calculator done processing.
|
||||||
MP_ASSERT_OK(graph_->WaitUntilIdle());
|
MP_ASSERT_OK(graph_->WaitUntilIdle());
|
||||||
EXPECT_EQ(1, output_packets.size());
|
ASSERT_EQ(output_packets.size(), 1);
|
||||||
|
|
||||||
// Get and process results.
|
// Get and process results.
|
||||||
const std::vector<Tensor>& tensor_vec =
|
const std::vector<Tensor>& tensor_vec =
|
||||||
output_packets[0].Get<std::vector<Tensor>>();
|
output_packets[0].Get<std::vector<Tensor>>();
|
||||||
EXPECT_EQ(1, tensor_vec.size());
|
ASSERT_EQ(tensor_vec.size(), 1);
|
||||||
|
|
||||||
const Tensor* tensor = &tensor_vec[0];
|
const Tensor* tensor = &tensor_vec[0];
|
||||||
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
|
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
|
||||||
@@ -127,7 +134,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixColMajor) {
|
|||||||
auto tensor_buffer = view.buffer<float>();
|
auto tensor_buffer = view.buffer<float>();
|
||||||
for (int i = 0; i < num_rows * num_columns; ++i) {
|
for (int i = 0; i < num_rows * num_columns; ++i) {
|
||||||
const float expected = uniform_dist(random);
|
const float expected = uniform_dist(random);
|
||||||
EXPECT_EQ(expected, tensor_buffer[i]) << "at i = " << i;
|
EXPECT_FLOAT_EQ(tensor_buffer[i], expected) << "at i = " << i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
||||||
@@ -163,7 +170,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixRowMajor) {
|
|||||||
tool::AddVectorSink("tensor", &graph_config, &output_packets);
|
tool::AddVectorSink("tensor", &graph_config, &output_packets);
|
||||||
|
|
||||||
// Run the graph.
|
// Run the graph.
|
||||||
graph_ = absl::make_unique<CalculatorGraph>();
|
graph_ = std::make_unique<CalculatorGraph>();
|
||||||
MP_ASSERT_OK(graph_->Initialize(graph_config));
|
MP_ASSERT_OK(graph_->Initialize(graph_config));
|
||||||
MP_ASSERT_OK(graph_->StartRun({}));
|
MP_ASSERT_OK(graph_->StartRun({}));
|
||||||
|
|
||||||
@@ -172,12 +179,12 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixRowMajor) {
|
|||||||
|
|
||||||
// Wait until the calculator done processing.
|
// Wait until the calculator done processing.
|
||||||
MP_ASSERT_OK(graph_->WaitUntilIdle());
|
MP_ASSERT_OK(graph_->WaitUntilIdle());
|
||||||
EXPECT_EQ(1, output_packets.size());
|
ASSERT_EQ(output_packets.size(), 1);
|
||||||
|
|
||||||
// Get and process results.
|
// Get and process results.
|
||||||
const std::vector<Tensor>& tensor_vec =
|
const std::vector<Tensor>& tensor_vec =
|
||||||
output_packets[0].Get<std::vector<Tensor>>();
|
output_packets[0].Get<std::vector<Tensor>>();
|
||||||
EXPECT_EQ(1, tensor_vec.size());
|
ASSERT_EQ(tensor_vec.size(), 1);
|
||||||
|
|
||||||
const Tensor* tensor = &tensor_vec[0];
|
const Tensor* tensor = &tensor_vec[0];
|
||||||
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
|
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
|
||||||
@@ -189,7 +196,7 @@ TEST_F(TensorConverterCalculatorTest, RandomMatrixRowMajor) {
|
|||||||
auto tensor_buffer = view.buffer<float>();
|
auto tensor_buffer = view.buffer<float>();
|
||||||
for (int i = 0; i < num_rows * num_columns; ++i) {
|
for (int i = 0; i < num_rows * num_columns; ++i) {
|
||||||
const float expected = uniform_dist(random);
|
const float expected = uniform_dist(random);
|
||||||
EXPECT_EQ(expected, tensor_buffer[i]) << "at i = " << i;
|
EXPECT_EQ(tensor_buffer[i], expected) << "at i = " << i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
||||||
@@ -227,7 +234,7 @@ TEST_F(TensorConverterCalculatorTest, CustomDivAndSub) {
|
|||||||
// Run the graph.
|
// Run the graph.
|
||||||
MP_ASSERT_OK(graph.Initialize(graph_config));
|
MP_ASSERT_OK(graph.Initialize(graph_config));
|
||||||
MP_ASSERT_OK(graph.StartRun({}));
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
auto input_image = absl::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1);
|
auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1);
|
||||||
cv::Mat mat = mediapipe::formats::MatView(input_image.get());
|
cv::Mat mat = mediapipe::formats::MatView(input_image.get());
|
||||||
mat.at<uint8_t>(0, 0) = 200;
|
mat.at<uint8_t>(0, 0) = 200;
|
||||||
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
@@ -239,12 +246,12 @@ TEST_F(TensorConverterCalculatorTest, CustomDivAndSub) {
|
|||||||
// Get and process results.
|
// Get and process results.
|
||||||
const std::vector<Tensor>& tensor_vec =
|
const std::vector<Tensor>& tensor_vec =
|
||||||
output_packets[0].Get<std::vector<Tensor>>();
|
output_packets[0].Get<std::vector<Tensor>>();
|
||||||
EXPECT_EQ(1, tensor_vec.size());
|
ASSERT_EQ(tensor_vec.size(), 1);
|
||||||
|
|
||||||
const Tensor* tensor = &tensor_vec[0];
|
const Tensor* tensor = &tensor_vec[0];
|
||||||
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
|
EXPECT_EQ(Tensor::ElementType::kFloat32, tensor->element_type());
|
||||||
auto view = tensor->GetCpuReadView();
|
auto view = tensor->GetCpuReadView();
|
||||||
EXPECT_FLOAT_EQ(67.0f, *view.buffer<float>());
|
EXPECT_FLOAT_EQ(*view.buffer<float>(), 67.0f);
|
||||||
|
|
||||||
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
||||||
// after calling WaitUntilDone().
|
// after calling WaitUntilDone().
|
||||||
@@ -259,32 +266,29 @@ TEST_F(TensorConverterCalculatorTest, SetOutputRange) {
|
|||||||
for (std::pair<float, float> range : range_values) {
|
for (std::pair<float, float> range : range_values) {
|
||||||
CalculatorGraph graph;
|
CalculatorGraph graph;
|
||||||
CalculatorGraphConfig graph_config =
|
CalculatorGraphConfig graph_config =
|
||||||
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(
|
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(absl::Substitute(
|
||||||
absl::Substitute(R"(
|
R"pb(
|
||||||
input_stream: "input_image"
|
input_stream: "input_image"
|
||||||
node {
|
node {
|
||||||
calculator: "TensorConverterCalculator"
|
calculator: "TensorConverterCalculator"
|
||||||
input_stream: "IMAGE:input_image"
|
input_stream: "IMAGE:input_image"
|
||||||
output_stream: "TENSORS:tensor"
|
output_stream: "TENSORS:tensor"
|
||||||
options {
|
options {
|
||||||
[mediapipe.TensorConverterCalculatorOptions.ext] {
|
[mediapipe.TensorConverterCalculatorOptions.ext] {
|
||||||
output_tensor_float_range {
|
output_tensor_float_range { min: $0 max: $1 }
|
||||||
min: $0
|
}
|
||||||
max: $1
|
}
|
||||||
}
|
}
|
||||||
}
|
)pb",
|
||||||
}
|
/*$0=*/range.first,
|
||||||
}
|
/*$1=*/range.second));
|
||||||
)",
|
|
||||||
/*$0=*/range.first,
|
|
||||||
/*$1=*/range.second));
|
|
||||||
std::vector<Packet> output_packets;
|
std::vector<Packet> output_packets;
|
||||||
tool::AddVectorSink("tensor", &graph_config, &output_packets);
|
tool::AddVectorSink("tensor", &graph_config, &output_packets);
|
||||||
|
|
||||||
// Run the graph.
|
// Run the graph.
|
||||||
MP_ASSERT_OK(graph.Initialize(graph_config));
|
MP_ASSERT_OK(graph.Initialize(graph_config));
|
||||||
MP_ASSERT_OK(graph.StartRun({}));
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
auto input_image = absl::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1);
|
auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1);
|
||||||
cv::Mat mat = mediapipe::formats::MatView(input_image.get());
|
cv::Mat mat = mediapipe::formats::MatView(input_image.get());
|
||||||
mat.at<uint8_t>(0, 0) = 200;
|
mat.at<uint8_t>(0, 0) = 200;
|
||||||
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
@@ -292,26 +296,23 @@ TEST_F(TensorConverterCalculatorTest, SetOutputRange) {
|
|||||||
|
|
||||||
// Wait until the calculator finishes processing.
|
// Wait until the calculator finishes processing.
|
||||||
MP_ASSERT_OK(graph.WaitUntilIdle());
|
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||||
EXPECT_THAT(output_packets.size(), Eq(1));
|
ASSERT_EQ(output_packets.size(), 1);
|
||||||
|
|
||||||
// Get and process results.
|
// Get and process results.
|
||||||
const std::vector<Tensor>& tensor_vec =
|
const std::vector<Tensor>& tensor_vec =
|
||||||
output_packets[0].Get<std::vector<Tensor>>();
|
output_packets[0].Get<std::vector<Tensor>>();
|
||||||
EXPECT_THAT(tensor_vec.size(), Eq(1));
|
ASSERT_EQ(tensor_vec.size(), 1);
|
||||||
|
|
||||||
const Tensor* tensor = &tensor_vec[0];
|
const Tensor* tensor = &tensor_vec[0];
|
||||||
|
|
||||||
// Calculate the expected normalized value:
|
// Calculate the expected normalized value:
|
||||||
float normalized_value =
|
float expected_value =
|
||||||
range.first + (200 * (range.second - range.first)) / 255.0;
|
range.first + (200 * (range.second - range.first)) / 255.0;
|
||||||
|
|
||||||
EXPECT_THAT(tensor->element_type(), Eq(Tensor::ElementType::kFloat32));
|
EXPECT_EQ(tensor->element_type(), Tensor::ElementType::kFloat32);
|
||||||
auto view = tensor->GetCpuReadView();
|
auto view = tensor->GetCpuReadView();
|
||||||
float dataf = *view.buffer<float>();
|
float actual_value = *view.buffer<float>();
|
||||||
EXPECT_THAT(
|
EXPECT_FLOAT_EQ(actual_value, expected_value);
|
||||||
normalized_value,
|
|
||||||
testing::FloatNear(dataf, 2.0f * std::abs(dataf) *
|
|
||||||
std::numeric_limits<float>::epsilon()));
|
|
||||||
|
|
||||||
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
||||||
// after calling WaitUntilDone().
|
// after calling WaitUntilDone().
|
||||||
@@ -320,4 +321,153 @@ TEST_F(TensorConverterCalculatorTest, SetOutputRange) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TensorConverterCalculatorTest, FlipVertically) {
|
||||||
|
CalculatorGraph graph;
|
||||||
|
CalculatorGraphConfig graph_config =
|
||||||
|
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||||
|
input_stream: "input_image"
|
||||||
|
node {
|
||||||
|
calculator: "TensorConverterCalculator"
|
||||||
|
input_stream: "IMAGE:input_image"
|
||||||
|
output_stream: "TENSORS:tensor"
|
||||||
|
options {
|
||||||
|
[mediapipe.TensorConverterCalculatorOptions.ext] {
|
||||||
|
flip_vertically: true
|
||||||
|
output_tensor_float_range { min: 0 max: 255 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)pb");
|
||||||
|
std::vector<Packet> output_packets;
|
||||||
|
tool::AddVectorSink("tensor", &graph_config, &output_packets);
|
||||||
|
|
||||||
|
// Run the graph.
|
||||||
|
MP_ASSERT_OK(graph.Initialize(graph_config));
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 2);
|
||||||
|
cv::Mat mat = mediapipe::formats::MatView(input_image.get());
|
||||||
|
constexpr uint8_t kY0Value = 100;
|
||||||
|
constexpr uint8_t kY1Value = 200;
|
||||||
|
mat.at<uint8_t>(0, 0) = kY0Value;
|
||||||
|
mat.at<uint8_t>(1, 0) = kY1Value; // Note: y, x!
|
||||||
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
|
"input_image", Adopt(input_image.release()).At(Timestamp(0))));
|
||||||
|
|
||||||
|
// Wait until the calculator finishes processing.
|
||||||
|
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||||
|
ASSERT_EQ(output_packets.size(), 1);
|
||||||
|
|
||||||
|
// Get and process results.
|
||||||
|
const std::vector<Tensor>& tensor_vec =
|
||||||
|
output_packets[0].Get<std::vector<Tensor>>();
|
||||||
|
ASSERT_EQ(tensor_vec.size(), 1);
|
||||||
|
|
||||||
|
const Tensor* tensor = &tensor_vec[0];
|
||||||
|
|
||||||
|
EXPECT_EQ(tensor->element_type(), Tensor::ElementType::kFloat32);
|
||||||
|
const float* dataf = tensor->GetCpuReadView().buffer<float>();
|
||||||
|
EXPECT_EQ(static_cast<int>(roundf(dataf[0])), kY1Value); // Y0, Y1 flipped!
|
||||||
|
EXPECT_EQ(static_cast<int>(roundf(dataf[1])), kY0Value);
|
||||||
|
|
||||||
|
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
||||||
|
// after calling WaitUntilDone().
|
||||||
|
MP_ASSERT_OK(graph.CloseInputStream("input_image"));
|
||||||
|
MP_ASSERT_OK(graph.WaitUntilDone());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TensorConverterCalculatorTest,
|
||||||
|
CannotSpecifyBothFlipVerticallyAndGpuOrigin) {
|
||||||
|
CalculatorGraph graph;
|
||||||
|
CalculatorGraphConfig graph_config =
|
||||||
|
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||||
|
input_stream: "input_image"
|
||||||
|
node {
|
||||||
|
calculator: "TensorConverterCalculator"
|
||||||
|
input_stream: "IMAGE:input_image"
|
||||||
|
output_stream: "TENSORS:tensor"
|
||||||
|
options {
|
||||||
|
[mediapipe.TensorConverterCalculatorOptions.ext] {
|
||||||
|
flip_vertically: true
|
||||||
|
gpu_origin: TOP_LEFT
|
||||||
|
output_tensor_float_range { min: 0 max: 255 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)pb");
|
||||||
|
std::vector<Packet> output_packets;
|
||||||
|
tool::AddVectorSink("tensor", &graph_config, &output_packets);
|
||||||
|
|
||||||
|
// Run the graph.
|
||||||
|
MP_ASSERT_OK(graph.Initialize(graph_config));
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 1);
|
||||||
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
|
"input_image", Adopt(input_image.release()).At(Timestamp(0))));
|
||||||
|
|
||||||
|
// Processing should fail as we specified both flip_vertically and gpu_origin.
|
||||||
|
absl::Status status = graph.WaitUntilIdle();
|
||||||
|
EXPECT_FALSE(status.ok());
|
||||||
|
EXPECT_THAT(status.message(), HasSubstr("flip_vertically and gpu_origin"));
|
||||||
|
EXPECT_EQ(output_packets.size(), 0);
|
||||||
|
|
||||||
|
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
||||||
|
// after calling WaitUntilDone().
|
||||||
|
MP_ASSERT_OK(graph.CloseInputStream("input_image"));
|
||||||
|
EXPECT_FALSE(graph.WaitUntilDone().ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TensorConverterCalculatorTest, GpuOriginIsIgnoredWithCpuImage) {
|
||||||
|
CalculatorGraph graph;
|
||||||
|
CalculatorGraphConfig graph_config =
|
||||||
|
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||||
|
input_stream: "input_image"
|
||||||
|
node {
|
||||||
|
calculator: "TensorConverterCalculator"
|
||||||
|
input_stream: "IMAGE:input_image"
|
||||||
|
output_stream: "TENSORS:tensor"
|
||||||
|
options {
|
||||||
|
[mediapipe.TensorConverterCalculatorOptions.ext] {
|
||||||
|
gpu_origin: CONVENTIONAL
|
||||||
|
output_tensor_float_range { min: 0 max: 255 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)pb");
|
||||||
|
std::vector<Packet> output_packets;
|
||||||
|
tool::AddVectorSink("tensor", &graph_config, &output_packets);
|
||||||
|
|
||||||
|
// Run the graph.
|
||||||
|
MP_ASSERT_OK(graph.Initialize(graph_config));
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
auto input_image = std::make_unique<ImageFrame>(ImageFormat::GRAY8, 1, 2);
|
||||||
|
cv::Mat mat = mediapipe::formats::MatView(input_image.get());
|
||||||
|
constexpr uint8_t kY0Value = 100;
|
||||||
|
constexpr uint8_t kY1Value = 200;
|
||||||
|
mat.at<uint8_t>(0, 0) = kY0Value;
|
||||||
|
mat.at<uint8_t>(1, 0) = kY1Value; // Note: y, x!
|
||||||
|
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||||
|
"input_image", Adopt(input_image.release()).At(Timestamp(0))));
|
||||||
|
|
||||||
|
// Wait until the calculator finishes processing.
|
||||||
|
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||||
|
ASSERT_EQ(output_packets.size(), 1);
|
||||||
|
|
||||||
|
// Get and process results.
|
||||||
|
const std::vector<Tensor>& tensor_vec =
|
||||||
|
output_packets[0].Get<std::vector<Tensor>>();
|
||||||
|
ASSERT_EQ(tensor_vec.size(), 1);
|
||||||
|
|
||||||
|
const Tensor* tensor = &tensor_vec[0];
|
||||||
|
|
||||||
|
EXPECT_EQ(tensor->element_type(), Tensor::ElementType::kFloat32);
|
||||||
|
const float* dataf = tensor->GetCpuReadView().buffer<float>();
|
||||||
|
EXPECT_EQ(static_cast<int>(roundf(dataf[0])), kY0Value); // Not flipped!
|
||||||
|
EXPECT_EQ(static_cast<int>(roundf(dataf[1])), kY1Value);
|
||||||
|
|
||||||
|
// Fully close graph at end, otherwise calculator+tensors are destroyed
|
||||||
|
// after calling WaitUntilDone().
|
||||||
|
MP_ASSERT_OK(graph.CloseInputStream("input_image"));
|
||||||
|
MP_ASSERT_OK(graph.WaitUntilDone());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mediapipe
|
} // namespace mediapipe
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
// Copyright 2023 The MediaPipe Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "mediapipe/calculators/tensor/tensor_to_joints_calculator.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "mediapipe/calculators/tensor/tensor_to_joints_calculator.pb.h"
|
||||||
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/formats/body_rig.pb.h"
|
||||||
|
#include "mediapipe/framework/formats/tensor.h"
|
||||||
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
namespace api2 {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Number of values in 6D representation of rotation.
|
||||||
|
constexpr int kRotation6dSize = 6;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class TensorToJointsCalculatorImpl
|
||||||
|
: public mediapipe::api2::NodeImpl<TensorToJointsCalculator> {
|
||||||
|
public:
|
||||||
|
absl::Status Open(CalculatorContext* cc) override {
|
||||||
|
const auto& options = cc->Options<TensorToJointsCalculatorOptions>();
|
||||||
|
|
||||||
|
// Get number of joints.
|
||||||
|
RET_CHECK_GE(options.num_joints(), 0);
|
||||||
|
num_joints_ = options.num_joints();
|
||||||
|
|
||||||
|
// Get start index.
|
||||||
|
start_index_ = options.start_index();
|
||||||
|
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
absl::Status Process(CalculatorContext* cc) override {
|
||||||
|
// Skip if Tensor is empty.
|
||||||
|
if (kInTensor(cc).IsEmpty()) {
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get raw floats from the Tensor.
|
||||||
|
const Tensor& tensor = kInTensor(cc).Get();
|
||||||
|
RET_CHECK_EQ(tensor.shape().num_elements(),
|
||||||
|
num_joints_ * kRotation6dSize + start_index_)
|
||||||
|
<< "Unexpected number of values in Tensor";
|
||||||
|
const float* raw_floats = tensor.GetCpuReadView().buffer<float>();
|
||||||
|
|
||||||
|
// Convert raw floats into Joint rotations.
|
||||||
|
JointList joints;
|
||||||
|
for (int joint_idx = 0; joint_idx < num_joints_; ++joint_idx) {
|
||||||
|
Joint* joint = joints.add_joint();
|
||||||
|
for (int idx_6d = 0; idx_6d < kRotation6dSize; ++idx_6d) {
|
||||||
|
joint->add_rotation_6d(
|
||||||
|
raw_floats[start_index_ + joint_idx * kRotation6dSize + idx_6d]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kOutJoints(cc).Send(std::move(joints));
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int num_joints_ = 0;
|
||||||
|
int start_index_ = 0;
|
||||||
|
};
|
||||||
|
MEDIAPIPE_NODE_IMPLEMENTATION(TensorToJointsCalculatorImpl);
|
||||||
|
|
||||||
|
} // namespace api2
|
||||||
|
} // namespace mediapipe
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2023 The MediaPipe Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef MEDIAPIPE_CALCULATORS_TENSOR_TENSOR_TO_JOINTS_CALCULATOR_H_
|
||||||
|
#define MEDIAPIPE_CALCULATORS_TENSOR_TENSOR_TO_JOINTS_CALCULATOR_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "mediapipe/framework/api2/node.h"
|
||||||
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/formats/body_rig.pb.h"
|
||||||
|
#include "mediapipe/framework/formats/tensor.h"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
namespace api2 {
|
||||||
|
|
||||||
|
// A calculator to convert Tensors to JointList.
|
||||||
|
//
|
||||||
|
// Calculator fills in only rotation of the joints leaving visibility undefined.
|
||||||
|
//
|
||||||
|
// Input:
|
||||||
|
// TENSOR - std::vector<Tensor> with kFloat32 values
|
||||||
|
// Vector of tensors to be converted to joints. Only the first tensor will
|
||||||
|
// be used. Number of values is expected to be multiple of six.
|
||||||
|
//
|
||||||
|
// Output:
|
||||||
|
// JOINTS - JointList
|
||||||
|
// List of joints with rotations extracted from given tensor and undefined
|
||||||
|
// visibility.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// node {
|
||||||
|
// calculator: "TensorToJointsCalculator"
|
||||||
|
// input_stream: "TENSOR:tensor"
|
||||||
|
// output_stream: "JOINTS:joints"
|
||||||
|
// options: {
|
||||||
|
// [mediapipe.TensorToJointsCalculatorOptions.ext] {
|
||||||
|
// num_joints: 56
|
||||||
|
// start_index: 3
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
class TensorToJointsCalculator : public NodeIntf {
|
||||||
|
public:
|
||||||
|
static constexpr Input<mediapipe::Tensor> kInTensor{"TENSOR"};
|
||||||
|
static constexpr Output<mediapipe::JointList> kOutJoints{"JOINTS"};
|
||||||
|
MEDIAPIPE_NODE_INTERFACE(TensorToJointsCalculator, kInTensor, kOutJoints);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api2
|
||||||
|
} // namespace mediapipe
|
||||||
|
|
||||||
|
#endif // MEDIAPIPE_CALCULATORS_TENSOR_TENSOR_TO_JOINTS_CALCULATOR_H_
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2023 The MediaPipe Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package mediapipe;
|
||||||
|
|
||||||
|
import "mediapipe/framework/calculator.proto";
|
||||||
|
|
||||||
|
message TensorToJointsCalculatorOptions {
|
||||||
|
extend CalculatorOptions {
|
||||||
|
optional TensorToJointsCalculatorOptions ext = 406440177;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of joints from the output of the model. Calculator will expect the
|
||||||
|
// tensor to contain `6 * num_joints + start_index` values.
|
||||||
|
optional int32 num_joints = 1;
|
||||||
|
|
||||||
|
// Index to start reading 6 value blocks from.
|
||||||
|
optional int32 start_index = 2 [default = 0];
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
// Copyright 2023 The MediaPipe Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/strings/substitute.h"
|
||||||
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/calculator_runner.h"
|
||||||
|
#include "mediapipe/framework/formats/body_rig.pb.h"
|
||||||
|
#include "mediapipe/framework/formats/tensor.h"
|
||||||
|
#include "mediapipe/framework/port/gmock.h"
|
||||||
|
#include "mediapipe/framework/port/gtest.h"
|
||||||
|
#include "mediapipe/framework/port/parse_text_proto.h"
|
||||||
|
#include "mediapipe/framework/port/status_matchers.h"
|
||||||
|
#include "mediapipe/framework/timestamp.h"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
namespace api2 {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using Node = ::mediapipe::CalculatorGraphConfig::Node;
|
||||||
|
|
||||||
|
struct TensorToJointsTestCase {
|
||||||
|
std::string test_name;
|
||||||
|
int num_joints;
|
||||||
|
int start_index;
|
||||||
|
std::vector<float> raw_values;
|
||||||
|
std::vector<std::vector<float>> expected_rotations;
|
||||||
|
};
|
||||||
|
|
||||||
|
using TensorToJointsTest = ::testing::TestWithParam<TensorToJointsTestCase>;
|
||||||
|
|
||||||
|
TEST_P(TensorToJointsTest, TensorToJointsTest) {
|
||||||
|
const TensorToJointsTestCase& tc = GetParam();
|
||||||
|
|
||||||
|
// Prepare graph.
|
||||||
|
mediapipe::CalculatorRunner runner(ParseTextProtoOrDie<Node>(absl::Substitute(
|
||||||
|
R"(
|
||||||
|
calculator: "TensorToJointsCalculator"
|
||||||
|
input_stream: "TENSOR:tensor"
|
||||||
|
output_stream: "JOINTS:joints"
|
||||||
|
options: {
|
||||||
|
[mediapipe.TensorToJointsCalculatorOptions.ext] {
|
||||||
|
num_joints: $0
|
||||||
|
start_index: $1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
tc.num_joints, tc.start_index)));
|
||||||
|
|
||||||
|
// Prepare tensor.
|
||||||
|
Tensor tensor(Tensor::ElementType::kFloat32,
|
||||||
|
Tensor::Shape{1, 1, static_cast<int>(tc.raw_values.size()), 1});
|
||||||
|
float* tensor_buffer = tensor.GetCpuWriteView().buffer<float>();
|
||||||
|
ASSERT_NE(tensor_buffer, nullptr);
|
||||||
|
for (int i = 0; i < tc.raw_values.size(); ++i) {
|
||||||
|
tensor_buffer[i] = tc.raw_values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send tensor to the graph.
|
||||||
|
runner.MutableInputs()->Tag("TENSOR").packets.push_back(
|
||||||
|
mediapipe::MakePacket<Tensor>(std::move(tensor)).At(Timestamp(0)));
|
||||||
|
|
||||||
|
// Run the graph.
|
||||||
|
MP_ASSERT_OK(runner.Run());
|
||||||
|
|
||||||
|
const auto& output_packets = runner.Outputs().Tag("JOINTS").packets;
|
||||||
|
EXPECT_EQ(1, output_packets.size());
|
||||||
|
|
||||||
|
const auto& joints = output_packets[0].Get<JointList>();
|
||||||
|
EXPECT_EQ(joints.joint_size(), tc.expected_rotations.size());
|
||||||
|
for (int i = 0; i < joints.joint_size(); ++i) {
|
||||||
|
const Joint& joint = joints.joint(i);
|
||||||
|
std::vector<float> expected_rotation_6d = tc.expected_rotations[i];
|
||||||
|
EXPECT_EQ(joint.rotation_6d_size(), expected_rotation_6d.size())
|
||||||
|
<< "Unexpected joint #" << i << " rotation";
|
||||||
|
for (int j = 0; j < joint.rotation_6d_size(); ++j) {
|
||||||
|
EXPECT_EQ(joint.rotation_6d(j), expected_rotation_6d[j])
|
||||||
|
<< "Unexpected joint #" << i << " rotation";
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(joint.has_visibility());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
TensorToJointsTests, TensorToJointsTest,
|
||||||
|
testing::ValuesIn<TensorToJointsTestCase>({
|
||||||
|
{"Empty", 0, 3, {0, 0, 0}, {}},
|
||||||
|
|
||||||
|
{"Single",
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
{0, 0, 0, 10, 11, 12, 13, 14, 15},
|
||||||
|
{{10, 11, 12, 13, 14, 15}}},
|
||||||
|
|
||||||
|
{"Double",
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
{0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21},
|
||||||
|
{{10, 11, 12, 13, 14, 15}, {16, 17, 18, 19, 20, 21}}},
|
||||||
|
}),
|
||||||
|
[](const testing::TestParamInfo<TensorToJointsTest::ParamType>& info) {
|
||||||
|
return info.param.test_name;
|
||||||
|
});
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace api2
|
||||||
|
} // namespace mediapipe
|
||||||
@@ -110,8 +110,8 @@ absl::Status TensorsToClassificationCalculator::Open(CalculatorContext* cc) {
|
|||||||
sort_by_descending_score_ = options.sort_by_descending_score();
|
sort_by_descending_score_ = options.sort_by_descending_score();
|
||||||
if (options.has_label_map_path()) {
|
if (options.has_label_map_path()) {
|
||||||
std::string string_path;
|
std::string string_path;
|
||||||
ASSIGN_OR_RETURN(string_path,
|
MP_ASSIGN_OR_RETURN(string_path,
|
||||||
PathToResourceAsFile(options.label_map_path()));
|
PathToResourceAsFile(options.label_map_path()));
|
||||||
std::string label_map_string;
|
std::string label_map_string;
|
||||||
MP_RETURN_IF_ERROR(
|
MP_RETURN_IF_ERROR(
|
||||||
mediapipe::GetResourceContents(string_path, &label_map_string));
|
mediapipe::GetResourceContents(string_path, &label_map_string));
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "absl/strings/str_format.h"
|
#include "absl/strings/str_format.h"
|
||||||
#include "absl/types/span.h"
|
#include "absl/types/span.h"
|
||||||
#include "mediapipe/calculators/tensor/tensors_to_detections_calculator.pb.h"
|
#include "mediapipe/calculators/tensor/tensors_to_detections_calculator.pb.h"
|
||||||
@@ -83,7 +84,7 @@ void ConvertRawValuesToAnchors(const float* raw_anchors, int num_boxes,
|
|||||||
|
|
||||||
void ConvertAnchorsToRawValues(const std::vector<Anchor>& anchors,
|
void ConvertAnchorsToRawValues(const std::vector<Anchor>& anchors,
|
||||||
int num_boxes, float* raw_anchors) {
|
int num_boxes, float* raw_anchors) {
|
||||||
CHECK_EQ(anchors.size(), num_boxes);
|
ABSL_CHECK_EQ(anchors.size(), num_boxes);
|
||||||
int box = 0;
|
int box = 0;
|
||||||
for (const auto& anchor : anchors) {
|
for (const auto& anchor : anchors) {
|
||||||
raw_anchors[box * kNumCoordsPerBox + 0] = anchor.y_center();
|
raw_anchors[box * kNumCoordsPerBox + 0] = anchor.y_center();
|
||||||
@@ -329,7 +330,7 @@ absl::Status TensorsToDetectionsCalculator::Process(CalculatorContext* cc) {
|
|||||||
} else if (status.code() == absl::StatusCode::kFailedPrecondition) {
|
} else if (status.code() == absl::StatusCode::kFailedPrecondition) {
|
||||||
// For initialization error because of hardware limitation, fallback to
|
// For initialization error because of hardware limitation, fallback to
|
||||||
// CPU processing.
|
// CPU processing.
|
||||||
LOG(WARNING) << status.message();
|
ABSL_LOG(WARNING) << status.message();
|
||||||
} else {
|
} else {
|
||||||
// For other error, let the error propagates.
|
// For other error, let the error propagates.
|
||||||
return status;
|
return status;
|
||||||
@@ -668,7 +669,7 @@ absl::Status TensorsToDetectionsCalculator::ProcessGPU(
|
|||||||
output_detections));
|
output_detections));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
LOG(ERROR) << "GPU input on non-Android not supported yet.";
|
ABSL_LOG(ERROR) << "GPU input on non-Android not supported yet.";
|
||||||
#endif // !defined(MEDIAPIPE_DISABLE_GL_COMPUTE)
|
#endif // !defined(MEDIAPIPE_DISABLE_GL_COMPUTE)
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
@@ -703,18 +704,18 @@ absl::Status TensorsToDetectionsCalculator::LoadOptions(CalculatorContext* cc) {
|
|||||||
num_boxes_ = options_.num_boxes();
|
num_boxes_ = options_.num_boxes();
|
||||||
num_coords_ = options_.num_coords();
|
num_coords_ = options_.num_coords();
|
||||||
box_output_format_ = GetBoxFormat(options_);
|
box_output_format_ = GetBoxFormat(options_);
|
||||||
CHECK_NE(options_.max_results(), 0)
|
ABSL_CHECK_NE(options_.max_results(), 0)
|
||||||
<< "The maximum number of the top-scored detection results must be "
|
<< "The maximum number of the top-scored detection results must be "
|
||||||
"non-zero.";
|
"non-zero.";
|
||||||
max_results_ = options_.max_results();
|
max_results_ = options_.max_results();
|
||||||
|
|
||||||
// Currently only support 2D when num_values_per_keypoint equals to 2.
|
// Currently only support 2D when num_values_per_keypoint equals to 2.
|
||||||
CHECK_EQ(options_.num_values_per_keypoint(), 2);
|
ABSL_CHECK_EQ(options_.num_values_per_keypoint(), 2);
|
||||||
|
|
||||||
// Check if the output size is equal to the requested boxes and keypoints.
|
// Check if the output size is equal to the requested boxes and keypoints.
|
||||||
CHECK_EQ(options_.num_keypoints() * options_.num_values_per_keypoint() +
|
ABSL_CHECK_EQ(options_.num_keypoints() * options_.num_values_per_keypoint() +
|
||||||
kNumCoordsPerBox,
|
kNumCoordsPerBox,
|
||||||
num_coords_);
|
num_coords_);
|
||||||
|
|
||||||
if (kSideInIgnoreClasses(cc).IsConnected()) {
|
if (kSideInIgnoreClasses(cc).IsConnected()) {
|
||||||
RET_CHECK(!kSideInIgnoreClasses(cc).IsEmpty());
|
RET_CHECK(!kSideInIgnoreClasses(cc).IsEmpty());
|
||||||
@@ -1154,11 +1155,12 @@ void main() {
|
|||||||
}
|
}
|
||||||
// TODO support better filtering.
|
// TODO support better filtering.
|
||||||
if (class_index_set_.is_allowlist) {
|
if (class_index_set_.is_allowlist) {
|
||||||
CHECK_EQ(class_index_set_.values.size(),
|
ABSL_CHECK_EQ(class_index_set_.values.size(),
|
||||||
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
|
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
|
||||||
<< "Only all classes >= class 0 or >= class 1";
|
<< "Only all classes >= class 0 or >= class 1";
|
||||||
} else {
|
} else {
|
||||||
CHECK_EQ(class_index_set_.values.size(), IsClassIndexAllowed(0) ? 0 : 1)
|
ABSL_CHECK_EQ(class_index_set_.values.size(),
|
||||||
|
IsClassIndexAllowed(0) ? 0 : 1)
|
||||||
<< "Only ignore class 0 is allowed";
|
<< "Only ignore class 0 is allowed";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1379,11 +1381,12 @@ kernel void scoreKernel(
|
|||||||
|
|
||||||
// TODO support better filtering.
|
// TODO support better filtering.
|
||||||
if (class_index_set_.is_allowlist) {
|
if (class_index_set_.is_allowlist) {
|
||||||
CHECK_EQ(class_index_set_.values.size(),
|
ABSL_CHECK_EQ(class_index_set_.values.size(),
|
||||||
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
|
IsClassIndexAllowed(0) ? num_classes_ : num_classes_ - 1)
|
||||||
<< "Only all classes >= class 0 or >= class 1";
|
<< "Only all classes >= class 0 or >= class 1";
|
||||||
} else {
|
} else {
|
||||||
CHECK_EQ(class_index_set_.values.size(), IsClassIndexAllowed(0) ? 0 : 1)
|
ABSL_CHECK_EQ(class_index_set_.values.size(),
|
||||||
|
IsClassIndexAllowed(0) ? 0 : 1)
|
||||||
<< "Only ignore class 0 is allowed";
|
<< "Only ignore class 0 is allowed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ absl::Status TensorsToLandmarksCalculator::Process(CalculatorContext* cc) {
|
|||||||
RET_CHECK(input_tensors[0].element_type() == Tensor::ElementType::kFloat32);
|
RET_CHECK(input_tensors[0].element_type() == Tensor::ElementType::kFloat32);
|
||||||
int num_values = input_tensors[0].shape().num_elements();
|
int num_values = input_tensors[0].shape().num_elements();
|
||||||
const int num_dimensions = num_values / num_landmarks_;
|
const int num_dimensions = num_values / num_landmarks_;
|
||||||
CHECK_GT(num_dimensions, 0);
|
ABSL_CHECK_GT(num_dimensions, 0);
|
||||||
|
|
||||||
auto view = input_tensors[0].GetCpuReadView();
|
auto view = input_tensors[0].GetCpuReadView();
|
||||||
auto raw_landmarks = view.buffer<float>();
|
auto raw_landmarks = view.buffer<float>();
|
||||||
|
|||||||
@@ -174,6 +174,9 @@ class TensorsToSegmentationCalculator : public CalculatorBase {
|
|||||||
mediapipe::GlCalculatorHelper gpu_helper_;
|
mediapipe::GlCalculatorHelper gpu_helper_;
|
||||||
GLuint upsample_program_;
|
GLuint upsample_program_;
|
||||||
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
|
int cached_width_ = 0;
|
||||||
|
int cached_height_ = 0;
|
||||||
|
std::unique_ptr<tflite::gpu::gl::GlTexture> small_mask_texture_;
|
||||||
std::unique_ptr<GlProgram> mask_program_31_;
|
std::unique_ptr<GlProgram> mask_program_31_;
|
||||||
#else
|
#else
|
||||||
GLuint mask_program_20_;
|
GLuint mask_program_20_;
|
||||||
@@ -264,7 +267,8 @@ absl::Status TensorsToSegmentationCalculator::Process(CalculatorContext* cc) {
|
|||||||
{
|
{
|
||||||
RET_CHECK(!input_tensors.empty());
|
RET_CHECK(!input_tensors.empty());
|
||||||
RET_CHECK(input_tensors[0].element_type() == Tensor::ElementType::kFloat32);
|
RET_CHECK(input_tensors[0].element_type() == Tensor::ElementType::kFloat32);
|
||||||
ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims));
|
MP_ASSIGN_OR_RETURN(auto hwc,
|
||||||
|
GetHwcFromDims(input_tensors[0].shape().dims));
|
||||||
int tensor_channels = std::get<2>(hwc);
|
int tensor_channels = std::get<2>(hwc);
|
||||||
typedef mediapipe::TensorsToSegmentationCalculatorOptions Options;
|
typedef mediapipe::TensorsToSegmentationCalculatorOptions Options;
|
||||||
switch (options_.activation()) {
|
switch (options_.activation()) {
|
||||||
@@ -307,6 +311,7 @@ absl::Status TensorsToSegmentationCalculator::Close(CalculatorContext* cc) {
|
|||||||
upsample_program_ = 0;
|
upsample_program_ = 0;
|
||||||
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
mask_program_31_.reset();
|
mask_program_31_.reset();
|
||||||
|
small_mask_texture_.reset();
|
||||||
#else
|
#else
|
||||||
if (mask_program_20_) glDeleteProgram(mask_program_20_);
|
if (mask_program_20_) glDeleteProgram(mask_program_20_);
|
||||||
mask_program_20_ = 0;
|
mask_program_20_ = 0;
|
||||||
@@ -326,7 +331,7 @@ absl::Status TensorsToSegmentationCalculator::ProcessCpu(
|
|||||||
// Get input streams, and dimensions.
|
// Get input streams, and dimensions.
|
||||||
const auto& input_tensors =
|
const auto& input_tensors =
|
||||||
cc->Inputs().Tag(kTensorsTag).Get<std::vector<Tensor>>();
|
cc->Inputs().Tag(kTensorsTag).Get<std::vector<Tensor>>();
|
||||||
ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims));
|
MP_ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims));
|
||||||
auto [tensor_height, tensor_width, tensor_channels] = hwc;
|
auto [tensor_height, tensor_width, tensor_channels] = hwc;
|
||||||
int output_width = tensor_width, output_height = tensor_height;
|
int output_width = tensor_width, output_height = tensor_height;
|
||||||
if (cc->Inputs().HasTag(kOutputSizeTag)) {
|
if (cc->Inputs().HasTag(kOutputSizeTag)) {
|
||||||
@@ -437,7 +442,7 @@ absl::Status TensorsToSegmentationCalculator::ProcessGpu(
|
|||||||
// Get input streams, and dimensions.
|
// Get input streams, and dimensions.
|
||||||
const auto& input_tensors =
|
const auto& input_tensors =
|
||||||
cc->Inputs().Tag(kTensorsTag).Get<std::vector<Tensor>>();
|
cc->Inputs().Tag(kTensorsTag).Get<std::vector<Tensor>>();
|
||||||
ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims));
|
MP_ASSIGN_OR_RETURN(auto hwc, GetHwcFromDims(input_tensors[0].shape().dims));
|
||||||
auto [tensor_height, tensor_width, tensor_channels] = hwc;
|
auto [tensor_height, tensor_width, tensor_channels] = hwc;
|
||||||
int output_width = tensor_width, output_height = tensor_height;
|
int output_width = tensor_width, output_height = tensor_height;
|
||||||
if (cc->Inputs().HasTag(kOutputSizeTag)) {
|
if (cc->Inputs().HasTag(kOutputSizeTag)) {
|
||||||
@@ -448,21 +453,24 @@ absl::Status TensorsToSegmentationCalculator::ProcessGpu(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create initial working mask texture.
|
// Create initial working mask texture.
|
||||||
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#if !(MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31)
|
||||||
tflite::gpu::gl::GlTexture small_mask_texture;
|
|
||||||
#else
|
|
||||||
mediapipe::GlTexture small_mask_texture;
|
mediapipe::GlTexture small_mask_texture;
|
||||||
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
|
|
||||||
// Run shader, process mask tensor.
|
// Run shader, process mask tensor.
|
||||||
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
{
|
{
|
||||||
MP_RETURN_IF_ERROR(CreateReadWriteRgbaImageTexture(
|
// Only recreate if the size has changed. See b/297809673 for more details.
|
||||||
tflite::gpu::DataType::UINT8, // GL_RGBA8
|
if (tensor_width != cached_width_ || tensor_height != cached_height_) {
|
||||||
{tensor_width, tensor_height}, &small_mask_texture));
|
MP_RETURN_IF_ERROR(CreateReadWriteRgbaImageTexture(
|
||||||
|
tflite::gpu::DataType::UINT8, // GL_RGBA8
|
||||||
|
{tensor_width, tensor_height}, small_mask_texture_.get()));
|
||||||
|
cached_width_ = tensor_width;
|
||||||
|
cached_height_ = tensor_height;
|
||||||
|
}
|
||||||
|
|
||||||
const int output_index = 0;
|
const int output_index = 0;
|
||||||
glBindImageTexture(output_index, small_mask_texture.id(), 0, GL_FALSE, 0,
|
glBindImageTexture(output_index, small_mask_texture_->id(), 0, GL_FALSE, 0,
|
||||||
GL_WRITE_ONLY, GL_RGBA8);
|
GL_WRITE_ONLY, GL_RGBA8);
|
||||||
|
|
||||||
auto read_view = input_tensors[0].GetOpenGlBufferReadView();
|
auto read_view = input_tensors[0].GetOpenGlBufferReadView();
|
||||||
@@ -547,7 +555,7 @@ absl::Status TensorsToSegmentationCalculator::ProcessGpu(
|
|||||||
gpu_helper_.BindFramebuffer(output_texture);
|
gpu_helper_.BindFramebuffer(output_texture);
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
glBindTexture(GL_TEXTURE_2D, small_mask_texture.id());
|
glBindTexture(GL_TEXTURE_2D, small_mask_texture_->id());
|
||||||
#else
|
#else
|
||||||
glBindTexture(GL_TEXTURE_2D, small_mask_texture.name());
|
glBindTexture(GL_TEXTURE_2D, small_mask_texture.name());
|
||||||
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||||
@@ -854,6 +862,7 @@ void main() {
|
|||||||
mask_program_31_ = absl::make_unique<GlProgram>();
|
mask_program_31_ = absl::make_unique<GlProgram>();
|
||||||
MP_RETURN_IF_ERROR(GlProgram::CreateWithShader(shader_without_previous,
|
MP_RETURN_IF_ERROR(GlProgram::CreateWithShader(shader_without_previous,
|
||||||
mask_program_31_.get()));
|
mask_program_31_.get()));
|
||||||
|
small_mask_texture_ = absl::make_unique<tflite::gpu::gl::GlTexture>();
|
||||||
#elif MEDIAPIPE_METAL_ENABLED
|
#elif MEDIAPIPE_METAL_ENABLED
|
||||||
id<MTLDevice> device = metal_helper_.mtlDevice;
|
id<MTLDevice> device = metal_helper_.mtlDevice;
|
||||||
NSString* library_source =
|
NSString* library_source =
|
||||||
|
|||||||
+4
-3
@@ -61,9 +61,10 @@ RunUniversalSentenceEncoderPreprocessorCalculator(absl::string_view text) {
|
|||||||
|
|
||||||
std::string model_buffer =
|
std::string model_buffer =
|
||||||
tasks::core::LoadBinaryContent(kTestModelPath.data());
|
tasks::core::LoadBinaryContent(kTestModelPath.data());
|
||||||
ASSIGN_OR_RETURN(std::unique_ptr<ModelMetadataExtractor> metadata_extractor,
|
MP_ASSIGN_OR_RETURN(
|
||||||
ModelMetadataExtractor::CreateFromModelBuffer(
|
std::unique_ptr<ModelMetadataExtractor> metadata_extractor,
|
||||||
model_buffer.data(), model_buffer.size()));
|
ModelMetadataExtractor::CreateFromModelBuffer(model_buffer.data(),
|
||||||
|
model_buffer.size()));
|
||||||
// Run the graph.
|
// Run the graph.
|
||||||
CalculatorGraph graph;
|
CalculatorGraph graph;
|
||||||
MP_RETURN_IF_ERROR(graph.Initialize(
|
MP_RETURN_IF_ERROR(graph.Initialize(
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# Placeholder: load py_proto_library
|
||||||
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library", "mediapipe_proto_library")
|
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library", "mediapipe_proto_library")
|
||||||
|
|
||||||
licenses(["notice"])
|
licenses(["notice"])
|
||||||
@@ -314,6 +315,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
] + select({
|
] + select({
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
"@org_tensorflow//tensorflow/core:framework",
|
"@org_tensorflow//tensorflow/core:framework",
|
||||||
@@ -366,18 +368,18 @@ cc_library(
|
|||||||
name = "pack_media_sequence_calculator",
|
name = "pack_media_sequence_calculator",
|
||||||
srcs = ["pack_media_sequence_calculator.cc"],
|
srcs = ["pack_media_sequence_calculator.cc"],
|
||||||
deps = [
|
deps = [
|
||||||
|
":pack_media_sequence_calculator_cc_proto",
|
||||||
"//mediapipe/calculators/image:opencv_image_encoder_calculator_cc_proto",
|
"//mediapipe/calculators/image:opencv_image_encoder_calculator_cc_proto",
|
||||||
"//mediapipe/calculators/tensorflow:pack_media_sequence_calculator_cc_proto",
|
|
||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/formats:detection_cc_proto",
|
"//mediapipe/framework/formats:detection_cc_proto",
|
||||||
"//mediapipe/framework/formats:location",
|
"//mediapipe/framework/formats:location",
|
||||||
"//mediapipe/framework/formats:location_opencv",
|
"//mediapipe/framework/formats:location_opencv",
|
||||||
"//mediapipe/framework/port:opencv_imgcodecs",
|
"//mediapipe/framework/port:opencv_imgcodecs",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
|
||||||
"//mediapipe/util/sequence:media_sequence",
|
"//mediapipe/util/sequence:media_sequence",
|
||||||
"//mediapipe/util/sequence:media_sequence_util",
|
"//mediapipe/util/sequence:media_sequence_util",
|
||||||
"@com_google_absl//absl/container:flat_hash_map",
|
"@com_google_absl//absl/container:flat_hash_map",
|
||||||
|
"@com_google_absl//absl/status",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
||||||
],
|
],
|
||||||
@@ -429,7 +431,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/tool:status_util",
|
"//mediapipe/framework/tool:status_util",
|
||||||
"@com_google_absl//absl/base:core_headers",
|
"@com_google_absl//absl/base:core_headers",
|
||||||
"@com_google_absl//absl/log:check",
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@com_google_absl//absl/synchronization",
|
"@com_google_absl//absl/synchronization",
|
||||||
@@ -488,10 +490,10 @@ cc_library(
|
|||||||
"//mediapipe/calculators/tensorflow:tensorflow_session_from_frozen_graph_calculator_cc_proto",
|
"//mediapipe/calculators/tensorflow:tensorflow_session_from_frozen_graph_calculator_cc_proto",
|
||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/deps:clock",
|
"//mediapipe/framework/deps:clock",
|
||||||
"//mediapipe/framework/port:logging",
|
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/tool:status_util",
|
"//mediapipe/framework/tool:status_util",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
||||||
] + select({
|
] + select({
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
@@ -519,10 +521,10 @@ cc_library(
|
|||||||
":tensorflow_session_from_frozen_graph_generator_cc_proto",
|
":tensorflow_session_from_frozen_graph_generator_cc_proto",
|
||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/deps:clock",
|
"//mediapipe/framework/deps:clock",
|
||||||
"//mediapipe/framework/port:logging",
|
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/tool:status_util",
|
"//mediapipe/framework/tool:status_util",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
||||||
] + select({
|
] + select({
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
@@ -555,6 +557,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/deps:file_path",
|
"//mediapipe/framework/deps:file_path",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@org_tensorflow//tensorflow/cc/saved_model:constants",
|
"@org_tensorflow//tensorflow/cc/saved_model:constants",
|
||||||
"@org_tensorflow//tensorflow/cc/saved_model:loader_lite",
|
"@org_tensorflow//tensorflow/cc/saved_model:loader_lite",
|
||||||
@@ -632,6 +635,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/tool:status_util",
|
"//mediapipe/framework/tool:status_util",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/status",
|
"@com_google_absl//absl/status",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@org_tensorflow//tensorflow/cc/saved_model:constants",
|
"@org_tensorflow//tensorflow/cc/saved_model:constants",
|
||||||
@@ -653,6 +657,7 @@ cc_library(
|
|||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@org_tensorflow//tensorflow/core:framework",
|
"@org_tensorflow//tensorflow/core:framework",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
@@ -667,6 +672,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:image_frame",
|
"//mediapipe/framework/formats:image_frame",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@org_tensorflow//tensorflow/core:framework",
|
"@org_tensorflow//tensorflow/core:framework",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
@@ -682,6 +688,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
"//mediapipe/framework/formats:time_series_header_cc_proto",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
] + select({
|
] + select({
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
"@org_tensorflow//tensorflow/core:framework",
|
"@org_tensorflow//tensorflow/core:framework",
|
||||||
@@ -716,6 +723,7 @@ cc_library(
|
|||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@org_tensorflow//tensorflow/core/platform:bfloat16",
|
||||||
] + select({
|
] + select({
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
"@org_tensorflow//tensorflow/core:framework",
|
"@org_tensorflow//tensorflow/core:framework",
|
||||||
@@ -778,6 +786,7 @@ cc_library(
|
|||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/util:audio_decoder_cc_proto",
|
"//mediapipe/util:audio_decoder_cc_proto",
|
||||||
"//mediapipe/util/sequence:media_sequence",
|
"//mediapipe/util/sequence:media_sequence",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
||||||
],
|
],
|
||||||
@@ -792,6 +801,8 @@ cc_library(
|
|||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@org_tensorflow//tensorflow/core:framework",
|
"@org_tensorflow//tensorflow/core:framework",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
@@ -805,6 +816,7 @@ cc_library(
|
|||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@org_tensorflow//tensorflow/core:framework",
|
"@org_tensorflow//tensorflow/core:framework",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
@@ -818,6 +830,7 @@ cc_library(
|
|||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@org_tensorflow//tensorflow/core:framework",
|
"@org_tensorflow//tensorflow/core:framework",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
@@ -831,6 +844,8 @@ cc_library(
|
|||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework:packet",
|
"//mediapipe/framework:packet",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
@@ -925,21 +940,24 @@ cc_test(
|
|||||||
srcs = ["pack_media_sequence_calculator_test.cc"],
|
srcs = ["pack_media_sequence_calculator_test.cc"],
|
||||||
deps = [
|
deps = [
|
||||||
":pack_media_sequence_calculator",
|
":pack_media_sequence_calculator",
|
||||||
|
":pack_media_sequence_calculator_cc_proto",
|
||||||
"//mediapipe/calculators/image:opencv_image_encoder_calculator_cc_proto",
|
"//mediapipe/calculators/image:opencv_image_encoder_calculator_cc_proto",
|
||||||
"//mediapipe/calculators/tensorflow:pack_media_sequence_calculator_cc_proto",
|
|
||||||
"//mediapipe/framework:calculator_framework",
|
"//mediapipe/framework:calculator_framework",
|
||||||
"//mediapipe/framework:calculator_runner",
|
"//mediapipe/framework:calculator_runner",
|
||||||
|
"//mediapipe/framework:packet",
|
||||||
"//mediapipe/framework:timestamp",
|
"//mediapipe/framework:timestamp",
|
||||||
"//mediapipe/framework/formats:detection_cc_proto",
|
"//mediapipe/framework/formats:detection_cc_proto",
|
||||||
"//mediapipe/framework/formats:image_frame",
|
|
||||||
"//mediapipe/framework/formats:location",
|
"//mediapipe/framework/formats:location",
|
||||||
"//mediapipe/framework/formats:location_opencv",
|
"//mediapipe/framework/formats:location_opencv",
|
||||||
"//mediapipe/framework/port:gtest_main",
|
"//mediapipe/framework/port:gtest_main",
|
||||||
"//mediapipe/framework/port:opencv_imgcodecs",
|
"//mediapipe/framework/port:opencv_imgcodecs",
|
||||||
"//mediapipe/util/sequence:media_sequence",
|
"//mediapipe/util/sequence:media_sequence",
|
||||||
"@com_google_absl//absl/container:flat_hash_map",
|
"//mediapipe/util/sequence:media_sequence_util",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
|
"@com_google_absl//absl/status",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
|
"@com_google_googletest//:gtest_main",
|
||||||
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -1122,6 +1140,7 @@ cc_test(
|
|||||||
"//mediapipe/util:packet_test_util",
|
"//mediapipe/util:packet_test_util",
|
||||||
"@org_tensorflow//tensorflow/core:framework",
|
"@org_tensorflow//tensorflow/core:framework",
|
||||||
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
||||||
|
"@org_tensorflow//tensorflow/core/platform:bfloat16",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1167,6 +1186,7 @@ cc_test(
|
|||||||
"//mediapipe/framework/port:rectangle",
|
"//mediapipe/framework/port:rectangle",
|
||||||
"//mediapipe/util:audio_decoder_cc_proto",
|
"//mediapipe/util:audio_decoder_cc_proto",
|
||||||
"//mediapipe/util/sequence:media_sequence",
|
"//mediapipe/util/sequence:media_sequence",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
||||||
@@ -1248,6 +1268,8 @@ cc_test(
|
|||||||
"//mediapipe/framework/tool:sink",
|
"//mediapipe/framework/tool:sink",
|
||||||
"//mediapipe/framework/tool:validate_type",
|
"//mediapipe/framework/tool:validate_type",
|
||||||
"@com_google_absl//absl/flags:flag",
|
"@com_google_absl//absl/flags:flag",
|
||||||
|
"@com_google_absl//absl/log:absl_check",
|
||||||
|
"@com_google_absl//absl/log:absl_log",
|
||||||
] + select({
|
] + select({
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
"@org_tensorflow//tensorflow/core:direct_session",
|
"@org_tensorflow//tensorflow/core:direct_session",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "mediapipe/calculators/tensorflow/matrix_to_tensor_calculator_options.pb.h"
|
#include "mediapipe/calculators/tensorflow/matrix_to_tensor_calculator_options.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/formats/matrix.h"
|
#include "mediapipe/framework/formats/matrix.h"
|
||||||
@@ -28,7 +29,7 @@ namespace mediapipe {
|
|||||||
namespace {
|
namespace {
|
||||||
absl::Status FillTimeSeriesHeaderIfValid(const Packet& header_packet,
|
absl::Status FillTimeSeriesHeaderIfValid(const Packet& header_packet,
|
||||||
TimeSeriesHeader* header) {
|
TimeSeriesHeader* header) {
|
||||||
CHECK(header);
|
ABSL_CHECK(header);
|
||||||
if (header_packet.IsEmpty()) {
|
if (header_packet.IsEmpty()) {
|
||||||
return absl::UnknownError("No header found.");
|
return absl::UnknownError("No header found.");
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -151,7 +151,7 @@ class ObjectDetectionTensorsToDetectionsCalculator : public CalculatorBase {
|
|||||||
tf::Tensor input_num_detections_tensor =
|
tf::Tensor input_num_detections_tensor =
|
||||||
tf::Tensor(tf::DT_FLOAT, tf::TensorShape({0}));
|
tf::Tensor(tf::DT_FLOAT, tf::TensorShape({0}));
|
||||||
if (cc->Inputs().HasTag(kClasses)) {
|
if (cc->Inputs().HasTag(kClasses)) {
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
input_num_detections_tensor,
|
input_num_detections_tensor,
|
||||||
MaybeSqueezeDims(kNumDetections,
|
MaybeSqueezeDims(kNumDetections,
|
||||||
cc->Inputs().Tag(kNumDetections).Get<tf::Tensor>()));
|
cc->Inputs().Tag(kNumDetections).Get<tf::Tensor>()));
|
||||||
@@ -160,12 +160,12 @@ class ObjectDetectionTensorsToDetectionsCalculator : public CalculatorBase {
|
|||||||
RET_CHECK_EQ(input_num_detections_tensor.dtype(), tf::DT_FLOAT);
|
RET_CHECK_EQ(input_num_detections_tensor.dtype(), tf::DT_FLOAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
auto input_boxes_tensor,
|
auto input_boxes_tensor,
|
||||||
MaybeSqueezeDims(kBoxes, cc->Inputs().Tag(kBoxes).Get<tf::Tensor>()));
|
MaybeSqueezeDims(kBoxes, cc->Inputs().Tag(kBoxes).Get<tf::Tensor>()));
|
||||||
RET_CHECK_EQ(input_boxes_tensor.dtype(), tf::DT_FLOAT);
|
RET_CHECK_EQ(input_boxes_tensor.dtype(), tf::DT_FLOAT);
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
auto input_scores_tensor,
|
auto input_scores_tensor,
|
||||||
MaybeSqueezeDims(kScores, cc->Inputs().Tag(kScores).Get<tf::Tensor>()));
|
MaybeSqueezeDims(kScores, cc->Inputs().Tag(kScores).Get<tf::Tensor>()));
|
||||||
RET_CHECK_EQ(input_scores_tensor.dtype(), tf::DT_FLOAT);
|
RET_CHECK_EQ(input_scores_tensor.dtype(), tf::DT_FLOAT);
|
||||||
@@ -173,7 +173,7 @@ class ObjectDetectionTensorsToDetectionsCalculator : public CalculatorBase {
|
|||||||
tf::Tensor input_classes_tensor =
|
tf::Tensor input_classes_tensor =
|
||||||
tf::Tensor(tf::DT_FLOAT, tf::TensorShape({0}));
|
tf::Tensor(tf::DT_FLOAT, tf::TensorShape({0}));
|
||||||
if (cc->Inputs().HasTag(kClasses)) {
|
if (cc->Inputs().HasTag(kClasses)) {
|
||||||
ASSIGN_OR_RETURN(
|
MP_ASSIGN_OR_RETURN(
|
||||||
input_classes_tensor,
|
input_classes_tensor,
|
||||||
MaybeSqueezeDims(kClasses,
|
MaybeSqueezeDims(kClasses,
|
||||||
cc->Inputs().Tag(kClasses).Get<tf::Tensor>()));
|
cc->Inputs().Tag(kClasses).Get<tf::Tensor>()));
|
||||||
|
|||||||
@@ -12,21 +12,23 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/container/flat_hash_map.h"
|
#include "absl/container/flat_hash_map.h"
|
||||||
|
#include "absl/status/status.h"
|
||||||
#include "absl/strings/match.h"
|
#include "absl/strings/match.h"
|
||||||
|
#include "absl/strings/strip.h"
|
||||||
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
|
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
|
||||||
#include "mediapipe/calculators/tensorflow/pack_media_sequence_calculator.pb.h"
|
#include "mediapipe/calculators/tensorflow/pack_media_sequence_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/formats/detection.pb.h"
|
#include "mediapipe/framework/formats/detection.pb.h"
|
||||||
#include "mediapipe/framework/formats/location.h"
|
#include "mediapipe/framework/formats/location.h"
|
||||||
#include "mediapipe/framework/formats/location_opencv.h"
|
#include "mediapipe/framework/formats/location_opencv.h"
|
||||||
#include "mediapipe/framework/port/canonical_errors.h"
|
|
||||||
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
|
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
|
||||||
#include "mediapipe/framework/port/ret_check.h"
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
#include "mediapipe/framework/port/status.h"
|
|
||||||
#include "mediapipe/util/sequence/media_sequence.h"
|
#include "mediapipe/util/sequence/media_sequence.h"
|
||||||
#include "mediapipe/util/sequence/media_sequence_util.h"
|
#include "mediapipe/util/sequence/media_sequence_util.h"
|
||||||
#include "tensorflow/core/example/example.pb.h"
|
#include "tensorflow/core/example/example.pb.h"
|
||||||
@@ -36,7 +38,11 @@ namespace mediapipe {
|
|||||||
|
|
||||||
const char kSequenceExampleTag[] = "SEQUENCE_EXAMPLE";
|
const char kSequenceExampleTag[] = "SEQUENCE_EXAMPLE";
|
||||||
const char kImageTag[] = "IMAGE";
|
const char kImageTag[] = "IMAGE";
|
||||||
|
const char kImageLabelPrefixTag[] = "IMAGE_LABEL_";
|
||||||
|
const char kClipLabelPrefixTag[] = "CLIP_LABEL_";
|
||||||
const char kFloatContextFeaturePrefixTag[] = "FLOAT_CONTEXT_FEATURE_";
|
const char kFloatContextFeaturePrefixTag[] = "FLOAT_CONTEXT_FEATURE_";
|
||||||
|
const char kIntsContextFeaturePrefixTag[] = "INTS_CONTEXT_FEATURE_";
|
||||||
|
const char kBytesContextFeaturePrefixTag[] = "BYTES_CONTEXT_FEATURE_";
|
||||||
const char kFloatFeaturePrefixTag[] = "FLOAT_FEATURE_";
|
const char kFloatFeaturePrefixTag[] = "FLOAT_FEATURE_";
|
||||||
const char kIntFeaturePrefixTag[] = "INT_FEATURE_";
|
const char kIntFeaturePrefixTag[] = "INT_FEATURE_";
|
||||||
const char kBytesFeaturePrefixTag[] = "BYTES_FEATURE_";
|
const char kBytesFeaturePrefixTag[] = "BYTES_FEATURE_";
|
||||||
@@ -44,6 +50,7 @@ const char kForwardFlowEncodedTag[] = "FORWARD_FLOW_ENCODED";
|
|||||||
const char kBBoxTag[] = "BBOX";
|
const char kBBoxTag[] = "BBOX";
|
||||||
const char kKeypointsTag[] = "KEYPOINTS";
|
const char kKeypointsTag[] = "KEYPOINTS";
|
||||||
const char kSegmentationMaskTag[] = "CLASS_SEGMENTATION";
|
const char kSegmentationMaskTag[] = "CLASS_SEGMENTATION";
|
||||||
|
const char kClipMediaIdTag[] = "CLIP_MEDIA_ID";
|
||||||
|
|
||||||
namespace tf = ::tensorflow;
|
namespace tf = ::tensorflow;
|
||||||
namespace mpms = mediapipe::mediasequence;
|
namespace mpms = mediapipe::mediasequence;
|
||||||
@@ -55,16 +62,24 @@ namespace mpms = mediapipe::mediasequence;
|
|||||||
// context features can be supplied verbatim in the calculator's options. The
|
// context features can be supplied verbatim in the calculator's options. The
|
||||||
// SequenceExample will conform to the description in media_sequence.h.
|
// SequenceExample will conform to the description in media_sequence.h.
|
||||||
//
|
//
|
||||||
// The supported input stream tags are "IMAGE", which stores the encoded
|
// The supported input stream tags are:
|
||||||
// images from the OpenCVImageEncoderCalculator, "FORWARD_FLOW_ENCODED", which
|
// * "IMAGE", which stores the encoded images from the
|
||||||
// stores the encoded optical flow from the same calculator, "BBOX" which stores
|
// OpenCVImageEncoderCalculator,
|
||||||
// bounding boxes from vector<Detections>, and streams with the
|
// * "IMAGE_LABEL", which stores whole image labels from Detection,
|
||||||
// "FLOAT_FEATURE_${NAME}" pattern, which stores the values from vector<float>'s
|
// * "FORWARD_FLOW_ENCODED", which stores the encoded optical flow from the same
|
||||||
// associated with the name ${NAME}. "KEYPOINTS" stores a map of 2D keypoints
|
// calculator,
|
||||||
// from flat_hash_map<string, vector<pair<float, float>>>. "IMAGE_${NAME}",
|
// * "BBOX" which stores bounding boxes from vector<Detections>,
|
||||||
// "BBOX_${NAME}", and "KEYPOINTS_${NAME}" will also store prefixed versions of
|
// * streams with the "FLOAT_FEATURE_${NAME}" pattern, which stores the values
|
||||||
// each stream, which allows for multiple image streams to be included. However,
|
// from vector<float>'s associated with the name ${NAME},
|
||||||
// the default names are suppored by more tools.
|
// * "KEYPOINTS" stores a map of 2D keypoints from flat_hash_map<string,
|
||||||
|
// vector<pair<float, float>>>,
|
||||||
|
// * "CLIP_MEDIA_ID", which stores the clip's media ID as a string.
|
||||||
|
// * "CLIP_LABEL_${NAME}" which stores sparse feature labels, ID and scores in
|
||||||
|
// mediapipe::Detection. In the input Detection, the score field is required,
|
||||||
|
// and label and label_id are optional but at least one of them should be set.
|
||||||
|
// "IMAGE_${NAME}", "BBOX_${NAME}", and "KEYPOINTS_${NAME}" will also store
|
||||||
|
// prefixed versions of each stream, which allows for multiple image streams to
|
||||||
|
// be included. However, the default names are suppored by more tools.
|
||||||
//
|
//
|
||||||
// Example config:
|
// Example config:
|
||||||
// node {
|
// node {
|
||||||
@@ -100,6 +115,9 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
static absl::Status GetContract(CalculatorContract* cc) {
|
static absl::Status GetContract(CalculatorContract* cc) {
|
||||||
RET_CHECK(cc->InputSidePackets().HasTag(kSequenceExampleTag));
|
RET_CHECK(cc->InputSidePackets().HasTag(kSequenceExampleTag));
|
||||||
cc->InputSidePackets().Tag(kSequenceExampleTag).Set<tf::SequenceExample>();
|
cc->InputSidePackets().Tag(kSequenceExampleTag).Set<tf::SequenceExample>();
|
||||||
|
if (cc->InputSidePackets().HasTag(kClipMediaIdTag)) {
|
||||||
|
cc->InputSidePackets().Tag(kClipMediaIdTag).Set<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
if (cc->Inputs().HasTag(kForwardFlowEncodedTag)) {
|
if (cc->Inputs().HasTag(kForwardFlowEncodedTag)) {
|
||||||
cc->Inputs()
|
cc->Inputs()
|
||||||
@@ -112,6 +130,10 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
|
|
||||||
for (const auto& tag : cc->Inputs().GetTags()) {
|
for (const auto& tag : cc->Inputs().GetTags()) {
|
||||||
if (absl::StartsWith(tag, kImageTag)) {
|
if (absl::StartsWith(tag, kImageTag)) {
|
||||||
|
if (absl::StartsWith(tag, kImageLabelPrefixTag)) {
|
||||||
|
cc->Inputs().Tag(tag).Set<Detection>();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
std::string key = "";
|
std::string key = "";
|
||||||
if (tag != kImageTag) {
|
if (tag != kImageTag) {
|
||||||
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
|
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
|
||||||
@@ -150,9 +172,18 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
}
|
}
|
||||||
cc->Inputs().Tag(tag).Set<std::vector<Detection>>();
|
cc->Inputs().Tag(tag).Set<std::vector<Detection>>();
|
||||||
}
|
}
|
||||||
|
if (absl::StartsWith(tag, kClipLabelPrefixTag)) {
|
||||||
|
cc->Inputs().Tag(tag).Set<Detection>();
|
||||||
|
}
|
||||||
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag)) {
|
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag)) {
|
||||||
cc->Inputs().Tag(tag).Set<std::vector<float>>();
|
cc->Inputs().Tag(tag).Set<std::vector<float>>();
|
||||||
}
|
}
|
||||||
|
if (absl::StartsWith(tag, kIntsContextFeaturePrefixTag)) {
|
||||||
|
cc->Inputs().Tag(tag).Set<std::vector<int64_t>>();
|
||||||
|
}
|
||||||
|
if (absl::StartsWith(tag, kBytesContextFeaturePrefixTag)) {
|
||||||
|
cc->Inputs().Tag(tag).Set<std::vector<std::string>>();
|
||||||
|
}
|
||||||
if (absl::StartsWith(tag, kFloatFeaturePrefixTag)) {
|
if (absl::StartsWith(tag, kFloatFeaturePrefixTag)) {
|
||||||
cc->Inputs().Tag(tag).Set<std::vector<float>>();
|
cc->Inputs().Tag(tag).Set<std::vector<float>>();
|
||||||
}
|
}
|
||||||
@@ -184,6 +215,11 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
cc->InputSidePackets()
|
cc->InputSidePackets()
|
||||||
.Tag(kSequenceExampleTag)
|
.Tag(kSequenceExampleTag)
|
||||||
.Get<tf::SequenceExample>());
|
.Get<tf::SequenceExample>());
|
||||||
|
if (cc->InputSidePackets().HasTag(kClipMediaIdTag) &&
|
||||||
|
!cc->InputSidePackets().Tag(kClipMediaIdTag).IsEmpty()) {
|
||||||
|
clip_media_id_ =
|
||||||
|
cc->InputSidePackets().Tag(kClipMediaIdTag).Get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
const auto& context_features =
|
const auto& context_features =
|
||||||
cc->Options<PackMediaSequenceCalculatorOptions>().context_feature_map();
|
cc->Options<PackMediaSequenceCalculatorOptions>().context_feature_map();
|
||||||
@@ -197,8 +233,19 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
replace_keypoints_ = false;
|
replace_keypoints_ = false;
|
||||||
if (cc->Options<PackMediaSequenceCalculatorOptions>()
|
if (cc->Options<PackMediaSequenceCalculatorOptions>()
|
||||||
.replace_data_instead_of_append()) {
|
.replace_data_instead_of_append()) {
|
||||||
|
// Clear the existing values under the same key.
|
||||||
for (const auto& tag : cc->Inputs().GetTags()) {
|
for (const auto& tag : cc->Inputs().GetTags()) {
|
||||||
if (absl::StartsWith(tag, kImageTag)) {
|
if (absl::StartsWith(tag, kImageTag)) {
|
||||||
|
if (absl::StartsWith(tag, kImageLabelPrefixTag)) {
|
||||||
|
std::string key =
|
||||||
|
std::string(absl::StripPrefix(tag, kImageLabelPrefixTag));
|
||||||
|
mpms::ClearImageLabelString(key, sequence_.get());
|
||||||
|
mpms::ClearImageLabelConfidence(key, sequence_.get());
|
||||||
|
if (!key.empty() || mpms::HasImageEncoded(*sequence_)) {
|
||||||
|
mpms::ClearImageTimestamp(key, sequence_.get());
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
std::string key = "";
|
std::string key = "";
|
||||||
if (tag != kImageTag) {
|
if (tag != kImageTag) {
|
||||||
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
|
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
|
||||||
@@ -227,12 +274,41 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
mpms::ClearBBoxNumRegions(key, sequence_.get());
|
mpms::ClearBBoxNumRegions(key, sequence_.get());
|
||||||
mpms::ClearBBoxLabelString(key, sequence_.get());
|
mpms::ClearBBoxLabelString(key, sequence_.get());
|
||||||
mpms::ClearBBoxLabelIndex(key, sequence_.get());
|
mpms::ClearBBoxLabelIndex(key, sequence_.get());
|
||||||
|
mpms::ClearBBoxLabelConfidence(key, sequence_.get());
|
||||||
mpms::ClearBBoxClassString(key, sequence_.get());
|
mpms::ClearBBoxClassString(key, sequence_.get());
|
||||||
mpms::ClearBBoxClassIndex(key, sequence_.get());
|
mpms::ClearBBoxClassIndex(key, sequence_.get());
|
||||||
mpms::ClearBBoxTrackString(key, sequence_.get());
|
mpms::ClearBBoxTrackString(key, sequence_.get());
|
||||||
mpms::ClearBBoxTrackIndex(key, sequence_.get());
|
mpms::ClearBBoxTrackIndex(key, sequence_.get());
|
||||||
mpms::ClearUnmodifiedBBoxTimestamp(key, sequence_.get());
|
mpms::ClearUnmodifiedBBoxTimestamp(key, sequence_.get());
|
||||||
}
|
}
|
||||||
|
if (absl::StartsWith(tag, kClipLabelPrefixTag)) {
|
||||||
|
const std::string& key = tag.substr(
|
||||||
|
sizeof(kClipLabelPrefixTag) / sizeof(*kClipLabelPrefixTag) - 1);
|
||||||
|
mpms::ClearClipLabelIndex(key, sequence_.get());
|
||||||
|
mpms::ClearClipLabelString(key, sequence_.get());
|
||||||
|
mpms::ClearClipLabelConfidence(key, sequence_.get());
|
||||||
|
}
|
||||||
|
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag)) {
|
||||||
|
const std::string& key =
|
||||||
|
tag.substr(sizeof(kFloatContextFeaturePrefixTag) /
|
||||||
|
sizeof(*kFloatContextFeaturePrefixTag) -
|
||||||
|
1);
|
||||||
|
mpms::ClearContextFeatureFloats(key, sequence_.get());
|
||||||
|
}
|
||||||
|
if (absl::StartsWith(tag, kIntsContextFeaturePrefixTag)) {
|
||||||
|
const std::string& key =
|
||||||
|
tag.substr(sizeof(kIntsContextFeaturePrefixTag) /
|
||||||
|
sizeof(*kIntsContextFeaturePrefixTag) -
|
||||||
|
1);
|
||||||
|
mpms::ClearContextFeatureInts(key, sequence_.get());
|
||||||
|
}
|
||||||
|
if (absl::StartsWith(tag, kBytesContextFeaturePrefixTag)) {
|
||||||
|
const std::string& key =
|
||||||
|
tag.substr(sizeof(kBytesContextFeaturePrefixTag) /
|
||||||
|
sizeof(*kBytesContextFeaturePrefixTag) -
|
||||||
|
1);
|
||||||
|
mpms::ClearContextFeatureBytes(key, sequence_.get());
|
||||||
|
}
|
||||||
if (absl::StartsWith(tag, kFloatFeaturePrefixTag)) {
|
if (absl::StartsWith(tag, kFloatFeaturePrefixTag)) {
|
||||||
std::string key = tag.substr(sizeof(kFloatFeaturePrefixTag) /
|
std::string key = tag.substr(sizeof(kFloatFeaturePrefixTag) /
|
||||||
sizeof(*kFloatFeaturePrefixTag) -
|
sizeof(*kFloatFeaturePrefixTag) -
|
||||||
@@ -343,6 +419,34 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
if (absl::StartsWith(tag, kImageTag) &&
|
if (absl::StartsWith(tag, kImageTag) &&
|
||||||
!cc->Inputs().Tag(tag).IsEmpty()) {
|
!cc->Inputs().Tag(tag).IsEmpty()) {
|
||||||
std::string key = "";
|
std::string key = "";
|
||||||
|
if (absl::StartsWith(tag, kImageLabelPrefixTag)) {
|
||||||
|
std::string key =
|
||||||
|
std::string(absl::StripPrefix(tag, kImageLabelPrefixTag));
|
||||||
|
const auto& detection = cc->Inputs().Tag(tag).Get<Detection>();
|
||||||
|
if (detection.label().empty()) continue;
|
||||||
|
RET_CHECK(detection.label_size() == detection.score_size())
|
||||||
|
<< "Wrong image label data format: " << detection.label_size()
|
||||||
|
<< " vs " << detection.score_size();
|
||||||
|
if (!detection.label_id().empty()) {
|
||||||
|
RET_CHECK(detection.label_id_size() == detection.label_size())
|
||||||
|
<< "Wrong image label ID format: " << detection.label_id_size()
|
||||||
|
<< " vs " << detection.label_size();
|
||||||
|
}
|
||||||
|
std::vector<std::string> labels(detection.label().begin(),
|
||||||
|
detection.label().end());
|
||||||
|
std::vector<float> confidences(detection.score().begin(),
|
||||||
|
detection.score().end());
|
||||||
|
std::vector<int32_t> ids(detection.label_id().begin(),
|
||||||
|
detection.label_id().end());
|
||||||
|
if (!key.empty() || mpms::HasImageEncoded(*sequence_)) {
|
||||||
|
mpms::AddImageTimestamp(key, cc->InputTimestamp().Value(),
|
||||||
|
sequence_.get());
|
||||||
|
}
|
||||||
|
mpms::AddImageLabelString(key, labels, sequence_.get());
|
||||||
|
mpms::AddImageLabelConfidence(key, confidences, sequence_.get());
|
||||||
|
if (!ids.empty()) mpms::AddImageLabelIndex(key, ids, sequence_.get());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (tag != kImageTag) {
|
if (tag != kImageTag) {
|
||||||
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
|
int tag_length = sizeof(kImageTag) / sizeof(*kImageTag) - 1;
|
||||||
if (tag[tag_length] == '_') {
|
if (tag[tag_length] == '_') {
|
||||||
@@ -393,6 +497,7 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
mpms::ClearBBoxNumRegions(prefix, sequence_.get());
|
mpms::ClearBBoxNumRegions(prefix, sequence_.get());
|
||||||
mpms::ClearBBoxLabelString(prefix, sequence_.get());
|
mpms::ClearBBoxLabelString(prefix, sequence_.get());
|
||||||
mpms::ClearBBoxLabelIndex(prefix, sequence_.get());
|
mpms::ClearBBoxLabelIndex(prefix, sequence_.get());
|
||||||
|
mpms::ClearBBoxLabelConfidence(prefix, sequence_.get());
|
||||||
mpms::ClearBBoxClassString(prefix, sequence_.get());
|
mpms::ClearBBoxClassString(prefix, sequence_.get());
|
||||||
mpms::ClearBBoxClassIndex(prefix, sequence_.get());
|
mpms::ClearBBoxClassIndex(prefix, sequence_.get());
|
||||||
mpms::ClearBBoxTrackString(prefix, sequence_.get());
|
mpms::ClearBBoxTrackString(prefix, sequence_.get());
|
||||||
@@ -405,6 +510,46 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
}
|
}
|
||||||
replace_keypoints_ = false;
|
replace_keypoints_ = false;
|
||||||
}
|
}
|
||||||
|
if (absl::StartsWith(tag, kClipLabelPrefixTag) &&
|
||||||
|
!cc->Inputs().Tag(tag).IsEmpty()) {
|
||||||
|
const std::string& key = tag.substr(
|
||||||
|
sizeof(kClipLabelPrefixTag) / sizeof(*kClipLabelPrefixTag) - 1);
|
||||||
|
const Detection& detection = cc->Inputs().Tag(tag).Get<Detection>();
|
||||||
|
if (detection.score().empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (detection.label().empty() && detection.label_id().empty()) {
|
||||||
|
return absl::InvalidArgumentError(
|
||||||
|
"detection.label and detection.label_id can't be both empty");
|
||||||
|
}
|
||||||
|
// Allow empty label (for indexed feature inputs), but if label is not
|
||||||
|
// empty, it should have the same size as the score field.
|
||||||
|
if (!detection.label().empty()) {
|
||||||
|
if (detection.label().size() != detection.score().size()) {
|
||||||
|
return absl::InvalidArgumentError(
|
||||||
|
"Different size of detection.label and detection.score");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Allow empty label_ids, but if label_ids is not empty, it should have
|
||||||
|
// the same size as the score field.
|
||||||
|
if (!detection.label_id().empty()) {
|
||||||
|
if (detection.label_id().size() != detection.score().size()) {
|
||||||
|
return absl::InvalidArgumentError(
|
||||||
|
"Different size of detection.label_id and detection.score");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < detection.score().size(); ++i) {
|
||||||
|
if (!detection.label_id().empty()) {
|
||||||
|
mpms::AddClipLabelIndex(key, detection.label_id(i),
|
||||||
|
sequence_.get());
|
||||||
|
}
|
||||||
|
if (!detection.label().empty()) {
|
||||||
|
mpms::AddClipLabelString(key, detection.label(i), sequence_.get());
|
||||||
|
}
|
||||||
|
mpms::AddClipLabelConfidence(key, detection.score(i),
|
||||||
|
sequence_.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag) &&
|
if (absl::StartsWith(tag, kFloatContextFeaturePrefixTag) &&
|
||||||
!cc->Inputs().Tag(tag).IsEmpty()) {
|
!cc->Inputs().Tag(tag).IsEmpty()) {
|
||||||
std::string key =
|
std::string key =
|
||||||
@@ -412,9 +557,36 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
sizeof(*kFloatContextFeaturePrefixTag) -
|
sizeof(*kFloatContextFeaturePrefixTag) -
|
||||||
1);
|
1);
|
||||||
RET_CHECK_EQ(cc->InputTimestamp(), Timestamp::PostStream());
|
RET_CHECK_EQ(cc->InputTimestamp(), Timestamp::PostStream());
|
||||||
mpms::SetContextFeatureFloats(
|
for (const auto& value :
|
||||||
key, cc->Inputs().Tag(tag).Get<std::vector<float>>(),
|
cc->Inputs().Tag(tag).Get<std::vector<float>>()) {
|
||||||
sequence_.get());
|
mpms::AddContextFeatureFloats(key, value, sequence_.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (absl::StartsWith(tag, kIntsContextFeaturePrefixTag) &&
|
||||||
|
!cc->Inputs().Tag(tag).IsEmpty()) {
|
||||||
|
const std::string& key =
|
||||||
|
tag.substr(sizeof(kIntsContextFeaturePrefixTag) /
|
||||||
|
sizeof(*kIntsContextFeaturePrefixTag) -
|
||||||
|
1);
|
||||||
|
// To ensure only one packet is provided for this tag.
|
||||||
|
RET_CHECK_EQ(cc->InputTimestamp(), Timestamp::PostStream());
|
||||||
|
for (const auto& value :
|
||||||
|
cc->Inputs().Tag(tag).Get<std::vector<int64_t>>()) {
|
||||||
|
mpms::AddContextFeatureInts(key, value, sequence_.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (absl::StartsWith(tag, kBytesContextFeaturePrefixTag) &&
|
||||||
|
!cc->Inputs().Tag(tag).IsEmpty()) {
|
||||||
|
const std::string& key =
|
||||||
|
tag.substr(sizeof(kBytesContextFeaturePrefixTag) /
|
||||||
|
sizeof(*kBytesContextFeaturePrefixTag) -
|
||||||
|
1);
|
||||||
|
// To ensure only one packet is provided for this tag.
|
||||||
|
RET_CHECK_EQ(cc->InputTimestamp(), Timestamp::PostStream());
|
||||||
|
for (const auto& value :
|
||||||
|
cc->Inputs().Tag(tag).Get<std::vector<std::string>>()) {
|
||||||
|
mpms::AddContextFeatureBytes(key, value, sequence_.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (absl::StartsWith(tag, kFloatFeaturePrefixTag) &&
|
if (absl::StartsWith(tag, kFloatFeaturePrefixTag) &&
|
||||||
!cc->Inputs().Tag(tag).IsEmpty()) {
|
!cc->Inputs().Tag(tag).IsEmpty()) {
|
||||||
@@ -460,6 +632,7 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
}
|
}
|
||||||
std::vector<Location> predicted_locations;
|
std::vector<Location> predicted_locations;
|
||||||
std::vector<std::string> predicted_class_strings;
|
std::vector<std::string> predicted_class_strings;
|
||||||
|
std::vector<float> predicted_class_confidences;
|
||||||
std::vector<int> predicted_label_ids;
|
std::vector<int> predicted_label_ids;
|
||||||
for (auto& detection :
|
for (auto& detection :
|
||||||
cc->Inputs().Tag(tag).Get<std::vector<Detection>>()) {
|
cc->Inputs().Tag(tag).Get<std::vector<Detection>>()) {
|
||||||
@@ -488,6 +661,9 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
if (detection.label_id_size() > 0) {
|
if (detection.label_id_size() > 0) {
|
||||||
predicted_label_ids.push_back(detection.label_id(0));
|
predicted_label_ids.push_back(detection.label_id(0));
|
||||||
}
|
}
|
||||||
|
if (detection.score_size() > 0) {
|
||||||
|
predicted_class_confidences.push_back(detection.score(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!predicted_locations.empty()) {
|
if (!predicted_locations.empty()) {
|
||||||
@@ -501,6 +677,10 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
if (!predicted_label_ids.empty()) {
|
if (!predicted_label_ids.empty()) {
|
||||||
mpms::AddBBoxLabelIndex(key, predicted_label_ids, sequence_.get());
|
mpms::AddBBoxLabelIndex(key, predicted_label_ids, sequence_.get());
|
||||||
}
|
}
|
||||||
|
if (!predicted_class_confidences.empty()) {
|
||||||
|
mpms::AddBBoxLabelConfidence(key, predicted_class_confidences,
|
||||||
|
sequence_.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -548,10 +728,14 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (clip_media_id_.has_value()) {
|
||||||
|
mpms::SetClipMediaId(*clip_media_id_, sequence_.get());
|
||||||
|
}
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<tf::SequenceExample> sequence_;
|
std::unique_ptr<tf::SequenceExample> sequence_;
|
||||||
|
std::optional<std::string> clip_media_id_ = std::nullopt;
|
||||||
std::map<std::string, bool> features_present_;
|
std::map<std::string, bool> features_present_;
|
||||||
bool replace_keypoints_;
|
bool replace_keypoints_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,27 +12,32 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/container/flat_hash_map.h"
|
#include "absl/log/absl_check.h"
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/strings/numbers.h"
|
#include "absl/status/status.h"
|
||||||
|
#include "absl/strings/str_cat.h"
|
||||||
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
|
#include "mediapipe/calculators/image/opencv_image_encoder_calculator.pb.h"
|
||||||
#include "mediapipe/calculators/tensorflow/pack_media_sequence_calculator.pb.h"
|
#include "mediapipe/calculators/tensorflow/pack_media_sequence_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/calculator_runner.h"
|
#include "mediapipe/framework/calculator_runner.h"
|
||||||
#include "mediapipe/framework/formats/detection.pb.h"
|
#include "mediapipe/framework/formats/detection.pb.h"
|
||||||
#include "mediapipe/framework/formats/image_frame.h"
|
|
||||||
#include "mediapipe/framework/formats/location.h"
|
#include "mediapipe/framework/formats/location.h"
|
||||||
#include "mediapipe/framework/formats/location_opencv.h"
|
#include "mediapipe/framework/formats/location_opencv.h"
|
||||||
#include "mediapipe/framework/port/gmock.h"
|
#include "mediapipe/framework/packet.h"
|
||||||
#include "mediapipe/framework/port/gtest.h"
|
|
||||||
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
|
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
|
||||||
#include "mediapipe/framework/port/status_matchers.h"
|
#include "mediapipe/framework/port/status_matchers.h"
|
||||||
#include "mediapipe/framework/timestamp.h"
|
#include "mediapipe/framework/timestamp.h"
|
||||||
#include "mediapipe/util/sequence/media_sequence.h"
|
#include "mediapipe/util/sequence/media_sequence.h"
|
||||||
|
#include "mediapipe/util/sequence/media_sequence_util.h"
|
||||||
#include "tensorflow/core/example/example.pb.h"
|
#include "tensorflow/core/example/example.pb.h"
|
||||||
#include "tensorflow/core/example/feature.pb.h"
|
#include "tensorflow/core/example/feature.pb.h"
|
||||||
|
#include "testing/base/public/gmock.h"
|
||||||
|
#include "testing/base/public/gunit.h"
|
||||||
|
|
||||||
namespace mediapipe {
|
namespace mediapipe {
|
||||||
namespace {
|
namespace {
|
||||||
@@ -54,13 +59,23 @@ constexpr char kBytesFeatureTestTag[] = "BYTES_FEATURE_TEST";
|
|||||||
constexpr char kForwardFlowEncodedTag[] = "FORWARD_FLOW_ENCODED";
|
constexpr char kForwardFlowEncodedTag[] = "FORWARD_FLOW_ENCODED";
|
||||||
constexpr char kFloatContextFeatureOtherTag[] = "FLOAT_CONTEXT_FEATURE_OTHER";
|
constexpr char kFloatContextFeatureOtherTag[] = "FLOAT_CONTEXT_FEATURE_OTHER";
|
||||||
constexpr char kFloatContextFeatureTestTag[] = "FLOAT_CONTEXT_FEATURE_TEST";
|
constexpr char kFloatContextFeatureTestTag[] = "FLOAT_CONTEXT_FEATURE_TEST";
|
||||||
|
constexpr char kIntsContextFeatureTestTag[] = "INTS_CONTEXT_FEATURE_TEST";
|
||||||
|
constexpr char kIntsContextFeatureOtherTag[] = "INTS_CONTEXT_FEATURE_OTHER";
|
||||||
|
constexpr char kBytesContextFeatureTestTag[] = "BYTES_CONTEXT_FEATURE_TEST";
|
||||||
|
constexpr char kBytesContextFeatureOtherTag[] = "BYTES_CONTEXT_FEATURE_OTHER";
|
||||||
constexpr char kFloatFeatureOtherTag[] = "FLOAT_FEATURE_OTHER";
|
constexpr char kFloatFeatureOtherTag[] = "FLOAT_FEATURE_OTHER";
|
||||||
constexpr char kFloatFeatureTestTag[] = "FLOAT_FEATURE_TEST";
|
constexpr char kFloatFeatureTestTag[] = "FLOAT_FEATURE_TEST";
|
||||||
constexpr char kIntFeatureOtherTag[] = "INT_FEATURE_OTHER";
|
constexpr char kIntFeatureOtherTag[] = "INT_FEATURE_OTHER";
|
||||||
constexpr char kIntFeatureTestTag[] = "INT_FEATURE_TEST";
|
constexpr char kIntFeatureTestTag[] = "INT_FEATURE_TEST";
|
||||||
|
constexpr char kImageLabelTestTag[] = "IMAGE_LABEL_TEST";
|
||||||
|
constexpr char kImageLabelOtherTag[] = "IMAGE_LABEL_OTHER";
|
||||||
constexpr char kImagePrefixTag[] = "IMAGE_PREFIX";
|
constexpr char kImagePrefixTag[] = "IMAGE_PREFIX";
|
||||||
constexpr char kSequenceExampleTag[] = "SEQUENCE_EXAMPLE";
|
constexpr char kSequenceExampleTag[] = "SEQUENCE_EXAMPLE";
|
||||||
constexpr char kImageTag[] = "IMAGE";
|
constexpr char kImageTag[] = "IMAGE";
|
||||||
|
constexpr char kClipMediaIdTag[] = "CLIP_MEDIA_ID";
|
||||||
|
constexpr char kClipLabelTestTag[] = "CLIP_LABEL_TEST";
|
||||||
|
constexpr char kClipLabelOtherTag[] = "CLIP_LABEL_OTHER";
|
||||||
|
constexpr char kClipLabelAnotherTag[] = "CLIP_LABEL_ANOTHER";
|
||||||
|
|
||||||
class PackMediaSequenceCalculatorTest : public ::testing::Test {
|
class PackMediaSequenceCalculatorTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
@@ -68,10 +83,14 @@ class PackMediaSequenceCalculatorTest : public ::testing::Test {
|
|||||||
const tf::Features& features,
|
const tf::Features& features,
|
||||||
const bool output_only_if_all_present,
|
const bool output_only_if_all_present,
|
||||||
const bool replace_instead_of_append,
|
const bool replace_instead_of_append,
|
||||||
const bool output_as_zero_timestamp = false) {
|
const bool output_as_zero_timestamp = false,
|
||||||
|
const std::vector<std::string>& input_side_packets = {
|
||||||
|
"SEQUENCE_EXAMPLE:input_sequence"}) {
|
||||||
CalculatorGraphConfig::Node config;
|
CalculatorGraphConfig::Node config;
|
||||||
config.set_calculator("PackMediaSequenceCalculator");
|
config.set_calculator("PackMediaSequenceCalculator");
|
||||||
config.add_input_side_packet("SEQUENCE_EXAMPLE:input_sequence");
|
for (const std::string& side_packet : input_side_packets) {
|
||||||
|
config.add_input_side_packet(side_packet);
|
||||||
|
}
|
||||||
config.add_output_stream("SEQUENCE_EXAMPLE:output_sequence");
|
config.add_output_stream("SEQUENCE_EXAMPLE:output_sequence");
|
||||||
for (const std::string& stream : input_streams) {
|
for (const std::string& stream : input_streams) {
|
||||||
config.add_input_stream(stream);
|
config.add_input_stream(stream);
|
||||||
@@ -313,6 +332,76 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoBytesLists) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, PacksTwoImageLabels) {
|
||||||
|
SetUpCalculator(
|
||||||
|
{"IMAGE_LABEL_TEST:test_labels", "IMAGE_LABEL_OTHER:test_labels2"}, {},
|
||||||
|
false, true);
|
||||||
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
|
|
||||||
|
int num_timesteps = 2;
|
||||||
|
for (int i = 0; i < num_timesteps; ++i) {
|
||||||
|
Detection detection1;
|
||||||
|
detection1.add_label(absl::StrCat("foo", 2 << i));
|
||||||
|
detection1.add_label_id(i);
|
||||||
|
detection1.add_score(0.1 * i);
|
||||||
|
detection1.add_label(absl::StrCat("foo", 2 << i));
|
||||||
|
detection1.add_label_id(i);
|
||||||
|
detection1.add_score(0.1 * i);
|
||||||
|
auto label_ptr1 = ::absl::make_unique<Detection>(detection1);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kImageLabelTestTag)
|
||||||
|
.packets.push_back(Adopt(label_ptr1.release()).At(Timestamp(i)));
|
||||||
|
Detection detection2;
|
||||||
|
detection2.add_label(absl::StrCat("bar", 2 << i));
|
||||||
|
detection2.add_score(0.2 * i);
|
||||||
|
detection2.add_label(absl::StrCat("bar", 2 << i));
|
||||||
|
detection2.add_score(0.2 * i);
|
||||||
|
auto label_ptr2 = ::absl::make_unique<Detection>(detection2);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kImageLabelOtherTag)
|
||||||
|
.packets.push_back(Adopt(label_ptr2.release()).At(Timestamp(i)));
|
||||||
|
}
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_EQ(num_timesteps,
|
||||||
|
mpms::GetImageTimestampSize("TEST", output_sequence));
|
||||||
|
ASSERT_EQ(num_timesteps,
|
||||||
|
mpms::GetImageLabelStringSize("TEST", output_sequence));
|
||||||
|
ASSERT_EQ(num_timesteps,
|
||||||
|
mpms::GetImageLabelConfidenceSize("TEST", output_sequence));
|
||||||
|
ASSERT_EQ(num_timesteps,
|
||||||
|
mpms::GetImageTimestampSize("OTHER", output_sequence));
|
||||||
|
ASSERT_EQ(num_timesteps,
|
||||||
|
mpms::GetImageLabelStringSize("OTHER", output_sequence));
|
||||||
|
ASSERT_EQ(num_timesteps,
|
||||||
|
mpms::GetImageLabelConfidenceSize("OTHER", output_sequence));
|
||||||
|
for (int i = 0; i < num_timesteps; ++i) {
|
||||||
|
ASSERT_EQ(i, mpms::GetImageTimestampAt("TEST", output_sequence, i));
|
||||||
|
ASSERT_THAT(mpms::GetImageLabelStringAt("TEST", output_sequence, i),
|
||||||
|
::testing::ElementsAreArray(
|
||||||
|
std::vector<std::string>(2, absl::StrCat("foo", 2 << i))));
|
||||||
|
ASSERT_THAT(mpms::GetImageLabelIndexAt("TEST", output_sequence, i),
|
||||||
|
::testing::ElementsAreArray(std::vector<int32_t>(2, i)));
|
||||||
|
ASSERT_THAT(mpms::GetImageLabelConfidenceAt("TEST", output_sequence, i),
|
||||||
|
::testing::ElementsAreArray(std::vector<float>(2, 0.1 * i)));
|
||||||
|
ASSERT_EQ(i, mpms::GetImageTimestampAt("OTHER", output_sequence, i));
|
||||||
|
ASSERT_THAT(mpms::GetImageLabelStringAt("OTHER", output_sequence, i),
|
||||||
|
::testing::ElementsAreArray(
|
||||||
|
std::vector<std::string>(2, absl::StrCat("bar", 2 << i))));
|
||||||
|
ASSERT_THAT(mpms::GetImageLabelConfidenceAt("OTHER", output_sequence, i),
|
||||||
|
::testing::ElementsAreArray(std::vector<float>(2, 0.2 * i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(PackMediaSequenceCalculatorTest, OutputAsZeroTimestamp) {
|
TEST_F(PackMediaSequenceCalculatorTest, OutputAsZeroTimestamp) {
|
||||||
SetUpCalculator({"FLOAT_FEATURE_TEST:test"}, {}, false, true, true);
|
SetUpCalculator({"FLOAT_FEATURE_TEST:test"}, {}, false, true, true);
|
||||||
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
@@ -368,6 +457,315 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoContextFloatLists) {
|
|||||||
testing::ElementsAre(4, 4));
|
testing::ElementsAre(4, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, ReplaceTwoContextFloatLists) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"FLOAT_CONTEXT_FEATURE_TEST:test",
|
||||||
|
"FLOAT_CONTEXT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = std::make_unique<tf::SequenceExample>();
|
||||||
|
mpms::SetContextFeatureFloats("TEST", {2, 3}, input_sequence.get());
|
||||||
|
mpms::SetContextFeatureFloats("OTHER", {2, 4}, input_sequence.get());
|
||||||
|
|
||||||
|
const std::vector<float> vf_1 = {5, 6};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kFloatContextFeatureTestTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<float>>(vf_1).At(Timestamp::PostStream()));
|
||||||
|
const std::vector<float> vf_2 = {7, 8};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kFloatContextFeatureOtherTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<float>>(vf_2).At(Timestamp::PostStream()));
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureFloats("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(5, 6));
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureFloats("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(7, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, AppendTwoContextFloatLists) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"FLOAT_CONTEXT_FEATURE_TEST:test",
|
||||||
|
"FLOAT_CONTEXT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/false);
|
||||||
|
auto input_sequence = std::make_unique<tf::SequenceExample>();
|
||||||
|
mpms::SetContextFeatureFloats("TEST", {2, 3}, input_sequence.get());
|
||||||
|
mpms::SetContextFeatureFloats("OTHER", {2, 4}, input_sequence.get());
|
||||||
|
|
||||||
|
const std::vector<float> vf_1 = {5, 6};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kFloatContextFeatureTestTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<float>>(vf_1).At(Timestamp::PostStream()));
|
||||||
|
const std::vector<float> vf_2 = {7, 8};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kFloatContextFeatureOtherTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<float>>(vf_2).At(Timestamp::PostStream()));
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
EXPECT_THAT(mpms::GetContextFeatureFloats("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(2, 3, 5, 6));
|
||||||
|
EXPECT_THAT(mpms::GetContextFeatureFloats("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(2, 4, 7, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, PackTwoContextIntLists) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"INTS_CONTEXT_FEATURE_TEST:test",
|
||||||
|
"INTS_CONTEXT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = absl::make_unique<tf::SequenceExample>();
|
||||||
|
|
||||||
|
const std::vector<int64_t> vi_1 = {2, 3};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kIntsContextFeatureTestTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<int64_t>>(vi_1).At(Timestamp::PostStream()));
|
||||||
|
const std::vector<int64_t> vi_2 = {2, 4};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kIntsContextFeatureOtherTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<int64_t>>(vi_2).At(Timestamp::PostStream()));
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureInts("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(2, 3));
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureInts("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(2, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, ReplaceTwoContextIntLists) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"INTS_CONTEXT_FEATURE_TEST:test",
|
||||||
|
"INTS_CONTEXT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = absl::make_unique<tf::SequenceExample>();
|
||||||
|
mpms::SetContextFeatureInts("TEST", {2, 3}, input_sequence.get());
|
||||||
|
mpms::SetContextFeatureInts("OTHER", {2, 4}, input_sequence.get());
|
||||||
|
|
||||||
|
const std::vector<int64_t> vi_1 = {5, 6};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kIntsContextFeatureTestTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<int64_t>>(vi_1).At(Timestamp::PostStream()));
|
||||||
|
const std::vector<int64_t> vi_2 = {7, 8};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kIntsContextFeatureOtherTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<int64_t>>(vi_2).At(Timestamp::PostStream()));
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureInts("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(5, 6));
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureInts("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(7, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, AppendTwoContextIntLists) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"INTS_CONTEXT_FEATURE_TEST:test",
|
||||||
|
"INTS_CONTEXT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/false);
|
||||||
|
auto input_sequence = absl::make_unique<tf::SequenceExample>();
|
||||||
|
mpms::SetContextFeatureInts("TEST", {2, 3}, input_sequence.get());
|
||||||
|
mpms::SetContextFeatureInts("OTHER", {2, 4}, input_sequence.get());
|
||||||
|
|
||||||
|
const std::vector<int64_t> vi_1 = {5, 6};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kIntsContextFeatureTestTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<int64_t>>(vi_1).At(Timestamp::PostStream()));
|
||||||
|
const std::vector<int64_t> vi_2 = {7, 8};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kIntsContextFeatureOtherTag)
|
||||||
|
.packets.push_back(
|
||||||
|
MakePacket<std::vector<int64_t>>(vi_2).At(Timestamp::PostStream()));
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureInts("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(2, 3, 5, 6));
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureInts("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(2, 4, 7, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, PackTwoContextByteLists) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"BYTES_CONTEXT_FEATURE_TEST:test",
|
||||||
|
"BYTES_CONTEXT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = absl::make_unique<tf::SequenceExample>();
|
||||||
|
|
||||||
|
const std::vector<std::string> vb_1 = {"value_1", "value_2"};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kBytesContextFeatureTestTag)
|
||||||
|
.packets.push_back(MakePacket<std::vector<std::string>>(vb_1).At(
|
||||||
|
Timestamp::PostStream()));
|
||||||
|
const std::vector<std::string> vb_2 = {"value_3", "value_4"};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kBytesContextFeatureOtherTag)
|
||||||
|
.packets.push_back(MakePacket<std::vector<std::string>>(vb_2).At(
|
||||||
|
Timestamp::PostStream()));
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureBytes("TEST", output_sequence),
|
||||||
|
testing::ElementsAre("value_1", "value_2"));
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureBytes("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre("value_3", "value_4"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, ReplaceTwoContextByteLists) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"BYTES_CONTEXT_FEATURE_TEST:test",
|
||||||
|
"BYTES_CONTEXT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false, /*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = absl::make_unique<tf::SequenceExample>();
|
||||||
|
mpms::SetContextFeatureBytes("TEST", {"existing_value_1", "existing_value_2"},
|
||||||
|
input_sequence.get());
|
||||||
|
mpms::SetContextFeatureBytes(
|
||||||
|
"OTHER", {"existing_value_3", "existing_value_4"}, input_sequence.get());
|
||||||
|
|
||||||
|
const std::vector<std::string> vb_1 = {"value_1", "value_2"};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kBytesContextFeatureTestTag)
|
||||||
|
.packets.push_back(MakePacket<std::vector<std::string>>(vb_1).At(
|
||||||
|
Timestamp::PostStream()));
|
||||||
|
const std::vector<std::string> vb_2 = {"value_3", "value_4"};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kBytesContextFeatureOtherTag)
|
||||||
|
.packets.push_back(MakePacket<std::vector<std::string>>(vb_2).At(
|
||||||
|
Timestamp::PostStream()));
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureBytes("TEST", output_sequence),
|
||||||
|
testing::ElementsAre("value_1", "value_2"));
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureBytes("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre("value_3", "value_4"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, AppendTwoContextByteLists) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"BYTES_CONTEXT_FEATURE_TEST:test",
|
||||||
|
"BYTES_CONTEXT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/false);
|
||||||
|
auto input_sequence = absl::make_unique<tf::SequenceExample>();
|
||||||
|
mpms::SetContextFeatureBytes("TEST", {"existing_value_1", "existing_value_2"},
|
||||||
|
input_sequence.get());
|
||||||
|
mpms::SetContextFeatureBytes(
|
||||||
|
"OTHER", {"existing_value_3", "existing_value_4"}, input_sequence.get());
|
||||||
|
|
||||||
|
const std::vector<std::string> vb_1 = {"value_1", "value_2"};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kBytesContextFeatureTestTag)
|
||||||
|
.packets.push_back(MakePacket<std::vector<std::string>>(vb_1).At(
|
||||||
|
Timestamp::PostStream()));
|
||||||
|
const std::vector<std::string> vb_2 = {"value_3", "value_4"};
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kBytesContextFeatureOtherTag)
|
||||||
|
.packets.push_back(MakePacket<std::vector<std::string>>(vb_2).At(
|
||||||
|
Timestamp::PostStream()));
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureBytes("TEST", output_sequence),
|
||||||
|
testing::ElementsAre("existing_value_1", "existing_value_2",
|
||||||
|
"value_1", "value_2"));
|
||||||
|
ASSERT_THAT(mpms::GetContextFeatureBytes("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre("existing_value_3", "existing_value_4",
|
||||||
|
"value_3", "value_4"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(PackMediaSequenceCalculatorTest, PacksAdditionalContext) {
|
TEST_F(PackMediaSequenceCalculatorTest, PacksAdditionalContext) {
|
||||||
tf::Features context;
|
tf::Features context;
|
||||||
(*context.mutable_feature())["TEST"].mutable_bytes_list()->add_value("YES");
|
(*context.mutable_feature())["TEST"].mutable_bytes_list()->add_value("YES");
|
||||||
@@ -529,6 +927,10 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoBBoxDetections) {
|
|||||||
auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i);
|
auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i);
|
||||||
ASSERT_EQ(0, class_indices[0]);
|
ASSERT_EQ(0, class_indices[0]);
|
||||||
ASSERT_EQ(1, class_indices[1]);
|
ASSERT_EQ(1, class_indices[1]);
|
||||||
|
auto class_scores =
|
||||||
|
mpms::GetPredictedBBoxLabelConfidenceAt(output_sequence, i);
|
||||||
|
ASSERT_FLOAT_EQ(0.5, class_scores[0]);
|
||||||
|
ASSERT_FLOAT_EQ(0.75, class_scores[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,6 +1073,10 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksBBoxWithImages) {
|
|||||||
auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i);
|
auto class_indices = mpms::GetPredictedBBoxLabelIndexAt(output_sequence, i);
|
||||||
ASSERT_EQ(0, class_indices[0]);
|
ASSERT_EQ(0, class_indices[0]);
|
||||||
ASSERT_EQ(1, class_indices[1]);
|
ASSERT_EQ(1, class_indices[1]);
|
||||||
|
auto class_scores =
|
||||||
|
mpms::GetPredictedBBoxLabelConfidenceAt(output_sequence, i);
|
||||||
|
ASSERT_FLOAT_EQ(0.5, class_scores[0]);
|
||||||
|
ASSERT_FLOAT_EQ(0.75, class_scores[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,6 +1167,456 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoMaskDetections) {
|
|||||||
testing::ElementsAreArray(::std::vector<std::string>({"mask"})));
|
testing::ElementsAreArray(::std::vector<std::string>({"mask"})));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, PackThreeClipLabels) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2",
|
||||||
|
"CLIP_LABEL_ANOTHER:test3"},
|
||||||
|
/*features=*/{}, /*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
|
|
||||||
|
Detection detection_1;
|
||||||
|
detection_1.add_label("label_1");
|
||||||
|
detection_1.add_label("label_2");
|
||||||
|
detection_1.add_label_id(1);
|
||||||
|
detection_1.add_label_id(2);
|
||||||
|
detection_1.add_score(0.1);
|
||||||
|
detection_1.add_score(0.2);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelTestTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
|
||||||
|
// No label ID for detection_2.
|
||||||
|
Detection detection_2;
|
||||||
|
detection_2.add_label("label_3");
|
||||||
|
detection_2.add_label("label_4");
|
||||||
|
detection_2.add_score(0.3);
|
||||||
|
detection_2.add_score(0.4);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelOtherTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
|
||||||
|
// No label for detection_3.
|
||||||
|
Detection detection_3;
|
||||||
|
detection_3.add_label_id(3);
|
||||||
|
detection_3.add_label_id(4);
|
||||||
|
detection_3.add_score(0.3);
|
||||||
|
detection_3.add_score(0.4);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelAnotherTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_3).At(Timestamp(3)));
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelString("TEST", output_sequence),
|
||||||
|
testing::ElementsAre("label_1", "label_2"));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelIndex("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(1, 2));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelConfidence("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(0.1, 0.2));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelString("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre("label_3", "label_4"));
|
||||||
|
ASSERT_FALSE(mpms::HasClipLabelIndex("OTHER", output_sequence));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelConfidence("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(0.3, 0.4));
|
||||||
|
ASSERT_FALSE(mpms::HasClipLabelString("ANOTHER", output_sequence));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelIndex("ANOTHER", output_sequence),
|
||||||
|
testing::ElementsAre(3, 4));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelConfidence("ANOTHER", output_sequence),
|
||||||
|
testing::ElementsAre(0.3, 0.4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, PackTwoClipLabels_EmptyScore) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
|
||||||
|
/*features=*/{}, /*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
|
|
||||||
|
// No score in detection_1. detection_1 is ignored.
|
||||||
|
Detection detection_1;
|
||||||
|
detection_1.add_label("label_1");
|
||||||
|
detection_1.add_label("label_2");
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelTestTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
|
||||||
|
Detection detection_2;
|
||||||
|
detection_2.add_label("label_3");
|
||||||
|
detection_2.add_label("label_4");
|
||||||
|
detection_2.add_score(0.3);
|
||||||
|
detection_2.add_score(0.4);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelOtherTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_FALSE(mpms::HasClipLabelString("TEST", output_sequence));
|
||||||
|
ASSERT_FALSE(mpms::HasClipLabelIndex("TEST", output_sequence));
|
||||||
|
ASSERT_FALSE(mpms::HasClipLabelConfidence("TEST", output_sequence));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelString("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre("label_3", "label_4"));
|
||||||
|
ASSERT_FALSE(mpms::HasClipLabelIndex("OTHER", output_sequence));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelConfidence("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(0.3, 0.4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, PackTwoClipLabels_NoLabelOrLabelIndex) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
|
||||||
|
/*features=*/{}, /*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
|
|
||||||
|
// No label or label_index in detection_1.
|
||||||
|
Detection detection_1;
|
||||||
|
detection_1.add_score(0.1);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelTestTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
|
||||||
|
Detection detection_2;
|
||||||
|
detection_2.add_label("label_3");
|
||||||
|
detection_2.add_label("label_4");
|
||||||
|
detection_2.add_score(0.3);
|
||||||
|
detection_2.add_score(0.4);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelOtherTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
runner_->Run(),
|
||||||
|
testing::status::StatusIs(
|
||||||
|
absl::StatusCode::kInvalidArgument,
|
||||||
|
testing::HasSubstr(
|
||||||
|
"detection.label and detection.label_id can't be both empty")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest,
|
||||||
|
PackTwoClipLabels_DifferentLabelScoreSize) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
|
||||||
|
/*features=*/{}, /*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
|
|
||||||
|
// 2 labels and 1 score in detection_1.
|
||||||
|
Detection detection_1;
|
||||||
|
detection_1.add_label("label_1");
|
||||||
|
detection_1.add_label("label_2");
|
||||||
|
detection_1.add_score(0.1);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelTestTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
|
||||||
|
Detection detection_2;
|
||||||
|
detection_2.add_label("label_3");
|
||||||
|
detection_2.add_label("label_4");
|
||||||
|
detection_2.add_score(0.3);
|
||||||
|
detection_2.add_score(0.4);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelOtherTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
runner_->Run(),
|
||||||
|
testing::status::StatusIs(
|
||||||
|
absl::StatusCode::kInvalidArgument,
|
||||||
|
testing::HasSubstr(
|
||||||
|
"Different size of detection.label and detection.score")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest,
|
||||||
|
PackTwoClipLabels_DifferentLabelIdSize) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
|
||||||
|
/*features=*/{}, /*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
|
|
||||||
|
// 2 scores and 1 label_id in detection_1.
|
||||||
|
Detection detection_1;
|
||||||
|
detection_1.add_label("label_1");
|
||||||
|
detection_1.add_label("label_2");
|
||||||
|
detection_1.add_label_id(1);
|
||||||
|
detection_1.add_score(0.1);
|
||||||
|
detection_1.add_score(0.2);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelTestTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
|
||||||
|
Detection detection_2;
|
||||||
|
detection_2.add_label("label_3");
|
||||||
|
detection_2.add_label("label_4");
|
||||||
|
detection_2.add_score(0.3);
|
||||||
|
detection_2.add_score(0.4);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelOtherTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
runner_->Run(),
|
||||||
|
testing::status::StatusIs(
|
||||||
|
absl::StatusCode::kInvalidArgument,
|
||||||
|
testing::HasSubstr(
|
||||||
|
"Different size of detection.label_id and detection.score")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, ReplaceTwoClipLabels) {
|
||||||
|
// Replace existing clip/label/string and clip/label/confidence values for
|
||||||
|
// the prefixes.
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
|
||||||
|
/*features=*/{}, /*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
|
mpms::SetClipLabelString("TEST", {"old_label_1", "old_label_2"},
|
||||||
|
input_sequence.get());
|
||||||
|
mpms::SetClipLabelConfidence("TEST", {0.1, 0.2}, input_sequence.get());
|
||||||
|
mpms::SetClipLabelString("OTHER", {"old_label_3", "old_label_4"},
|
||||||
|
input_sequence.get());
|
||||||
|
mpms::SetClipLabelConfidence("OTHER", {0.3, 0.4}, input_sequence.get());
|
||||||
|
|
||||||
|
Detection detection_1;
|
||||||
|
detection_1.add_label("label_1");
|
||||||
|
detection_1.add_label("label_2");
|
||||||
|
detection_1.add_label_id(1);
|
||||||
|
detection_1.add_label_id(2);
|
||||||
|
detection_1.add_score(0.9);
|
||||||
|
detection_1.add_score(0.8);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelTestTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
|
||||||
|
Detection detection_2;
|
||||||
|
detection_2.add_label("label_3");
|
||||||
|
detection_2.add_label("label_4");
|
||||||
|
detection_2.add_label_id(3);
|
||||||
|
detection_2.add_label_id(4);
|
||||||
|
detection_2.add_score(0.7);
|
||||||
|
detection_2.add_score(0.6);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelOtherTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelString("TEST", output_sequence),
|
||||||
|
testing::ElementsAre("label_1", "label_2"));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelIndex("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(1, 2));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelConfidence("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(0.9, 0.8));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelString("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre("label_3", "label_4"));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelIndex("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(3, 4));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelConfidence("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(0.7, 0.6));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, AppendTwoClipLabels) {
|
||||||
|
// Append to the existing clip/label/string and clip/label/confidence values
|
||||||
|
// for the prefixes.
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
|
||||||
|
/*features=*/{}, /*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/false);
|
||||||
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
|
mpms::SetClipLabelString("TEST", {"old_label_1", "old_label_2"},
|
||||||
|
input_sequence.get());
|
||||||
|
mpms::SetClipLabelIndex("TEST", {1, 2}, input_sequence.get());
|
||||||
|
mpms::SetClipLabelConfidence("TEST", {0.1, 0.2}, input_sequence.get());
|
||||||
|
mpms::SetClipLabelString("OTHER", {"old_label_3", "old_label_4"},
|
||||||
|
input_sequence.get());
|
||||||
|
mpms::SetClipLabelIndex("OTHER", {3, 4}, input_sequence.get());
|
||||||
|
mpms::SetClipLabelConfidence("OTHER", {0.3, 0.4}, input_sequence.get());
|
||||||
|
|
||||||
|
Detection detection_1;
|
||||||
|
detection_1.add_label("label_1");
|
||||||
|
detection_1.add_label("label_2");
|
||||||
|
detection_1.add_label_id(9);
|
||||||
|
detection_1.add_label_id(8);
|
||||||
|
detection_1.add_score(0.9);
|
||||||
|
detection_1.add_score(0.8);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelTestTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
|
||||||
|
Detection detection_2;
|
||||||
|
detection_2.add_label("label_3");
|
||||||
|
detection_2.add_label("label_4");
|
||||||
|
detection_2.add_label_id(7);
|
||||||
|
detection_2.add_label_id(6);
|
||||||
|
detection_2.add_score(0.7);
|
||||||
|
detection_2.add_score(0.6);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelOtherTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
mpms::GetClipLabelString("TEST", output_sequence),
|
||||||
|
testing::ElementsAre("old_label_1", "old_label_2", "label_1", "label_2"));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelIndex("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(1, 2, 9, 8));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelConfidence("TEST", output_sequence),
|
||||||
|
testing::ElementsAre(0.1, 0.2, 0.9, 0.8));
|
||||||
|
ASSERT_THAT(
|
||||||
|
mpms::GetClipLabelString("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre("old_label_3", "old_label_4", "label_3", "label_4"));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelIndex("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(3, 4, 7, 6));
|
||||||
|
ASSERT_THAT(mpms::GetClipLabelConfidence("OTHER", output_sequence),
|
||||||
|
testing::ElementsAre(0.3, 0.4, 0.7, 0.6));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest,
|
||||||
|
DifferentClipLabelScoreAndConfidenceSize) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"CLIP_LABEL_TEST:test", "CLIP_LABEL_OTHER:test2"},
|
||||||
|
/*features=*/{}, /*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/true);
|
||||||
|
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||||
|
|
||||||
|
Detection detection_1;
|
||||||
|
// 2 labels and 1 score.
|
||||||
|
detection_1.add_label("label_1");
|
||||||
|
detection_1.add_label("label_2");
|
||||||
|
detection_1.add_score(0.1);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelTestTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_1).At(Timestamp(1)));
|
||||||
|
Detection detection_2;
|
||||||
|
detection_2.add_label("label_3");
|
||||||
|
detection_2.add_label("label_4");
|
||||||
|
detection_2.add_score(0.3);
|
||||||
|
detection_2.add_score(0.4);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kClipLabelOtherTag)
|
||||||
|
.packets.push_back(MakePacket<Detection>(detection_2).At(Timestamp(2)));
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
ASSERT_THAT(runner_->Run(),
|
||||||
|
testing::status::StatusIs(absl::StatusCode::kInvalidArgument));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, AddClipMediaId) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"FLOAT_FEATURE_TEST:test",
|
||||||
|
"FLOAT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/true,
|
||||||
|
/*output_as_zero_timestamp=*/false, /*input_side_packets=*/
|
||||||
|
{"SEQUENCE_EXAMPLE:input_sequence", "CLIP_MEDIA_ID:video_id"});
|
||||||
|
auto input_sequence = absl::make_unique<tf::SequenceExample>();
|
||||||
|
const std::string test_video_id = "test_video_id";
|
||||||
|
|
||||||
|
int num_timesteps = 2;
|
||||||
|
for (int i = 0; i < num_timesteps; ++i) {
|
||||||
|
auto vf_ptr = ::absl::make_unique<std::vector<float>>(2, 2 << i);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kFloatFeatureTestTag)
|
||||||
|
.packets.push_back(Adopt(vf_ptr.release()).At(Timestamp(i)));
|
||||||
|
vf_ptr = ::absl::make_unique<std::vector<float>>(2, 2 << i);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kFloatFeatureOtherTag)
|
||||||
|
.packets.push_back(Adopt(vf_ptr.release()).At(Timestamp(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kClipMediaIdTag) =
|
||||||
|
MakePacket<std::string>(test_video_id);
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_EQ(test_video_id, mpms::GetClipMediaId(output_sequence));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PackMediaSequenceCalculatorTest, ReplaceClipMediaId) {
|
||||||
|
SetUpCalculator(
|
||||||
|
/*input_streams=*/{"FLOAT_FEATURE_TEST:test",
|
||||||
|
"FLOAT_FEATURE_OTHER:test2"},
|
||||||
|
/*features=*/{},
|
||||||
|
/*output_only_if_all_present=*/false,
|
||||||
|
/*replace_instead_of_append=*/true,
|
||||||
|
/*output_as_zero_timestamp=*/false, /*input_side_packets=*/
|
||||||
|
{"SEQUENCE_EXAMPLE:input_sequence", "CLIP_MEDIA_ID:video_id"});
|
||||||
|
auto input_sequence = absl::make_unique<tf::SequenceExample>();
|
||||||
|
const std::string existing_video_id = "existing_video_id";
|
||||||
|
mpms::SetClipMediaId(existing_video_id, input_sequence.get());
|
||||||
|
const std::string test_video_id = "test_video_id";
|
||||||
|
|
||||||
|
int num_timesteps = 2;
|
||||||
|
for (int i = 0; i < num_timesteps; ++i) {
|
||||||
|
auto vf_ptr = ::absl::make_unique<std::vector<float>>(2, 2 << i);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kFloatFeatureTestTag)
|
||||||
|
.packets.push_back(Adopt(vf_ptr.release()).At(Timestamp(i)));
|
||||||
|
vf_ptr = ::absl::make_unique<std::vector<float>>(2, 2 << i);
|
||||||
|
runner_->MutableInputs()
|
||||||
|
->Tag(kFloatFeatureOtherTag)
|
||||||
|
.packets.push_back(Adopt(vf_ptr.release()).At(Timestamp(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
runner_->MutableSidePackets()->Tag(kClipMediaIdTag) =
|
||||||
|
MakePacket<std::string>(test_video_id).At(Timestamp(0));
|
||||||
|
runner_->MutableSidePackets()->Tag(kSequenceExampleTag) =
|
||||||
|
Adopt(input_sequence.release());
|
||||||
|
|
||||||
|
MP_ASSERT_OK(runner_->Run());
|
||||||
|
|
||||||
|
const std::vector<Packet>& output_packets =
|
||||||
|
runner_->Outputs().Tag(kSequenceExampleTag).packets;
|
||||||
|
ASSERT_EQ(1, output_packets.size());
|
||||||
|
const tf::SequenceExample& output_sequence =
|
||||||
|
output_packets[0].Get<tf::SequenceExample>();
|
||||||
|
|
||||||
|
ASSERT_EQ(test_video_id, mpms::GetClipMediaId(output_sequence));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(PackMediaSequenceCalculatorTest, MissingStreamOK) {
|
TEST_F(PackMediaSequenceCalculatorTest, MissingStreamOK) {
|
||||||
SetUpCalculator(
|
SetUpCalculator(
|
||||||
{"FORWARD_FLOW_ENCODED:flow", "FLOAT_FEATURE_I3D_FLOW:feature"}, {},
|
{"FORWARD_FLOW_ENCODED:flow", "FLOAT_FEATURE_I3D_FLOW:feature"}, {},
|
||||||
@@ -1065,6 +1921,7 @@ TEST_F(PackMediaSequenceCalculatorTest, TestOverwritingAndReconciling) {
|
|||||||
mpms::AddBBoxNumRegions(-1, input_sequence.get());
|
mpms::AddBBoxNumRegions(-1, input_sequence.get());
|
||||||
mpms::AddBBoxLabelString({"anything"}, input_sequence.get());
|
mpms::AddBBoxLabelString({"anything"}, input_sequence.get());
|
||||||
mpms::AddBBoxLabelIndex({-1}, input_sequence.get());
|
mpms::AddBBoxLabelIndex({-1}, input_sequence.get());
|
||||||
|
mpms::AddBBoxLabelConfidence({-1}, input_sequence.get());
|
||||||
mpms::AddBBoxClassString({"anything"}, input_sequence.get());
|
mpms::AddBBoxClassString({"anything"}, input_sequence.get());
|
||||||
mpms::AddBBoxClassIndex({-1}, input_sequence.get());
|
mpms::AddBBoxClassIndex({-1}, input_sequence.get());
|
||||||
mpms::AddBBoxTrackString({"anything"}, input_sequence.get());
|
mpms::AddBBoxTrackString({"anything"}, input_sequence.get());
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/log/absl_log.h"
|
||||||
#include "mediapipe/calculators/tensorflow/tensor_squeeze_dimensions_calculator.pb.h"
|
#include "mediapipe/calculators/tensorflow/tensor_squeeze_dimensions_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/port/ret_check.h"
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
@@ -99,10 +100,11 @@ class TensorSqueezeDimensionsCalculator : public CalculatorBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (remove_dims_.empty()) {
|
if (remove_dims_.empty()) {
|
||||||
LOG(ERROR) << "TensorSqueezeDimensionsCalculator is squeezing input with "
|
ABSL_LOG(ERROR)
|
||||||
"no single-dimensions. Calculator will be a no-op.";
|
<< "TensorSqueezeDimensionsCalculator is squeezing input with "
|
||||||
LOG(ERROR) << "Input to TensorSqueezeDimensionsCalculator has shape "
|
"no single-dimensions. Calculator will be a no-op.";
|
||||||
<< tensor_shape.DebugString();
|
ABSL_LOG(ERROR) << "Input to TensorSqueezeDimensionsCalculator has shape "
|
||||||
|
<< tensor_shape.DebugString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "absl/log/absl_check.h"
|
||||||
#include "mediapipe/calculators/tensorflow/tensor_to_image_frame_calculator.pb.h"
|
#include "mediapipe/calculators/tensorflow/tensor_to_image_frame_calculator.pb.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/formats/image_frame.h"
|
#include "mediapipe/framework/formats/image_frame.h"
|
||||||
@@ -99,7 +100,7 @@ absl::Status TensorToImageFrameCalculator::Process(CalculatorContext* cc) {
|
|||||||
const tf::Tensor& input_tensor = cc->Inputs().Tag(kTensor).Get<tf::Tensor>();
|
const tf::Tensor& input_tensor = cc->Inputs().Tag(kTensor).Get<tf::Tensor>();
|
||||||
int32_t depth = 1;
|
int32_t depth = 1;
|
||||||
if (input_tensor.dims() != 2) { // Depth is 1 for 2D tensors.
|
if (input_tensor.dims() != 2) { // Depth is 1 for 2D tensors.
|
||||||
CHECK(3 == input_tensor.dims())
|
ABSL_CHECK(3 == input_tensor.dims())
|
||||||
<< "Only 2 or 3-D Tensors can be converted to frames. Instead got: "
|
<< "Only 2 or 3-D Tensors can be converted to frames. Instead got: "
|
||||||
<< input_tensor.dims();
|
<< input_tensor.dims();
|
||||||
depth = input_tensor.dim_size(2);
|
depth = input_tensor.dim_size(2);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user