Skip to content

Commit

Permalink
Add Holoviz feature samples (#452)
Browse files Browse the repository at this point in the history
* Add Holoviz feature samples

- sRGB example
- vsync example

This is using cookiecutter to generate the various examples from
a template.

Signed-off-by: Andreas Heumann <aheumann@nvidia.com>

* Update applications/holoviz/template/cookiecutter-holoviz/{{cookiecutter.project_slug}}/README.md

Minor spelling fix

Signed-off-by: Tom Birdsong <40648863+tbirdso@users.noreply.github.com>

* Update applications/holoviz/holoviz_srgb/README.md

Minor spelling fix

Signed-off-by: Tom Birdsong <40648863+tbirdso@users.noreply.github.com>

---------

Signed-off-by: Andreas Heumann <aheumann@nvidia.com>
Signed-off-by: Tom Birdsong <40648863+tbirdso@users.noreply.github.com>
Co-authored-by: Tom Birdsong <40648863+tbirdso@users.noreply.github.com>
  • Loading branch information
AndreasHeumann and tbirdso authored Jul 31, 2024
1 parent fb8fb56 commit e8af6cc
Show file tree
Hide file tree
Showing 23 changed files with 1,044 additions and 0 deletions.
2 changes: 2 additions & 0 deletions applications/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ add_subdirectory(h264)
add_holohub_application(high_speed_endoscopy DEPENDS
OPERATORS emergent_source)

add_subdirectory(holoviz)

add_holohub_application(hyperspectral_segmentation)

add_holohub_application(multiai_endoscopy)
Expand Down
17 changes: 17 additions & 0 deletions applications/holoviz/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# 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.

add_holohub_application(holoviz_srgb)
add_holohub_application(holoviz_vsync)
41 changes: 41 additions & 0 deletions applications/holoviz/holoviz_srgb/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# 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.

cmake_minimum_required(VERSION 3.20)

project(holoviz_srgb)

find_package(holoscan 2.3 REQUIRED CONFIG
PATHS "/opt/nvidia/holoscan" "/workspace/holoscan-sdk/install")

add_executable(holoviz_srgb
holoviz_srgb.cpp
)

target_link_libraries(holoviz_srgb
PRIVATE
holoscan::core
holoscan::ops::holoviz
)

if(BUILD_TESTING)
# Add test
add_test(NAME holoviz_srgb_test
COMMAND holoviz_srgb
--count=10
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_tests_properties(holoviz_srgb_test PROPERTIES
PASS_REGULAR_EXPRESSION "Application has finished running.")
endif()
39 changes: 39 additions & 0 deletions applications/holoviz/holoviz_srgb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Holoviz sRGB

![](holoviz_srgb.png)<br>
This application demonstrates the handling of the sRGB color space supported by the Holoviz operator.

The Holoviz operator can convert sRGB input images to linear color space before rendering and also can convert from linear color space to sRGB before writing to the frame buffer.

sRGB color space can be enabled for input images and for the frame buffer independently. By default, the sRGB color space is disabled for both.

By default, the Holoviz operator is auto detecting the input image format. Auto detection always assumes linear color space for input images. To change this to sRGB color space explicitly set the `image_format_` member of the input spec for that input image to a format ending with `SRGB`:

```cpp
// By default the image format is auto detected. Auto detection assumes linear color space,
// but we provide an sRGB encoded image. Create an input spec and change the image format to
// sRGB.
ops::HolovizOp::InputSpec input_spec("image", ops::HolovizOp::InputType::COLOR);
input_spec.image_format_ = ops::HolovizOp::ImageFormat::R8G8B8_SRGB;

auto holoviz = make_operator<ops::HolovizOp>(
"holoviz",
Arg("tensors", std::vector<ops::HolovizOp::InputSpec>{input_spec}));
```
By default, the frame buffer is using linear color space. To use the sRGB color space, set the `framebuffer_srbg` argument of the Holoviz operator to `true`:
```cpp
auto holoviz = make_operator<ops::HolovizOp>(
"holoviz",
// enable the sRGB frame buffer
Arg("framebuffer_srbg", true));
```

## Run Instructions

To build and start the application:

```bash
./dev_container build_and_run holoviz_srgb
```
175 changes: 175 additions & 0 deletions applications/holoviz/holoviz_srgb/holoviz_srgb.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* 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 <holoscan/holoscan.hpp>
#include <holoscan/operators/holoviz/holoviz.hpp>
#include <string>

#include <getopt.h>

namespace holoscan::ops {

class SourceOp : public Operator {
public:
HOLOSCAN_OPERATOR_FORWARD_ARGS(SourceOp);

void initialize() override {
shape_ = nvidia::gxf::Shape{64, 64, 3};
element_type_ = nvidia::gxf::PrimitiveType::kUnsigned8;
element_size_ = nvidia::gxf::PrimitiveTypeSize(element_type_);
strides_ = nvidia::gxf::ComputeTrivialStrides(shape_, element_size_);

data_.resize(strides_[0] * shape_.dimension(0));

// create an RGB image with random values
for (size_t y = 0; y < shape_.dimension(0); ++y) {
for (size_t x = 0; x < shape_.dimension(1); ++x) {
for (size_t component = 0; component < shape_.dimension(2); ++component) {
float value;
switch (component) {
case 0:
value = float(x) / shape_.dimension(1);
break;
case 1:
value = float(y) / shape_.dimension(0);
break;
case 2:
value = 1.f - (float(x) / shape_.dimension(1));
break;
default:
value = 1.f;
break;
}

// inverse sRGB EOTF conversion from linear to non-linear
// https://registry.khronos.org/DataFormat/specs/1.3/dataformat.1.3.html
if (value < 0.04045f) {
value /= 12.92f;
} else {
value = std::pow(((value + 0.055f) / 1.055f), 2.4f);
}

data_[y * strides_[0] + x * strides_[1] + component] = uint8_t((value * 255.f) + 0.5f);
}
}
}

Operator::initialize();
}

void setup(OperatorSpec& spec) override { spec.output<holoscan::gxf::Entity>("output"); }

void compute(InputContext& input, OutputContext& output, ExecutionContext& context) override {
auto entity = holoscan::gxf::Entity::New(&context);
auto tensor = static_cast<nvidia::gxf::Entity&>(entity).add<nvidia::gxf::Tensor>("image");
tensor.value()->wrapMemory(shape_,
element_type_,
element_size_,
strides_,
nvidia::gxf::MemoryStorageType::kSystem,
data_.data(),
nullptr);
output.emit(entity, "output");
}

private:
nvidia::gxf::Shape shape_;
nvidia::gxf::PrimitiveType element_type_;
uint64_t element_size_;
nvidia::gxf::Tensor::stride_array_t strides_;
std::vector<uint8_t> data_;
};

} // namespace holoscan::ops

class App : public holoscan::Application {
public:
explicit App(int count) : count_(count) {}
App() = delete;

void compose() override {
using namespace holoscan;

auto source =
make_operator<ops::SourceOp>("source",
// stop application count
make_condition<CountCondition>("count-condition", count_));

// By default the image format is auto detected. Auto detection assumes linear color space,
// but we provide an sRGB encoded image. Create an input spec and change the image format to
// sRGB.
ops::HolovizOp::InputSpec input_spec("image", ops::HolovizOp::InputType::COLOR);
input_spec.image_format_ = ops::HolovizOp::ImageFormat::R8G8B8_SRGB;

auto holoviz = make_operator<ops::HolovizOp>(
"holoviz",
Arg("tensors", std::vector<ops::HolovizOp::InputSpec>{input_spec}),
// enable the sRGB frame buffer
Arg("framebuffer_srgb", true),
Arg("window_title", std::string("Holoviz sRGB")),
Arg("cuda_stream_pool", make_resource<CudaStreamPool>("cuda_stream_pool", 0, 0, 0, 1, 5)));

add_flow(source, holoviz, {{"output", "receivers"}});
}

const int count_;
};

int main(int argc, char** argv) {
int count = -1;

struct option long_options[] = {
{"help", no_argument, 0, 'h'}, {"count", optional_argument, 0, 'c'}, {0, 0, 0, 0}};

// parse options
while (true) {
int option_index = 0;

const int c = getopt_long(argc, argv, "hc:", long_options, &option_index);

if (c == -1) { break; }

const std::string argument(optarg ? optarg : "");
switch (c) {
case 'h':
std::cout << "Holoscan ClaraViz volume renderer."
<< "Usage: " << argv[0] << " [options]" << std::endl
<< "Options:" << std::endl
<< " -h, --help Display this information" << std::endl
<< " -c <COUNT>, --count <COUNT> execute operators <COUNT> times (default "
"'-1' for unlimited)"
<< std::endl;
return 0;

case 'c':
count = stoi(argument);
break;

case '?':
// unknown option, error already printed by getop_long
break;
default:
holoscan::log_error("Unhandled option '{}'", static_cast<char>(c));
}
}

auto app = holoscan::make_application<App>(count);
app->run();

holoscan::log_info("Application has finished running.");
return 0;
}
1 change: 1 addition & 0 deletions applications/holoviz/holoviz_srgb/holoviz_srgb.png
35 changes: 35 additions & 0 deletions applications/holoviz/holoviz_srgb/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"application": {
"name": "Holoviz sRGB",
"authors": [
{
"name": "Holoscan Team",
"affiliation": "NVIDIA"
}
],
"language": "C++",
"version": "1.0.0",
"changelog": {
"1.0": "Initial Release"
},
"holoscan_sdk": {
"minimum_required_version": "2.3",
"tested_versions": [
"2.3"
]
},
"platforms": [
"amd64",
"arm64"
],
"tags": [
"Holoviz sRGB"
],
"ranking": 1,
"dependencies": {},
"run": {
"command": "<holohub_app_bin>/holoviz/holoviz_srgb",
"workdir": "holohub_bin"
}
}
}
41 changes: 41 additions & 0 deletions applications/holoviz/holoviz_vsync/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# 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.

cmake_minimum_required(VERSION 3.20)

project(holoviz_vsync)

find_package(holoscan 2.3 REQUIRED CONFIG
PATHS "/opt/nvidia/holoscan" "/workspace/holoscan-sdk/install")

add_executable(holoviz_vsync
holoviz_vsync.cpp
)

target_link_libraries(holoviz_vsync
PRIVATE
holoscan::core
holoscan::ops::holoviz
)

if(BUILD_TESTING)
# Add test
add_test(NAME holoviz_vsync_test
COMMAND holoviz_vsync
--count=10
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_tests_properties(holoviz_vsync_test PROPERTIES
PASS_REGULAR_EXPRESSION "Application has finished running.")
endif()
23 changes: 23 additions & 0 deletions applications/holoviz/holoviz_vsync/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Holoviz vsync

![](holoviz_vsync.png)<br>
This application demonstrates the capability of the Holoviz operator to wait for the vertical blank of the display before updating the current image. It prints the displayed frames per second to the console, if sync to vertical blank is enabled the frames per second are capped to the display refresh rate.

To enable syncing to vertical blank set the `vsync` parameter of the Holoviz operator to `true`:

```cpp
auto holoviz = make_operator<ops::HolovizOp>(
"holoviz",
// enable synchronization to vertical blank
Arg("vsync", true));
```
By default, the Holoviz operator is not syncing to the vertical blank of the display.
## Run Instructions
To build and start the application:
```bash
./dev_container build_and_run holoviz_vsync
```
Loading

0 comments on commit e8af6cc

Please sign in to comment.