Skip to content

Commit ff33107

Browse files
authored
Frame testing multiai ultrasound (nvidia-holoscan#535)
* Enabling frame validation for multiai-ultrasound application Signed-off-by: Julien Jomier <[email protected]> * Added validation frame testing for Python Signed-off-by: Julien Jomier <[email protected]> * Fix linting Signed-off-by: Julien Jomier <[email protected]> --------- Signed-off-by: Julien Jomier <[email protected]>
1 parent 1375044 commit ff33107

17 files changed

+221
-25
lines changed

applications/endoscopy_tool_tracking/python/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ if(BUILD_TESTING)
6161
DEPENDS endoscopy_tool_tracking_python_test
6262
PASS_REGULAR_EXPRESSION "Valid video output!"
6363
)
64-
6564
endif()
6665

6766
# Install application and dependencies into the install/ directory for packaging

applications/multiai_ultrasound/cpp/CMakeLists.txt

+30-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
1+
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
# SPDX-License-Identifier: Apache-2.0
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,6 +27,7 @@ target_link_libraries(multiai_ultrasound
2727
PRIVATE
2828
holoscan::core
2929
holoscan::ops::aja
30+
holoscan::ops::video_stream_recorder
3031
holoscan::ops::video_stream_replayer
3132
holoscan::ops::format_converter
3233
holoscan::ops::holoviz
@@ -57,10 +58,20 @@ add_dependencies(multiai_ultrasound mgpu_multiai_ultrasound_yaml)
5758

5859
# Add testing
5960
if(BUILD_TESTING)
60-
# Configure the yaml file to only play 10 frames
61+
set(RECORDING_DIR ${CMAKE_CURRENT_BINARY_DIR}/recording_output)
62+
set(SOURCE_VIDEO_BASENAME cpp_multiai_ultrasound_output)
63+
set(VALIDATION_FRAMES_DIR ${CMAKE_SOURCE_DIR}/applications/multiai_ultrasound/testing/)
64+
65+
file(MAKE_DIRECTORY ${RECORDING_DIR})
66+
67+
# Configure the yaml file for testing
6168
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/multiai_ultrasound.yaml" CONFIG_FILE)
62-
string(REGEX REPLACE "source:[^\n]*" "source: replayer" CONFIG_FILE ${CONFIG_FILE})
6369
string(REPLACE "count: 0" "count: 10" CONFIG_FILE ${CONFIG_FILE})
70+
string(REGEX REPLACE "source:[^\n]*" "source: replayer" CONFIG_FILE ${CONFIG_FILE})
71+
string(REPLACE "record_type: \"none\"" "record_type: \"visualizer\"" CONFIG_FILE ${CONFIG_FILE})
72+
string(REPLACE "directory: \"/tmp\"" "directory: \"${RECORDING_DIR}\"" CONFIG_FILE ${CONFIG_FILE})
73+
string(REPLACE "basename: \"tensor\"" "basename: \"${SOURCE_VIDEO_BASENAME}\"" CONFIG_FILE ${CONFIG_FILE})
74+
6475
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/multiai_ultrasound_testing.yaml" ${CONFIG_FILE})
6576

6677
# Add test
@@ -71,4 +82,20 @@ if(BUILD_TESTING)
7182
set_tests_properties(multiai_ultrasound_cpp_test PROPERTIES
7283
PASS_REGULAR_EXPRESSION "Reach end of file or playback count reaches to the limit. Stop ticking."
7384
FAIL_REGULAR_EXPRESSION "[^a-z]Error;ERROR;Failed")
85+
86+
# Add a test to check the validity of the frames
87+
add_test(NAME multiai_ultrasound_cpp_render_test
88+
COMMAND python3 ${CMAKE_SOURCE_DIR}/utilities/video_validation.py
89+
--source_video_dir ${RECORDING_DIR}
90+
--source_video_basename ${SOURCE_VIDEO_BASENAME}
91+
--output_dir ${RECORDING_DIR}
92+
--validation_frames_dir ${VALIDATION_FRAMES_DIR}
93+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
94+
)
95+
96+
set_tests_properties(multiai_ultrasound_cpp_render_test PROPERTIES
97+
DEPENDS multiai_ultrasound_cpp_test
98+
PASS_REGULAR_EXPRESSION "Valid video output!"
99+
)
100+
74101
endif()

applications/multiai_ultrasound/cpp/main.cpp

+61-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
#include <holoscan/operators/holoviz/holoviz.hpp>
2424
#include <holoscan/operators/inference/inference.hpp>
2525
#include <holoscan/operators/inference_processor/inference_processor.hpp>
26+
#include <holoscan/operators/video_stream_recorder/video_stream_recorder.hpp>
2627
#include <holoscan/operators/video_stream_replayer/video_stream_replayer.hpp>
28+
2729
#include <holoscan/version_config.hpp>
2830

2931
#include <visualizer_icardio.hpp>
@@ -37,12 +39,25 @@ class App : public holoscan::Application {
3739
if (source == "aja") { is_aja_source_ = true; }
3840
}
3941

42+
enum class Record { NONE, INPUT, VISUALIZER };
43+
44+
void set_record(const std::string& record) {
45+
if (record == "input") {
46+
record_type_ = Record::INPUT;
47+
} else if (record == "visualizer") {
48+
record_type_ = Record::VISUALIZER;
49+
}
50+
}
51+
4052
void set_datapath(const std::string& path) { datapath = path; }
4153

4254
void compose() override {
4355
using namespace holoscan;
4456

4557
std::shared_ptr<Operator> source;
58+
std::shared_ptr<Operator> recorder;
59+
std::shared_ptr<Operator> recorder_format_converter;
60+
4661
const std::shared_ptr<CudaStreamPool> cuda_stream_pool =
4762
make_resource<CudaStreamPool>("cuda_stream");
4863

@@ -143,10 +158,34 @@ class App : public holoscan::Application {
143158
Arg("cuda_stream_pool") = cuda_stream_pool);
144159

145160
auto holoviz = make_operator<ops::HolovizOp>(
146-
"holoviz", from_config("holoviz"), Arg("cuda_stream_pool") = cuda_stream_pool);
161+
"holoviz", from_config("holoviz"),
162+
Arg("enable_render_buffer_output") = (record_type_ == Record::VISUALIZER),
163+
Arg("allocator") =
164+
make_resource<BlockMemoryPool>("visualizer_allocator",
165+
(int32_t)nvidia::gxf::MemoryStorageType::kDevice,
166+
// max from VisualizerICardioOp::tensor_to_shape_
167+
320 * 320 * 4 * sizeof(uint8_t),
168+
1 * 8),
169+
Arg("cuda_stream_pool") = cuda_stream_pool);
147170

148-
// Flow definition
149171

172+
// Add recording operators
173+
if (record_type_ != Record::NONE) {
174+
if (((record_type_ == Record::INPUT) && is_aja_source_) ||
175+
(record_type_ == Record::VISUALIZER)) {
176+
recorder_format_converter = make_operator<ops::FormatConverterOp>(
177+
"recorder_format_converter",
178+
from_config("recorder_format_converter"),
179+
Arg("pool") =
180+
make_resource<BlockMemoryPool>("pool",
181+
(int32_t)nvidia::gxf::MemoryStorageType::kDevice,
182+
320 * 320 * 4 * sizeof(uint8_t),
183+
1 * 8));
184+
}
185+
recorder = make_operator<ops::VideoStreamRecorderOp>("recorder", from_config("recorder"));
186+
}
187+
188+
// Flow definition
150189
const std::string source_port_name = is_aja_source_ ? "video_buffer_output" : "";
151190
add_flow(source, plax_cham_pre, {{source_port_name, ""}});
152191
add_flow(source, aortic_ste_pre, {{source_port_name, ""}});
@@ -168,10 +207,26 @@ class App : public holoscan::Application {
168207
add_flow(visualizer_icardio, holoviz, {{"keyarea_5", "receivers"}});
169208
add_flow(visualizer_icardio, holoviz, {{"lines", "receivers"}});
170209
add_flow(visualizer_icardio, holoviz, {{"logo", "receivers"}});
210+
211+
212+
if (record_type_ == Record::INPUT) {
213+
if (is_aja_source_) {
214+
add_flow(source, recorder_format_converter, {{source_port_name, "source_video"}});
215+
add_flow(recorder_format_converter, recorder);
216+
} else {
217+
add_flow(source, recorder);
218+
}
219+
} else if (record_type_ == Record::VISUALIZER) {
220+
add_flow(holoviz,
221+
recorder_format_converter,
222+
{{"render_buffer_output", "source_video"}});
223+
add_flow(recorder_format_converter, recorder);
224+
}
171225
}
172226

173227
private:
174228
bool is_aja_source_ = false;
229+
Record record_type_ = Record::NONE;
175230
std::string datapath = "data/multiai_ultrasound";
176231
};
177232

@@ -214,6 +269,10 @@ int main(int argc, char** argv) {
214269

215270
auto source = app->from_config("source").as<std::string>();
216271
app->set_source(source);
272+
273+
auto record_type = app->from_config("record_type").as<std::string>();
274+
app->set_record(record_type);
275+
217276
if (data_path != "") app->set_datapath(data_path);
218277
app->run();
219278

applications/multiai_ultrasound/cpp/multiai_ultrasound.yaml

+11-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
# limitations under the License.
1616
---
1717
source: "replayer" # or "aja"
18-
do_record: false # or 'true' if you want to record input video stream.
1918

2019
replayer:
2120
basename: "icardio_input1"
@@ -24,6 +23,9 @@ replayer:
2423
realtime: true # default: true
2524
count: 0 # default: 0 (no frame count restriction)
2625

26+
record_type: "none" # or "input" if you want to record input video stream, or "visualizer" if you want
27+
# to record the visualizer output.
28+
2729
aja: # AJASourceOp
2830
width: 1920
2931
height: 1080
@@ -140,3 +142,11 @@ holoviz:
140142
width: 320
141143
height: 320
142144
use_exclusive_display: false
145+
146+
recorder_format_converter:
147+
in_dtype: "rgba8888"
148+
out_dtype: "rgb888"
149+
150+
recorder:
151+
directory: "/tmp"
152+
basename: "tensor"
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
1+
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
# SPDX-License-Identifier: Apache-2.0
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,26 +16,50 @@
1616
# Add testing
1717
if(BUILD_TESTING)
1818
# To get the environment path
19-
find_package(holoscan 0.6 REQUIRED CONFIG
20-
PATHS "/opt/nvidia/holoscan" "/workspace/holoscan-sdk/install")
19+
find_package(holoscan 1.0 REQUIRED CONFIG PATHS "/opt/nvidia/holoscan" "/workspace/holoscan-sdk/install")
2120

22-
# Configure the yaml file to only play 10 frames
21+
set(RECORDING_DIR ${CMAKE_CURRENT_BINARY_DIR}/recording_output)
22+
set(SOURCE_VIDEO_BASENAME python_multiai_ultrasound_output)
23+
set(VALIDATION_FRAMES_DIR ${CMAKE_SOURCE_DIR}/applications/multiai_ultrasound/testing/)
24+
25+
file(MAKE_DIRECTORY ${RECORDING_DIR})
26+
27+
# Configure the yaml file for testing
2328
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/multiai_ultrasound.yaml" CONFIG_FILE)
24-
string(REGEX REPLACE "source:[^\n]*" "source: replayer" CONFIG_FILE ${CONFIG_FILE})
2529
string(REPLACE "count: 0" "count: 10" CONFIG_FILE ${CONFIG_FILE})
26-
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/multiai_ultrasound_testing.yaml ${CONFIG_FILE})
30+
string(REGEX REPLACE "source:[^\n]*" "source: replayer" CONFIG_FILE ${CONFIG_FILE})
31+
string(REPLACE "directory: \"/tmp\"" "directory: \"${RECORDING_DIR}\"" CONFIG_FILE ${CONFIG_FILE})
32+
string(REPLACE "basename: \"tensor\"" "basename: \"${SOURCE_VIDEO_BASENAME}\"" CONFIG_FILE ${CONFIG_FILE})
33+
34+
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/multiai_ultrasound_testing.yaml" ${CONFIG_FILE})
2735

2836
# Add test
2937
add_test(NAME multiai_ultrasound_python_test
30-
COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/multiai_ultrasound.py
31-
--config ${CMAKE_CURRENT_BINARY_DIR}/multiai_ultrasound_testing.yaml
32-
--data "${HOLOHUB_DATA_DIR}/multiai_ultrasound"
33-
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
38+
COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/multiai_ultrasound.py
39+
--config ${CMAKE_CURRENT_BINARY_DIR}/multiai_ultrasound_testing.yaml
40+
--data "${HOLOHUB_DATA_DIR}/multiai_ultrasound"
41+
--record_type visualizer
42+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
3443

3544
set_property(TEST multiai_ultrasound_python_test PROPERTY ENVIRONMENT
36-
"PYTHONPATH=${GXF_LIB_DIR}/../python/lib:${CMAKE_BINARY_DIR}/python/lib")
45+
"PYTHONPATH=${GXF_LIB_DIR}/../python/lib:${CMAKE_BINARY_DIR}/python/lib")
46+
47+
set_tests_properties(multiai_ultrasound_python_test PROPERTIES
48+
PASS_REGULAR_EXPRESSION "Reach end of file or playback count reaches to the limit. Stop ticking.;"
49+
FAIL_REGULAR_EXPRESSION "[^a-z]Error;ERROR;Failed")
50+
51+
# Add a test to check the validity of the frames
52+
add_test(NAME multiai_ultrasound_python_render_test
53+
COMMAND python3 ${CMAKE_SOURCE_DIR}/utilities/video_validation.py
54+
--source_video_dir ${RECORDING_DIR}
55+
--source_video_basename ${SOURCE_VIDEO_BASENAME}
56+
--output_dir ${RECORDING_DIR}
57+
--validation_frames_dir ${VALIDATION_FRAMES_DIR}
58+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
59+
)
3760

38-
set_tests_properties(multiai_ultrasound_python_test
39-
PROPERTIES PASS_REGULAR_EXPRESSION "Reach end of file or playback count reaches to the limit. Stop ticking.;"
40-
FAIL_REGULAR_EXPRESSION "[^a-z]Error;ERROR;Failed")
61+
set_tests_properties(multiai_ultrasound_python_render_test PROPERTIES
62+
DEPENDS multiai_ultrasound_python_test
63+
PASS_REGULAR_EXPRESSION "Valid video output!"
64+
)
4165
endif()

0 commit comments

Comments
 (0)