From 7c82b828c81c48d12875a291c0a0daa7b3235cbe Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 17 Oct 2025 05:19:22 -0500 Subject: [PATCH 01/77] Add support for ColorCast --- rocAL/include/api/rocal_api_augmentation.h | 36 ++++++ .../augmentations/augmentations_nodes.h | 1 + .../color_augmentations/node_color_cast.h | 51 +++++++++ rocAL/source/api/rocal_api_augmentation.cpp | 57 ++++++++++ .../color_augmentations/node_color_cast.cpp | 106 ++++++++++++++++++ rocAL_pybind/amd/rocal/fn.py | 18 +++ rocAL_pybind/rocal_pybind.cpp | 4 + tests/cpp_api/unit_tests/unit_tests.cpp | 10 ++ tests/python_api/unit_test.py | 8 +- tests/python_api/unit_tests.sh | 1 + 10 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 rocAL/include/augmentations/color_augmentations/node_color_cast.h create mode 100644 rocAL/source/augmentations/color_augmentations/node_color_cast.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 10a4e001d..258cf2c26 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -930,6 +930,42 @@ extern "C" RocalTensor ROCAL_API_CALL rocalColorTwistFixed(RocalContext context, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies color cast to images by blending a per-sample RGB color with input using alpha. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] alpha parameter that controls blending amount for color cast per sample (0..1) + * \param [in] rgb vector specifying the target color to cast. Can be a single triplet [r,g,b] replicated across batch or per-sample triplets of size batch*3 + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalColorCast(RocalContext context, RocalTensor input, + bool is_output, + RocalFloatParam alpha, + std::vector& rgb, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies color cast to images with fixed parameters. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] alpha fixed blending amount for color cast (0..1) + * \param [in] rgb vector specifying the target color to cast. Can be a single triplet [r,g,b] replicated across batch or per-sample triplets of size batch*3 + * \param [in] is_output is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalColorCastFixed(RocalContext context, RocalTensor input, + float alpha, + std::vector& rgb, + bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Fused function which performs crop, normalize and flip on images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 0d93109f7..7bef78ee8 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -44,6 +44,7 @@ THE SOFTWARE. #include "augmentations/geometry_augmentations/node_resize.h" #include "augmentations/geometry_augmentations/node_rotate.h" #include "augmentations/color_augmentations/node_color_twist.h" +#include "augmentations/color_augmentations/node_color_cast.h" #include "augmentations/color_augmentations/node_hue.h" #include "augmentations/color_augmentations/node_saturation.h" #include "augmentations/geometry_augmentations/node_crop_mirror_normalize.h" diff --git a/rocAL/include/augmentations/color_augmentations/node_color_cast.h b/rocAL/include/augmentations/color_augmentations/node_color_cast.h new file mode 100644 index 000000000..e6d3fb0cf --- /dev/null +++ b/rocAL/include/augmentations/color_augmentations/node_color_cast.h @@ -0,0 +1,51 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" + +class ColorCastNode : public Node { + public: + ColorCastNode(const std::vector &inputs, const std::vector &outputs); + ColorCastNode() = delete; + + // Per-sample alpha as random parameter, and RGB triplet(s) + void init(FloatParam *alpha_param, std::vector rgb); + // Fixed alpha and RGB triplet(s) + void init(float alpha, std::vector rgb); + + protected: + void create_node() override; + void update_node() override; + + private: + // Per-sample alpha (size batch_size) + ParameterVX _alpha; + // Flat RGB triplets (size batch_size * 3) + std::vector _rgb; + vx_array _rgb_vx_array = nullptr; + + // Reasonable range for alpha [0, 1] + constexpr static float ALPHA_RANGE[2] = {0.0f, 1.0f}; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index fdce0f00a..9c5dbceba 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -1645,6 +1645,63 @@ rocalColorTwistFixed( return output; } +RocalTensor ROCAL_API_CALL +rocalColorCast( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_alpha, + std::vector& rgb, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto alpha = static_cast(p_alpha); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(alpha, rgb); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalColorCastFixed( + RocalContext p_context, + RocalTensor p_input, + float alpha, + std::vector& rgb, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(alpha, rgb); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalCropMirrorNormalize(RocalContext p_context, RocalTensor p_input, unsigned crop_height, unsigned crop_width, float start_x, float start_y, std::vector& mean, diff --git a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp new file mode 100644 index 000000000..423332f04 --- /dev/null +++ b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp @@ -0,0 +1,106 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/color_augmentations/node_color_cast.h" +#include "pipeline/exception.h" + +namespace { +static void fill_rgb_for_batch(std::vector &rgb_out, unsigned batch_size, const std::vector &rgb_in) { + rgb_out.resize(batch_size * 3); + if (rgb_in.size() == 3) { + // Replicate a single triplet across the batch + for (unsigned i = 0; i < batch_size; ++i) { + unsigned base = i * 3; + rgb_out[base + 0] = rgb_in[0]; + rgb_out[base + 1] = rgb_in[1]; + rgb_out[base + 2] = rgb_in[2]; + } + } else if (rgb_in.size() == batch_size * 3) { + // Copy per-sample triplets + rgb_out = rgb_in; + } else { + // Invalid size, default to zeros + for (unsigned i = 0; i < batch_size; ++i) { + unsigned base = i * 3; + rgb_out[base + 0] = 0.0f; + rgb_out[base + 1] = 0.0f; + rgb_out[base + 2] = 0.0f; + } + } +} +} // namespace + +ColorCastNode::ColorCastNode(const std::vector &inputs, const std::vector &outputs) + : Node(inputs, outputs), + _alpha(ALPHA_RANGE[0], ALPHA_RANGE[1]) {} + +void ColorCastNode::create_node() { + if (_node) + return; + + // Create per-sample arrays + _alpha.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + + // Create and populate the RGB array (flat size = batch_size * 3) + vx_status status = VX_SUCCESS; + _rgb_vx_array = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, _batch_size * 3); + status |= vxAddArrayItems(_rgb_vx_array, _rgb.size(), _rgb.data(), sizeof(vx_float32)); + if (status != 0) + THROW(" vxAddArrayItems failed in the ColorCast (vxExtRppColorCast) node: " + TOSTR(status) + " " + TOSTR(status)) + + // Layouts & ROI type + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + + // Build node + _node = vxExtRppColorCast(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), + _rgb_vx_array, _alpha.default_array(), input_layout_vx, output_layout_vx, roi_type_vx); + vx_status nstatus; + if ((nstatus = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the ColorCast (vxExtRppColorCast) node failed: " + TOSTR(nstatus)) +} + +void ColorCastNode::init(FloatParam *alpha_param, std::vector rgb) { + _alpha.set_param(core(alpha_param)); + fill_rgb_for_batch(_rgb, _batch_size, rgb); +} + +void ColorCastNode::init(float alpha, std::vector rgb) { + _alpha.set_param(alpha); + fill_rgb_for_batch(_rgb, _batch_size, rgb); +} + +void ColorCastNode::update_node() { + _alpha.update_array(); + // Update the RGB array content if present + if (_rgb_vx_array) { + vx_status status = VX_SUCCESS; + status = vxCopyArrayRange(_rgb_vx_array, 0, _batch_size * 3, sizeof(vx_float32), _rgb.data(), VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); + if (status != 0) + THROW(" vxCopyArrayRange failed in update_node (ColorCast): " + TOSTR(status)) + } +} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 109cd27c6..c08f1ea0c 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -909,6 +909,24 @@ def color_twist(*inputs, brightness=1.0, contrast=1.0, hue=0.0, Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (color_twist_image) +def color_cast(*inputs, alpha=1.0, rgb=[0.0, 0.0, 0.0], device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies color cast by blending a target RGB color with the input using alpha. + + @param inputs the input image passed to the augmentation + @param alpha (float or FloatParam, default = 1.0) blending amount for the cast (0..1). If float, wrapped into a FloatParam. + @param rgb (list of floats, default = [0.0, 0.0, 0.0]) target color to cast; can be a single triplet [r,g,b] or per-sample triplets with length batch*3 + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Image with color cast applied + """ + alpha = b.createFloatParameter(alpha) if isinstance(alpha, float) else alpha + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "p_alpha": alpha, "rgb": rgb, + "output_layout": output_layout, "output_dtype": output_dtype} + color_cast_image = b.colorCast(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (color_cast_image) + def uniform(*inputs, range=[-1, 1], device=None): """!Applies uniform random number generation to the input images. diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index 10a7a6c1f..ca058efe9 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1083,6 +1083,10 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("colorTwistFixed", &rocalColorTwistFixed, py::return_value_policy::reference); + m.def("colorCast", &rocalColorCast, + py::return_value_policy::reference); + m.def("colorCastFixed", &rocalColorCastFixed, + py::return_value_policy::reference); m.def("cropMirrorNormalize", &rocalCropMirrorNormalize, py::return_value_policy::reference); m.def("crop", &rocalCrop, diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 57097983b..d74a4a856 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -884,6 +884,16 @@ int test(int test_case, int reader_type, const char *path, const char *outName, std::vector aspect_ratio = {3.0f / 4, 4.0f / 3}; output = rocalRandomResizedCrop(handle, input, resize_w, resize_h, true, area_factor, aspect_ratio); } break; + case 64: { + std::cout << "Running rocalColorCast" << std::endl; + std::vector rgb = {0.25f, 0.10f, 0.00f}; + output = rocalColorCast(handle, input, true, float_param, rgb, output_tensor_layout, output_tensor_dtype); + } break; + case 65: { + std::cout << "Running rocalColorCastFixed" << std::endl; + std::vector rgb = {0.25f, 0.10f, 0.00f}; + output = rocalColorCastFixed(handle, input, 0.5f, rgb, true, output_tensor_layout, output_tensor_dtype); + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index b8c55d7ca..4818d3f7e 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -91,7 +91,7 @@ def main(): if (scaling_mode != types.SCALING_MODE_DEFAULT and interpolation_type != types.LINEAR_INTERPOLATION): interpolation_type = types.LINEAR_INTERPOLATION - if augmentation_name in ["hue", "saturation", "color_twist"] and color_format == types.GRAY: + if augmentation_name in ["hue", "saturation", "color_twist", "color_cast"] and color_format == types.GRAY: print("Not a valid option! Exiting!") sys.exit(0) @@ -394,6 +394,12 @@ def main(): saturation=0.25, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "color_cast": + output = fn.color_cast(images, + alpha=0.5, + rgb=[0.25, 0.10, 0.00], + output_layout=tensor_layout, + output_dtype=tensor_dtype) elif augmentation_name == "crop": output = fn.crop(images, crop=(3, 224, 224), diff --git a/tests/python_api/unit_tests.sh b/tests/python_api/unit_tests.sh index a160dd7fb..e6104ce0f 100755 --- a/tests/python_api/unit_tests.sh +++ b/tests/python_api/unit_tests.sh @@ -112,6 +112,7 @@ do # caffe detection python"$ver" unit_test.py --image-dataset-path "$caffe_detection_path" --reader-type "caffe_detection" --augmentation-name saturation --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Saturation_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$caffe_detection_path" --reader-type "caffe_detection" --augmentation-name color_twist --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}ColorTwist_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$caffe_detection_path" --reader-type "caffe_detection" --augmentation-name color_cast --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}ColorCast_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$caffe_detection_path" --reader-type "caffe_detection" --augmentation-name rain --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Rain_${rgb_name[$rgb]}_${device_name}" # caffe2 classification From bb5fd27b8cba6d4948d50add6bda871861d188aa Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 22 Oct 2025 03:04:28 -0500 Subject: [PATCH 02/77] Add support for grid mask augmentation --- rocAL/include/api/rocal_api_augmentation.h | 24 ++++++ .../augmentations/augmentations_nodes.h | 1 + .../effects_augmentations/node_grid_mask.h | 45 +++++++++++ rocAL/source/api/rocal_api_augmentation.cpp | 31 ++++++++ .../effects_augmentations/node_grid_mask.cpp | 78 +++++++++++++++++++ rocAL_pybind/amd/rocal/fn.py | 31 ++++++++ rocAL_pybind/rocal_pybind.cpp | 2 + tests/cpp_api/unit_tests/unit_tests.cpp | 9 +++ tests/python_api/unit_test.py | 9 +++ 9 files changed, 230 insertions(+) create mode 100644 rocAL/include/augmentations/effects_augmentations/node_grid_mask.h create mode 100644 rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 258cf2c26..217a468c8 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -774,6 +774,30 @@ extern "C" RocalTensor ROCAL_API_CALL rocalPixelate(RocalContext context, RocalT RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies a grid mask effect to images by overlaying a grid of transparent/opaque tiles. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] tile_width width of each grid tile in pixels + * \param [in] grid_ratio ratio of masked area within a tile (0..1) + * \param [in] grid_angle angle of the grid in radians + * \param [in] translate_x translation offset in x for the grid origin + * \param [in] translate_y translation offset in y for the grid origin + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalGridMask(RocalContext context, RocalTensor input, + bool is_output, + unsigned tile_width, + float grid_ratio, + float grid_angle, + unsigned translate_x, + unsigned translate_y, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Adjusts the exposure in images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 7bef78ee8..0ba81caf1 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -32,6 +32,7 @@ THE SOFTWARE. #include "augmentations/color_augmentations/node_color_temperature.h" #include "augmentations/effects_augmentations/node_fog.h" #include "augmentations/effects_augmentations/node_pixelate.h" +#include "augmentations/effects_augmentations/node_grid_mask.h" #include "augmentations/geometry_augmentations/node_lens_correction.h" #include "augmentations/color_augmentations/node_gamma.h" #include "augmentations/geometry_augmentations/node_flip.h" diff --git a/rocAL/include/augmentations/effects_augmentations/node_grid_mask.h b/rocAL/include/augmentations/effects_augmentations/node_grid_mask.h new file mode 100644 index 000000000..3b6a82d2c --- /dev/null +++ b/rocAL/include/augmentations/effects_augmentations/node_grid_mask.h @@ -0,0 +1,45 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once + +#include "pipeline/node.h" + +class GridMaskNode : public Node { + public: + GridMaskNode(const std::vector &inputs, const std::vector &outputs); + GridMaskNode() = delete; + + // Scalar-only parameters (uniform across the batch) + void init(unsigned tile_width, float grid_ratio, float grid_angle_radians, unsigned translate_x, unsigned translate_y); + + protected: + void create_node() override; + void update_node() override; + + private: + unsigned _tile_width = 0; + float _grid_ratio = 0.0f; + float _grid_angle = 0.0f; // radians + unsigned _translate_x = 0; + unsigned _translate_y = 0; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 9c5dbceba..eb8dd0833 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -1490,6 +1490,37 @@ rocalPixelate( return output; } +RocalTensor ROCAL_API_CALL +rocalGridMask( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + unsigned tile_width, + float grid_ratio, + float grid_angle, + unsigned translate_x, + unsigned translate_y, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(tile_width, grid_ratio, grid_angle, translate_x, translate_y); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalLensCorrection( RocalContext p_context, diff --git a/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp new file mode 100644 index 000000000..9e2dfa0b4 --- /dev/null +++ b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp @@ -0,0 +1,78 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "augmentations/effects_augmentations/node_grid_mask.h" + +#include + +#include "pipeline/exception.h" + +GridMaskNode::GridMaskNode(const std::vector &inputs, const std::vector &outputs) + : Node(inputs, outputs) {} + +void GridMaskNode::create_node() { + if (_node) + return; + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + + vx_scalar tile_width_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &_tile_width); + vx_scalar grid_ratio_vx = vxCreateScalar(ctx, VX_TYPE_FLOAT32, &_grid_ratio); + vx_scalar grid_angle_vx = vxCreateScalar(ctx, VX_TYPE_FLOAT32, &_grid_angle); + vx_scalar translate_x_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &_translate_x); + vx_scalar translate_y_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &_translate_y); + + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); + + _node = vxExtRppGridMask(_graph->get(), + _inputs[0]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + tile_width_vx, + grid_ratio_vx, + grid_angle_vx, + translate_x_vx, + translate_y_vx, + input_layout_vx, + output_layout_vx, + roi_type_vx); + + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the grid mask (vxExtRppGridMask) node failed: " + TOSTR(status)) +} + +void GridMaskNode::init(unsigned tile_width, float grid_ratio, float grid_angle_radians, unsigned translate_x, unsigned translate_y) { + _tile_width = tile_width; + _grid_ratio = grid_ratio; + _grid_angle = grid_angle_radians; + _translate_x = translate_x; + _translate_y = translate_y; +} + +void GridMaskNode::update_node() {} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index c08f1ea0c..9cdea292e 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -371,6 +371,37 @@ def pixelate(*inputs, device=None, pixelate_percent=50.0, output_layout=types.NH return (pixelate_image) +def grid_mask(*inputs, tile_width=16, grid_ratio=0.5, grid_angle=0.0, translate_x=0, translate_y=0, + device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies GridMask effect by overlaying a grid of tiles with a masked ratio. + + @param inputs the input image passed to the augmentation + @param tile_width (int, default = 16) width of each grid tile in pixels + @param grid_ratio (float, default = 0.5) ratio of masked area within a tile (0..1) + @param grid_angle (float, default = 0.0) angle of the grid in radians + @param translate_x (int, default = 0) translation offset in x for the grid origin + @param translate_y (int, default = 0) translation offset in y for the grid origin + @param device (string, optional) Parameter unused for augmentation + @param output_layout (int, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, default = types.UINT8) tensor dtype for the augmentation output + + @return Image with grid mask effect applied + """ + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "tile_width": tile_width, + "grid_ratio": grid_ratio, + "grid_angle": grid_angle, + "translate_x": translate_x, + "translate_y": translate_y, + "output_layout": output_layout, + "output_dtype": output_dtype + } + grid_mask_image = b.gridMask(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (grid_mask_image) + + def rain(*inputs, rain=None, rain_width=0, rain_height=0, rain_transparency=None, rain_slant_angle=0.0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies Rain effect on images diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index ca058efe9..e8cf10dcb 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1133,6 +1133,8 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("pixelate", &rocalPixelate, py::return_value_policy::reference); + m.def("gridMask", &rocalGridMask, + py::return_value_policy::reference); m.def("blend", &rocalBlend, py::return_value_policy::reference); m.def("randomCrop", &rocalRandomCrop, diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index d74a4a856..48b58070c 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -894,6 +894,15 @@ int test(int test_case, int reader_type, const char *path, const char *outName, std::vector rgb = {0.25f, 0.10f, 0.00f}; output = rocalColorCastFixed(handle, input, 0.5f, rgb, true, output_tensor_layout, output_tensor_dtype); } break; + case 66: { + std::cout << "Running rocalGridMask" << std::endl; + unsigned tile_width = 32; + float grid_ratio = 0.5f; + float grid_angle = 0.0f; // radians + unsigned translate_x = 0; + unsigned translate_y = 0; + output = rocalGridMask(handle, input, true, tile_width, grid_ratio, grid_angle, translate_x, translate_y, output_tensor_layout, output_tensor_dtype); + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 4818d3f7e..af1112c1f 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -371,6 +371,15 @@ def main(): output = fn.pixelate(images, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "grid_mask": + output = fn.grid_mask(images, + tile_width=32, + grid_ratio=0.5, + grid_angle=0.0, + translate_x=0, + translate_y=0, + output_layout=tensor_layout, + output_dtype=tensor_dtype) elif augmentation_name == "exposure": output = fn.exposure(images, exposure=1.0, From c6365d4c412c06eb710abdce2b15348483975bb2 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 22 Oct 2025 08:59:50 -0500 Subject: [PATCH 03/77] Add NonLinearBlend support in rocAL --- rocAL/include/api/rocal_api_augmentation.h | 33 +++++++++ .../augmentations/augmentations_nodes.h | 1 + .../node_non_linear_blend.h | 45 ++++++++++++ rocAL/source/api/rocal_api_augmentation.cpp | 63 +++++++++++++++++ .../node_non_linear_blend.cpp | 70 +++++++++++++++++++ rocAL_pybind/amd/rocal/fn.py | 33 +++++++++ rocAL_pybind/rocal_pybind.cpp | 4 ++ tests/cpp_api/unit_tests/unit_tests.cpp | 12 ++++ tests/python_api/unit_test.py | 14 +++- tests/python_api/unit_tests.sh | 1 + 10 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h create mode 100644 rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 217a468c8..f55daad0e 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -425,6 +425,39 @@ extern "C" RocalTensor ROCAL_API_CALL rocalBlendFixed(RocalContext context, Roca RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Non-linear blend of two input images using per-sample stddev parameter. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 Input1 Rocal tensor + * \param [in] input2 Input2 Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] stddev Rocal parameter defining the per-sample stddev for non-linear blend + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlend(RocalContext context, RocalTensor input1, RocalTensor input2, + bool is_output, + RocalFloatParam stddev = NULL, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Non-linear blend of two input images using a fixed stddev parameter. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 Input1 Rocal tensor + * \param [in] input2 Input2 Rocal tensor + * \param [in] stddev fixed stddev for non-linear blend + * \param [in] is_output is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlendFixed(RocalContext context, RocalTensor input1, RocalTensor input2, + float stddev, bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Applies affine transformation to images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 0ba81caf1..a465000ed 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -42,6 +42,7 @@ THE SOFTWARE. #include "augmentations/color_augmentations/node_blur.h" #include "augmentations/geometry_augmentations/node_fisheye.h" #include "augmentations/color_augmentations/node_blend.h" +#include "augmentations/color_augmentations/node_non_linear_blend.h" #include "augmentations/geometry_augmentations/node_resize.h" #include "augmentations/geometry_augmentations/node_rotate.h" #include "augmentations/color_augmentations/node_color_twist.h" diff --git a/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h b/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h new file mode 100644 index 000000000..35772b338 --- /dev/null +++ b/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h @@ -0,0 +1,45 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" + +class NonLinearBlendNode : public Node { + public: + explicit NonLinearBlendNode(const std::vector& inputs, const std::vector& outputs); + NonLinearBlendNode() = delete; + + // Fixed vs dynamic stddev init + void init(float stddev); + void init(FloatParam* stddev); + + protected: + void create_node() override; + void update_node() override; + + private: + ParameterVX _stddev; + // Conservative default range; actual values are user-controlled + constexpr static float STDDEV_RANGE[2] = {0.05f, 0.50f}; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index eb8dd0833..416b64dc9 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -823,6 +823,69 @@ rocalBlendFixed( return output; } +RocalTensor ROCAL_API_CALL +rocalNonLinearBlend( + RocalContext p_context, + RocalTensor p_input1, + RocalTensor p_input2, + bool is_output, + RocalFloatParam p_stddev, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input1, output); + ROCAL_INVALID_INPUT_ERR(p_input2, output); + + auto context = static_cast(p_context); + auto input1 = static_cast(p_input1); + auto input2 = static_cast(p_input2); + auto stddev = static_cast(p_stddev); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input1->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input1, input2}, {output})->init(stddev); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalNonLinearBlendFixed( + RocalContext p_context, + RocalTensor p_input1, + RocalTensor p_input2, + float stddev, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input1, output); + ROCAL_INVALID_INPUT_ERR(p_input2, output); + + auto context = static_cast(p_context); + auto input1 = static_cast(p_input1); + auto input2 = static_cast(p_input2); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input1->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input1, input2}, {output})->init(stddev); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalWarpAffine( RocalContext p_context, diff --git a/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp new file mode 100644 index 000000000..76fb160d9 --- /dev/null +++ b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp @@ -0,0 +1,70 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/color_augmentations/node_non_linear_blend.h" +#include "pipeline/exception.h" + +NonLinearBlendNode::NonLinearBlendNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs), + _stddev(STDDEV_RANGE[0], STDDEV_RANGE[1]) { +} + +void NonLinearBlendNode::create_node() { + if (_node) + return; + + if (_inputs.size() < 2) + THROW("NonLinearBlend node needs two input images") + + _stddev.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + + _node = vxExtRppNonLinearBlend(_graph->get(), + _inputs[0]->handle(), + _inputs[1]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + _stddev.default_array(), + input_layout_vx, output_layout_vx, roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the NonLinearBlend (vxExtRppNonLinearBlend) node failed: " + TOSTR(status)) +} + +void NonLinearBlendNode::init(float stddev) { + _stddev.set_param(stddev); +} + +void NonLinearBlendNode::init(FloatParam* stddev) { + _stddev.set_param(core(stddev)); +} + +void NonLinearBlendNode::update_node() { + _stddev.update_array(); +} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 9cdea292e..491cc67f8 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -54,6 +54,39 @@ def blend(*inputs, ratio=None, device=None, output_layout=types.NHWC, output_dty Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (blend_image) +def non_linear_blend(*inputs, stddev=None, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Non-linear blend of two input images using per-sample stddev parameter. + + @param inputs list containing two input images + @param stddev (float, optional, default = None) standard deviation parameter controlling non-linear blend + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return non-linearly blended image + """ + stddev = b.createFloatParameter(stddev) if isinstance(stddev, float) else stddev + kwargs_pybind = {"input_image0": inputs[0], "input_image1": inputs[1], "is_output": False, "stddev": stddev, + "output_layout": output_layout, "output_dtype": output_dtype} + output_image = b.nonLinearBlend(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + +def non_linear_blend_fixed(*inputs, stddev=0.2, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Non-linear blend of two input images using a fixed stddev parameter. + + @param inputs list containing two input images + @param stddev (float, default = 0.2) fixed standard deviation parameter controlling non-linear blend + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return non-linearly blended image + """ + kwargs_pybind = {"input_image0": inputs[0], "input_image1": inputs[1], "stddev": stddev, "is_output": False, + "output_layout": output_layout, "output_dtype": output_dtype} + output_image = b.nonLinearBlendFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + def snow(*inputs, snow=0.5, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies snow effect on images. diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index e8cf10dcb..a8e64a538 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1137,6 +1137,10 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("blend", &rocalBlend, py::return_value_policy::reference); + m.def("nonLinearBlend", &rocalNonLinearBlend, + py::return_value_policy::reference); + m.def("nonLinearBlendFixed", &rocalNonLinearBlendFixed, + py::return_value_policy::reference); m.def("randomCrop", &rocalRandomCrop, py::return_value_policy::reference); m.def("colorTemp", &rocalColorTemp, diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 48b58070c..467392828 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -768,6 +768,18 @@ int test(int test_case, int reader_type, const char *path, const char *outName, RocalTensor output_1 = rocalRotateFixed(handle, input, 45, false); output = rocalBlendFixed(handle, input, output_1, 0.5, true); } break; + case 67: { + std::cout << "Running rocalNonLinearBlend" << std::endl; + RocalTensor output_1 = rocalRotate(handle, input, false); + RocalFloatParam stddev_param = rocalCreateFloatParameter(0.2f); + output = rocalNonLinearBlend(handle, input, output_1, true, stddev_param, output_tensor_layout, output_tensor_dtype); + } break; + case 68: { + std::cout << "Running rocalNonLinearBlendFixed" << std::endl; + RocalTensor output_1 = rocalRotateFixed(handle, input, 45, false); + float stddev = 0.2f; + output = rocalNonLinearBlendFixed(handle, input, output_1, stddev, true, output_tensor_layout, output_tensor_dtype); + } break; case 37: { std::cout << "Running rocalWarpAffineFixed" << std::endl; output = rocalWarpAffineFixed(handle, input, 1, 1, 0.5, 0.5, 7, 7, true); diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index af1112c1f..3f4f9b86a 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -91,7 +91,7 @@ def main(): if (scaling_mode != types.SCALING_MODE_DEFAULT and interpolation_type != types.LINEAR_INTERPOLATION): interpolation_type = types.LINEAR_INTERPOLATION - if augmentation_name in ["hue", "saturation", "color_twist", "color_cast"] and color_format == types.GRAY: + if augmentation_name in ["hue", "saturation", "color_twist", "color_cast", "non_linear_blend"] and color_format == types.GRAY: print("Not a valid option! Exiting!") sys.exit(0) @@ -483,6 +483,18 @@ def main(): ratio=0.5, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "non_linear_blend": + output1 = fn.rotate(images, + angle=45.0, + dest_width=416, + dest_height=416, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + output = fn.non_linear_blend(images, + output1, + stddev=0.2, + output_layout=tensor_layout, + output_dtype=tensor_dtype) elif augmentation_name == "resize_crop": output = fn.resize_crop(images, resize_width=416, diff --git a/tests/python_api/unit_tests.sh b/tests/python_api/unit_tests.sh index e6104ce0f..808d9e78e 100755 --- a/tests/python_api/unit_tests.sh +++ b/tests/python_api/unit_tests.sh @@ -96,6 +96,7 @@ do # tf classification python"$ver" unit_test.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name blend --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Blend_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name non_linear_blend --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}NonLinearBlend_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name warp_affine --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}WarpAffine_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name blur --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Blur_${rgb_name[$rgb]}_${device_name}" From 967555ddbb4a9be0e8b77ed118ae5e2b43950cb3 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Thu, 23 Oct 2025 06:47:09 -0500 Subject: [PATCH 04/77] Add support for the Median Filter and Gaussian filter --- rocAL/include/api/rocal_api_augmentation.h | 54 +++++++++++ .../augmentations/augmentations_nodes.h | 2 + .../node_gaussian_filter.h | 44 +++++++++ .../filter_augmentations/node_median_filter.h | 37 ++++++++ rocAL/source/api/rocal_api_augmentation.cpp | 94 +++++++++++++++++++ .../node_gaussian_filter.cpp | 73 ++++++++++++++ .../node_median_filter.cpp | 65 +++++++++++++ rocAL_pybind/amd/rocal/fn.py | 73 ++++++++++++++ rocAL_pybind/rocal_pybind.cpp | 6 ++ tests/python_api/unit_test.py | 18 ++++ 10 files changed, 466 insertions(+) create mode 100644 rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h create mode 100644 rocAL/include/augmentations/filter_augmentations/node_median_filter.h create mode 100644 rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp create mode 100644 rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index f55daad0e..214dad37b 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1465,4 +1465,58 @@ extern "C" RocalTensor ROCAL_API_CALL rocalLog1p(RocalContext p_context, RocalTensor p_input, bool is_output); +/*! \brief Applies median filter to images. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] kernel_size Median filter kernel size (pixels) + * \param [in] border_type Border handling policy (implementation specific) + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalMedianFilter(RocalContext context, RocalTensor input, + bool is_output, + int kernel_size = 3, + int border_type = 0, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies gaussian filter to images with per-sample stddev parameter. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] stddev Per-sample standard deviation parameter + * \param [in] kernel_size Gaussian filter kernel size (pixels) + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilter(RocalContext context, RocalTensor input, + bool is_output, + RocalFloatParam stddev = NULL, + int kernel_size = 3, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies gaussian filter to images with fixed stddev. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] stddev Fixed standard deviation value + * \param [in] kernel_size Gaussian filter kernel size (pixels) + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext context, RocalTensor input, + float stddev, + int kernel_size, + bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + #endif // MIVISIONX_ROCAL_API_AUGMENTATION_H diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index a465000ed..84a4c978e 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -72,3 +72,5 @@ THE SOFTWARE. #include "augmentations/audio_augmentations/node_mel_filter_bank.h" #include "augmentations/geometry_augmentations/node_transpose.h" #include "augmentations/arithmetic_augmentations/node_log1p.h" +#include "augmentations/filter_augmentations/node_median_filter.h" +#include "augmentations/filter_augmentations/node_gaussian_filter.h" diff --git a/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h b/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h new file mode 100644 index 000000000..4053cbe59 --- /dev/null +++ b/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h @@ -0,0 +1,44 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#pragma once +#include "pipeline/node.h" +#include "parameters/parameter_vx.h" + +class GaussianFilterNode : public Node { +public: + GaussianFilterNode(const std::vector& inputs, const std::vector& outputs); + GaussianFilterNode() = delete; + + // Dynamic per-sample stddev with fixed kernel size + void init(FloatParam* stddev_param, int kernel_size); + // Fixed stddev with fixed kernel size + void init(float stddev, int kernel_size); + +protected: + void create_node() override; + void update_node() override; + +private: + // Per-sample stddev (size batch_size) + ParameterVX _stddev; + int _kernel_size = 3; + + // Reasonable range for stddev > 0 + constexpr static float STDDEV_RANGE[2] = {0.01f, 64.0f}; +}; diff --git a/rocAL/include/augmentations/filter_augmentations/node_median_filter.h b/rocAL/include/augmentations/filter_augmentations/node_median_filter.h new file mode 100644 index 000000000..d254393ca --- /dev/null +++ b/rocAL/include/augmentations/filter_augmentations/node_median_filter.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#pragma once +#include "pipeline/node.h" + +class MedianFilterNode : public Node { +public: + MedianFilterNode(const std::vector& inputs, const std::vector& outputs); + MedianFilterNode() = delete; + + // Fixed parameters + void init(int kernel_size, int border_type); + +protected: + void create_node() override; + void update_node() override; + +private: + int _kernel_size = 3; + int _border_type = 0; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 416b64dc9..2cd18ba90 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -759,6 +759,100 @@ rocalBlur( return output; } +// New: Median Filter +RocalTensor ROCAL_API_CALL +rocalMedianFilter( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + int kernel_size, + int border_type, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(kernel_size, border_type); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +// New: Gaussian Filter (dynamic stddev) +RocalTensor ROCAL_API_CALL +rocalGaussianFilter( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_stddev, + int kernel_size, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto stddev = static_cast(p_stddev); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(stddev, kernel_size); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +// New: Gaussian Filter (fixed stddev) +RocalTensor ROCAL_API_CALL +rocalGaussianFilterFixed( + RocalContext p_context, + RocalTensor p_input, + float stddev, + int kernel_size, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(stddev, kernel_size); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalBlend( diff --git a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp new file mode 100644 index 000000000..481f1017d --- /dev/null +++ b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp @@ -0,0 +1,73 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#include +#include "augmentations/filter_augmentations/node_gaussian_filter.h" +#include "pipeline/exception.h" + +GaussianFilterNode::GaussianFilterNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs), + _stddev(STDDEV_RANGE[0], STDDEV_RANGE[1]) {} + +void GaussianFilterNode::init(float stddev, int kernel_size) { + _stddev.set_param(stddev); + _kernel_size = kernel_size; +} + +void GaussianFilterNode::init(FloatParam* stddev_param, int kernel_size) { + _stddev.set_param(core(stddev_param)); + _kernel_size = kernel_size; +} + +void GaussianFilterNode::create_node() { + if (_node) + return; + + // Per-sample stddev array + _stddev.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); + + vx_uint32 ksize_u32 = static_cast(_kernel_size); + vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &ksize_u32); + + _node = vxExtRppGaussianFilter(_graph->get(), + _inputs[0]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + _stddev.default_array(), + kernel_size_vx, + input_layout_vx, + output_layout_vx, + roi_type_vx); + + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the gaussian filter (vxExtRppGaussianFilter) node failed: " + TOSTR(status)) +} + +void GaussianFilterNode::update_node() { + _stddev.update_array(); +} diff --git a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp new file mode 100644 index 000000000..a743cb0b8 --- /dev/null +++ b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp @@ -0,0 +1,65 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#include +#include "augmentations/filter_augmentations/node_median_filter.h" +#include "pipeline/exception.h" + +MedianFilterNode::MedianFilterNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) {} + +void MedianFilterNode::init(int kernel_size, int border_type) { + _kernel_size = kernel_size; + _border_type = border_type; +} + +void MedianFilterNode::create_node() { + if (_node) + return; + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); + + vx_uint32 ksize_u32 = static_cast(_kernel_size); + vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &ksize_u32); + vx_int32 border_i32 = static_cast(_border_type); + vx_scalar border_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &border_i32); + + _node = vxExtRppMedianFilter(_graph->get(), + _inputs[0]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + kernel_size_vx, + border_type_vx, + input_layout_vx, + output_layout_vx, + roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the median filter (vxExtRppMedianFilter) node failed: " + TOSTR(status)) +} + +void MedianFilterNode::update_node() { + // No dynamic per-sample parameters to update +} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 491cc67f8..289f21507 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1361,3 +1361,76 @@ def log1p(*inputs, output_datatype = types.FLOAT): kwargs_pybind = {"input_tensor": inputs[0], "is_output": False} log_output = b.log1p(Pipeline._current_pipeline._handle ,*(kwargs_pybind.values())) return log_output + + +def median_filter(*inputs, kernel_size=3, border_type=0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies median filter to images. + + @param inputs the input image passed to the augmentation + @param kernel_size (int, default = 3) median filter kernel size (pixels), typically odd: 3,5,7 + @param border_type (int, default = 0) border handling policy (implementation specific) + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Image after median filtering + """ + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "kernel_size": kernel_size, + "border_type": border_type, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.medianFilter(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + + +def gaussian_filter(*inputs, stddev=None, kernel_size=3, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies gaussian filter to images with per-sample stddev parameter. + + @param inputs the input image passed to the augmentation + @param stddev (float or FloatParam, optional, default = None) per-sample standard deviation parameter; if float, wrapped into a FloatParam + @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Image after gaussian filtering + """ + stddev = b.createFloatParameter(stddev) if isinstance(stddev, float) else stddev + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "stddev": stddev, + "kernel_size": kernel_size, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.gaussianFilter(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + + +def gaussian_filter_fixed(*inputs, stddev=1.0, kernel_size=3, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies gaussian filter to images with fixed stddev. + + @param inputs the input image passed to the augmentation + @param stddev (float, default = 1.0) fixed standard deviation value + @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Image after gaussian filtering with fixed stddev + """ + kwargs_pybind = { + "input_image": inputs[0], + "stddev": stddev, + "kernel_size": kernel_size, + "is_output": False, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.gaussianFilterFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index a8e64a538..a581e714e 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1107,6 +1107,12 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("blur", &rocalBlur, py::return_value_policy::reference); + m.def("medianFilter", &rocalMedianFilter, + py::return_value_policy::reference); + m.def("gaussianFilter", &rocalGaussianFilter, + py::return_value_policy::reference); + m.def("gaussianFilterFixed", &rocalGaussianFilterFixed, + py::return_value_policy::reference); m.def("contrast", &rocalContrast, py::return_value_policy::reference); m.def("flip", &rocalFlip, diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 3f4f9b86a..072aa7648 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -325,6 +325,24 @@ def main(): window_size=5, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "median_filter": + output = fn.median_filter(images, + kernel_size=3, + border_type=0, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "gaussian_filter": + output = fn.gaussian_filter(images, + stddev=1.0, + kernel_size=3, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "gaussian_filter_fixed": + output = fn.gaussian_filter_fixed(images, + stddev=1.0, + kernel_size=3, + output_layout=tensor_layout, + output_dtype=tensor_dtype) elif augmentation_name == "warp_affine": output = fn.warp_affine(images, dest_height=416, dest_width=416, matrix=[1.0, 1.0, 0.5, 0.5, 7.0, 7.0], output_layout=tensor_layout, output_dtype=tensor_dtype, interpolation_type=types.LINEAR_INTERPOLATION) From 78b64738f550487e4c59140eb60b4f24b6f33217 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Mon, 17 Nov 2025 04:14:17 -0600 Subject: [PATCH 05/77] Fix kernel size data type for Gaussian and Median Filters Change copyright Add unit tests for NonLinearBlend, Gaussian and Median filters --- rocAL/include/api/rocal_api_augmentation.h | 6 +-- .../color_augmentations/node_color_cast.h | 2 +- .../node_non_linear_blend.h | 2 +- .../effects_augmentations/node_grid_mask.h | 2 +- .../node_gaussian_filter.h | 4 +- .../filter_augmentations/node_median_filter.h | 4 +- rocAL/source/api/rocal_api_augmentation.cpp | 6 +-- .../color_augmentations/node_color_cast.cpp | 2 +- .../node_non_linear_blend.cpp | 2 +- .../effects_augmentations/node_grid_mask.cpp | 2 +- .../node_gaussian_filter.cpp | 6 +-- .../node_median_filter.cpp | 6 +-- tests/cpp_api/unit_tests/unit_tests.cpp | 39 +++++++++++++------ 13 files changed, 47 insertions(+), 36 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 214dad37b..c10dfc80a 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1478,7 +1478,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalLog1p(RocalContext p_context, */ extern "C" RocalTensor ROCAL_API_CALL rocalMedianFilter(RocalContext context, RocalTensor input, bool is_output, - int kernel_size = 3, + unsigned kernel_size = 3, int border_type = 0, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); @@ -1497,7 +1497,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalMedianFilter(RocalContext context, Ro extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilter(RocalContext context, RocalTensor input, bool is_output, RocalFloatParam stddev = NULL, - int kernel_size = 3, + unsigned kernel_size = 3, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); @@ -1514,7 +1514,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilter(RocalContext context, */ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext context, RocalTensor input, float stddev, - int kernel_size, + unsigned kernel_size, bool is_output, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); diff --git a/rocAL/include/augmentations/color_augmentations/node_color_cast.h b/rocAL/include/augmentations/color_augmentations/node_color_cast.h index e6d3fb0cf..cd4963892 100644 --- a/rocAL/include/augmentations/color_augmentations/node_color_cast.h +++ b/rocAL/include/augmentations/color_augmentations/node_color_cast.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h b/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h index 35772b338..a5c397897 100644 --- a/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h +++ b/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/include/augmentations/effects_augmentations/node_grid_mask.h b/rocAL/include/augmentations/effects_augmentations/node_grid_mask.h index 3b6a82d2c..3c15075b2 100644 --- a/rocAL/include/augmentations/effects_augmentations/node_grid_mask.h +++ b/rocAL/include/augmentations/effects_augmentations/node_grid_mask.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h b/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h index 4053cbe59..ffb16c48d 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h +++ b/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights @@ -37,7 +37,7 @@ class GaussianFilterNode : public Node { private: // Per-sample stddev (size batch_size) ParameterVX _stddev; - int _kernel_size = 3; + unsigned _kernel_size = 3; // Reasonable range for stddev > 0 constexpr static float STDDEV_RANGE[2] = {0.01f, 64.0f}; diff --git a/rocAL/include/augmentations/filter_augmentations/node_median_filter.h b/rocAL/include/augmentations/filter_augmentations/node_median_filter.h index d254393ca..2d3524989 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_median_filter.h +++ b/rocAL/include/augmentations/filter_augmentations/node_median_filter.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights @@ -32,6 +32,6 @@ class MedianFilterNode : public Node { void update_node() override; private: - int _kernel_size = 3; + unsigned _kernel_size = 3; int _border_type = 0; }; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 2cd18ba90..45e6a1c51 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -765,7 +765,7 @@ rocalMedianFilter( RocalContext p_context, RocalTensor p_input, bool is_output, - int kernel_size, + unsigned kernel_size, int border_type, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { @@ -797,7 +797,7 @@ rocalGaussianFilter( RocalTensor p_input, bool is_output, RocalFloatParam p_stddev, - int kernel_size, + unsigned kernel_size, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { Tensor* output = nullptr; @@ -828,7 +828,7 @@ rocalGaussianFilterFixed( RocalContext p_context, RocalTensor p_input, float stddev, - int kernel_size, + unsigned kernel_size, bool is_output, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { diff --git a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp index 423332f04..437b09b7f 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp index 76fb160d9..a8f04039e 100644 --- a/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp index 9e2dfa0b4..82ce41a3f 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp index 481f1017d..026daac4a 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights @@ -49,9 +49,7 @@ void GaussianFilterNode::create_node() { vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); - - vx_uint32 ksize_u32 = static_cast(_kernel_size); - vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &ksize_u32); + vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &_kernel_size); _node = vxExtRppGaussianFilter(_graph->get(), _inputs[0]->handle(), diff --git a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp index a743cb0b8..119f67609 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights @@ -40,9 +40,7 @@ void MedianFilterNode::create_node() { vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); - - vx_uint32 ksize_u32 = static_cast(_kernel_size); - vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &ksize_u32); + vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &_kernel_size); vx_int32 border_i32 = static_cast(_border_type); vx_scalar border_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &border_i32); diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 467392828..d10e68a8d 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -768,18 +768,6 @@ int test(int test_case, int reader_type, const char *path, const char *outName, RocalTensor output_1 = rocalRotateFixed(handle, input, 45, false); output = rocalBlendFixed(handle, input, output_1, 0.5, true); } break; - case 67: { - std::cout << "Running rocalNonLinearBlend" << std::endl; - RocalTensor output_1 = rocalRotate(handle, input, false); - RocalFloatParam stddev_param = rocalCreateFloatParameter(0.2f); - output = rocalNonLinearBlend(handle, input, output_1, true, stddev_param, output_tensor_layout, output_tensor_dtype); - } break; - case 68: { - std::cout << "Running rocalNonLinearBlendFixed" << std::endl; - RocalTensor output_1 = rocalRotateFixed(handle, input, 45, false); - float stddev = 0.2f; - output = rocalNonLinearBlendFixed(handle, input, output_1, stddev, true, output_tensor_layout, output_tensor_dtype); - } break; case 37: { std::cout << "Running rocalWarpAffineFixed" << std::endl; output = rocalWarpAffineFixed(handle, input, 1, 1, 0.5, 0.5, 7, 7, true); @@ -915,6 +903,33 @@ int test(int test_case, int reader_type, const char *path, const char *outName, unsigned translate_y = 0; output = rocalGridMask(handle, input, true, tile_width, grid_ratio, grid_angle, translate_x, translate_y, output_tensor_layout, output_tensor_dtype); } break; + case 67: { + std::cout << "Running rocalNonLinearBlend" << std::endl; + RocalTensor output_1 = rocalRotate(handle, input, false); + RocalFloatParam stddev_param = rocalCreateFloatParameter(0.2f); + output = rocalNonLinearBlend(handle, input, output_1, true, stddev_param, output_tensor_layout, output_tensor_dtype); + } break; + case 68: { + std::cout << "Running rocalNonLinearBlendFixed" << std::endl; + RocalTensor output_1 = rocalRotateFixed(handle, input, 45, false); + float stddev = 0.2f; + output = rocalNonLinearBlendFixed(handle, input, output_1, stddev, true, output_tensor_layout, output_tensor_dtype); + } break; + case 76: { + std::cout << "Running rocalMedianFilter" << std::endl; + int kernel = 3; + int border_type = 0; + output = rocalMedianFilter(handle, input, true, kernel, border_type, output_tensor_layout, output_tensor_dtype); + } break; + case 77: { + std::cout << "Running rocalGaussianFilter" << std::endl; + // Use existing float_param defined earlier as per-sample stddev + output = rocalGaussianFilter(handle, input, true, float_param, 3, output_tensor_layout, output_tensor_dtype); + } break; + case 78: { + std::cout << "Running rocalGaussianFilterFixed" << std::endl; + output = rocalGaussianFilterFixed(handle, input, 0.5, 3, true, output_tensor_layout, output_tensor_dtype); + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; From 4d6c220fcafde625ec302c9ef675d47307297779 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Thu, 23 Oct 2025 07:37:07 -0500 Subject: [PATCH 06/77] Add support for Warp perspective augmentation --- rocAL/include/api/rocal_api_augmentation.h | 21 +++ .../augmentations/augmentations_nodes.h | 1 + .../node_warp_perspective.h | 47 ++++++ rocAL/source/api/rocal_api_augmentation.cpp | 39 +++++ .../node_warp_perspective.cpp | 143 ++++++++++++++++++ rocAL_pybind/amd/rocal/fn.py | 34 +++++ rocAL_pybind/rocal_pybind.cpp | 2 + tests/python_api/unit_test.py | 10 ++ 8 files changed, 297 insertions(+) create mode 100644 rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h create mode 100644 rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index c10dfc80a..a9121e0d6 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -510,6 +510,27 @@ extern "C" RocalTensor ROCAL_API_CALL rocalWarpAffineFixed(RocalContext context, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies perspective transformation to images. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] dest_height output height (0 to use input max height) + * \param [in] dest_width output width (0 to use input max width) + * \param [in] perspective vector specifying 3x3 perspective transform coefficients. + * Either a single matrix of length 9 replicated across the batch or a per-sample array of length batch*9. + * \param [in] interpolation_type The type of interpolation to be used for warp perspective. + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalWarpPerspective(RocalContext context, RocalTensor input, bool is_output, + unsigned dest_height = 0, unsigned dest_width = 0, + std::vector &perspective, + RocalResizeInterpolationType interpolation_type = ROCAL_LINEAR_INTERPOLATION, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Applies fish eye effect on images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 84a4c978e..b68fd98dd 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -23,6 +23,7 @@ THE SOFTWARE. #pragma once #include "augmentations/geometry_augmentations/node_warp_affine.h" +#include "augmentations/geometry_augmentations/node_warp_perspective.h" #include "augmentations/color_augmentations/node_exposure.h" #include "augmentations/color_augmentations/node_vignette.h" #include "augmentations/effects_augmentations/node_jitter.h" diff --git a/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h b/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h new file mode 100644 index 000000000..bbff0a2df --- /dev/null +++ b/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h @@ -0,0 +1,47 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#include "pipeline/graph.h" +#include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" + +// WarpPerspective tensor node: applies 3x3 perspective transform per-sample. +// The perspective matrix is provided as 9 floats either per-batch (size 9) replicated, +// or per-sample (size 9 * batch_size). +class WarpPerspectiveNode : public Node { +public: + WarpPerspectiveNode(const std::vector& inputs, const std::vector& outputs); + WarpPerspectiveNode() = delete; + + // Initialize with a perspective matrix (size == 9 or size == 9 * batch_size) + void init(const std::vector& perspective_matrix, ResizeInterpolationType interpolation_type); + +protected: + void create_node() override; + void update_node() override; + +private: + std::vector _perspective; // length 9 or 9 * batch_size + vx_array _perspective_array = nullptr; + int _interpolation_type = 0; + + void build_perspective_array(); // replicates per-batch if needed and creates vx_array +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 45e6a1c51..fffa43c9c 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -1063,6 +1063,45 @@ rocalWarpAffineFixed( return output; } +RocalTensor ROCAL_API_CALL +rocalWarpPerspective( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + unsigned dest_height, + unsigned dest_width, + std::vector& perspective, + RocalResizeInterpolationType interpolation_type, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + if (dest_width == 0 || dest_height == 0) { + dest_width = input->info().max_shape()[0]; + dest_height = input->info().max_shape()[1]; + } + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_data_type(op_tensor_dtype); + + // For the warp perspective node, user can create an image with a different width and height + output_info.modify_dims_width_and_height(op_tensor_layout, dest_width, dest_height); + output = context->master_graph->create_tensor(output_info, is_output); + + context->master_graph + ->add_node({input}, {output}) + ->init(perspective, static_cast(interpolation_type)); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalFishEye( RocalContext p_context, diff --git a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp new file mode 100644 index 000000000..89ee0ea3c --- /dev/null +++ b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp @@ -0,0 +1,143 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "augmentations/geometry_augmentations/node_warp_perspective.h" + +#include + +#include "pipeline/exception.h" + +WarpPerspectiveNode::WarpPerspectiveNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) { +} + +void WarpPerspectiveNode::init(const std::vector& perspective_matrix, ResizeInterpolationType interpolation_type) { + _perspective = perspective_matrix; + _interpolation_type = static_cast(interpolation_type); +} + +void WarpPerspectiveNode::build_perspective_array() { + // Build per-sample perspective array of length 9 * batch_size. + // If a single 9-element matrix is provided, replicate across the batch. + uint batch_size = _batch_size; + const size_t expected_len = static_cast(batch_size) * 9; + + std::vector data; + data.resize(expected_len); + + if (_perspective.size() == 9) { + // Replicate across batch + for (uint i = 0; i < batch_size; ++i) { + const size_t base = static_cast(i) * 9; + for (int k = 0; k < 9; ++k) { + data[base + k] = _perspective[k]; + } + } + } else if (_perspective.size() == expected_len) { + // Already per-sample + data = _perspective; + } else { + THROW("WarpPerspective: perspective matrix length must be 9 or 9 * batch_size, got: " + TOSTR(_perspective.size())); + } + + // Create vx_array and populate it + vx_status status; + _perspective_array = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, expected_len); + status = vxAddArrayItems(_perspective_array, expected_len, data.data(), sizeof(vx_float32)); + if (status != VX_SUCCESS) { + THROW("WarpPerspective: vxAddArrayItems failed while creating perspective array: " + TOSTR(status)); + } +} + +void WarpPerspectiveNode::create_node() { + if (_node) + return; + + // Build and allocate perspective array + build_perspective_array(); + + // Interpolation scalar + vx_scalar interpolation_vx = + vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &_interpolation_type); + + // Layout and ROI type scalars + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_scalar input_layout_vx = + vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = + vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = + vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + + // Construct the RPP WarpPerspective node + _node = vxExtRppWarpPerspective(_graph->get(), + _inputs[0]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + _perspective_array, + interpolation_vx, + input_layout_vx, + output_layout_vx, + roi_type_vx); + + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { + THROW("Adding the warp perspective (vxExtRppWarpPerspective) node failed: " + TOSTR(status)); + } +} + +void WarpPerspectiveNode::update_node() { + // Update perspective array if parameters are dynamic + uint batch_size = _batch_size; + const size_t expected_len = static_cast(batch_size) * 9; + + std::vector data; + data.resize(expected_len); + + if (_perspective.size() == 9) { + for (uint i = 0; i < batch_size; ++i) { + const size_t base = static_cast(i) * 9; + for (int k = 0; k < 9; ++k) { + data[base + k] = _perspective[k]; + } + } + } else if (_perspective.size() == expected_len) { + data = _perspective; + } else { + THROW("WarpPerspective update: perspective matrix length must be 9 or 9 * batch_size, got: " + TOSTR(_perspective.size())); + } + + vx_status perspective_status; + perspective_status = vxCopyArrayRange((vx_array)_perspective_array, + 0, + expected_len, + sizeof(vx_float32), + data.data(), + VX_WRITE_ONLY, + VX_MEMORY_TYPE_HOST); + if (perspective_status != VX_SUCCESS) { + THROW("vxCopyArrayRange failed in the WarpPerspective (vxExtRppWarpPerspective) node: " + TOSTR(perspective_status)); + } +} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 289f21507..ba283b598 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -795,6 +795,40 @@ def warp_affine(*inputs, dest_width=0, dest_height=0, matrix=[0, 0, 0, 0, 0, 0], Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (warp_affine_output) +def warp_perspective(*inputs, dest_width=0, dest_height=0, perspective=[1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0], + interpolation_type=types.LINEAR_INTERPOLATION, device=None, + output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies perspective transformation to images. + + @param inputs the input image passed to the augmentation + @param dest_width (int, optional, default = 0) The length of the X dimension of the transformed image (0 uses input max width) + @param dest_height (int, optional, default = 0) The length of the Y dimension of the transformed image (0 uses input max height) + @param perspective (list of 9 floats, default = identity) 3x3 perspective transform matrix flattened row-major. + Either a single 9-element list replicated across the batch or per-sample data of length batch*9. + @param interpolation_type (int, optional, default = types.LINEAR_INTERPOLATION) Type of interpolation to be used. + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Perspective warped images + """ + # Order of arguments must match C API binding signature in rocal_pybind: + # (context, input, is_output, dest_height, dest_width, perspective, interpolation_type, output_layout, output_datatype) + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "dest_height": dest_height, + "dest_width": dest_width, + "perspective": perspective, + "interpolation_type": interpolation_type, + "output_layout": output_layout, + "output_dtype": output_dtype + } + warp_persp_output = b.warpPerspective(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (warp_persp_output) + def vignette(*inputs, vignette=0.5, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies Vignette effect diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index a581e714e..25fd3f800 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1127,6 +1127,8 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("warpAffineFixed", &rocalWarpAffineFixed, py::return_value_policy::reference); + m.def("warpPerspective", &rocalWarpPerspective, + py::return_value_policy::reference); m.def("fog", &rocalFog, py::return_value_policy::reference); m.def("fishEye", &rocalFishEye, diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 072aa7648..4a25dc560 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -346,6 +346,16 @@ def main(): elif augmentation_name == "warp_affine": output = fn.warp_affine(images, dest_height=416, dest_width=416, matrix=[1.0, 1.0, 0.5, 0.5, 7.0, 7.0], output_layout=tensor_layout, output_dtype=tensor_dtype, interpolation_type=types.LINEAR_INTERPOLATION) + elif augmentation_name == "warp_perspective": + output = fn.warp_perspective(images, + dest_height=416, + dest_width=416, + perspective=[1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.001, 0.001, 1.0], + output_layout=tensor_layout, + output_dtype=tensor_dtype, + interpolation_type=types.LINEAR_INTERPOLATION) elif augmentation_name == "fish_eye": output = fn.fish_eye(images, output_layout=tensor_layout, From 6e778eb7bfe6084377ced1ba81eaac0c23400324 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 24 Oct 2025 04:40:16 -0500 Subject: [PATCH 07/77] Add support for Threshold augmentation and API --- rocAL/include/api/rocal_api_augmentation.h | 37 ++++++++- .../augmentations/augmentations_nodes.h | 1 + .../filter_augmentations/node_threshold.h | 48 ++++++++++++ rocAL/source/api/rocal_api_augmentation.cpp | 64 +++++++++++++++ .../filter_augmentations/node_threshold.cpp | 78 +++++++++++++++++++ rocAL_pybind/amd/rocal/fn.py | 48 ++++++++++++ rocAL_pybind/rocal_pybind.cpp | 4 + tests/cpp_api/unit_tests/unit_tests.cpp | 10 +++ tests/python_api/unit_test.py | 6 ++ 9 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 rocAL/include/augmentations/filter_augmentations/node_threshold.h create mode 100644 rocAL/source/augmentations/filter_augmentations/node_threshold.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index a9121e0d6..fe5876a95 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -525,7 +525,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalWarpAffineFixed(RocalContext context, * \return RocalTensor */ extern "C" RocalTensor ROCAL_API_CALL rocalWarpPerspective(RocalContext context, RocalTensor input, bool is_output, - unsigned dest_height = 0, unsigned dest_width = 0, + unsigned dest_height, unsigned dest_width, std::vector &perspective, RocalResizeInterpolationType interpolation_type = ROCAL_LINEAR_INTERPOLATION, RocalTensorLayout output_layout = ROCAL_NONE, @@ -1540,4 +1540,39 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext cont RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies thresholding to images. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] min per-sample minimum threshold value + * \param [in] max per-sample maximum threshold value + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalThreshold(RocalContext context, RocalTensor input, + bool is_output, + RocalFloatParam min = NULL, + RocalFloatParam max = NULL, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies thresholding to images with fixed min/max parameters. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] min fixed minimum threshold value + * \param [in] max fixed maximum threshold value + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalThresholdFixed(RocalContext context, RocalTensor input, + float min, float max, + bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + #endif // MIVISIONX_ROCAL_API_AUGMENTATION_H diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index b68fd98dd..c648d8212 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -75,3 +75,4 @@ THE SOFTWARE. #include "augmentations/arithmetic_augmentations/node_log1p.h" #include "augmentations/filter_augmentations/node_median_filter.h" #include "augmentations/filter_augmentations/node_gaussian_filter.h" +#include "augmentations/filter_augmentations/node_threshold.h" diff --git a/rocAL/include/augmentations/filter_augmentations/node_threshold.h b/rocAL/include/augmentations/filter_augmentations/node_threshold.h new file mode 100644 index 000000000..a28eadb22 --- /dev/null +++ b/rocAL/include/augmentations/filter_augmentations/node_threshold.h @@ -0,0 +1,48 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#include + +#include "pipeline/graph.h" +#include "pipeline/node.h" +#include "parameters/parameter_vx.h" + +class ThresholdNode : public Node { + public: + ThresholdNode(const std::vector &inputs, const std::vector &outputs); + ThresholdNode() = delete; + + // Overloads for dynamic vs fixed parameters + void init(float min_val, float max_val); + void init(FloatParam *min_param, FloatParam *max_param); + + protected: + void create_node() override; + void update_node() override; + + private: + ParameterVX _min, _max; + // Default ranges for thresholds on U8 inputs; for floating types values are passed as-is + constexpr static float THRESHOLD_MIN_RANGE[2] = {0.0f, 255.0f}; + constexpr static float THRESHOLD_MAX_RANGE[2] = {0.0f, 255.0f}; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index fffa43c9c..da9c9df71 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -822,6 +822,70 @@ rocalGaussianFilter( return output; } +// New: Threshold (dynamic min/max) +RocalTensor ROCAL_API_CALL +rocalThreshold( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_min, + RocalFloatParam p_max, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto min_param = static_cast(p_min); + auto max_param = static_cast(p_max); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(min_param, max_param); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +// New: Threshold (fixed min/max) +RocalTensor ROCAL_API_CALL +rocalThresholdFixed( + RocalContext p_context, + RocalTensor p_input, + float min, + float max, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(min, max); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + // New: Gaussian Filter (fixed stddev) RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed( diff --git a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp new file mode 100644 index 000000000..aad4d779c --- /dev/null +++ b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp @@ -0,0 +1,78 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/filter_augmentations/node_threshold.h" +#include "pipeline/exception.h" + +ThresholdNode::ThresholdNode(const std::vector &inputs, const std::vector &outputs) + : Node(inputs, outputs), + _min(THRESHOLD_MIN_RANGE[0], THRESHOLD_MIN_RANGE[1]), + _max(THRESHOLD_MAX_RANGE[0], THRESHOLD_MAX_RANGE[1]) {} + +void ThresholdNode::create_node() { + if (_node) + return; + + // Create per-sample arrays for min and max threshold values + _min.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _max.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + + // Tensor layout and ROI type + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + + // Create Threshold node via MIVisionX RPP extension + _node = vxExtRppThreshold(_graph->get(), + _inputs[0]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + _min.default_array(), + _max.default_array(), + input_layout_vx, + output_layout_vx, + roi_type_vx); + + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the threshold (vxExtRppThreshold) node failed: " + TOSTR(status)) +} + +void ThresholdNode::init(float min_val, float max_val) { + _min.set_param(min_val); + _max.set_param(max_val); +} + +void ThresholdNode::init(FloatParam *min_param, FloatParam *max_param) { + _min.set_param(core(min_param)); + _max.set_param(core(max_param)); +} + +void ThresholdNode::update_node() { + _min.update_array(); + _max.update_array(); +} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index ba283b598..ebfa51828 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1468,3 +1468,51 @@ def gaussian_filter_fixed(*inputs, stddev=1.0, kernel_size=3, device=None, outpu } output_image = b.gaussianFilterFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (output_image) + +def threshold(*inputs, min=None, max=None, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies thresholding to images with per-sample min/max parameters. + + @param inputs the input image passed to the augmentation + @param min (float or FloatParam, optional, default = None) per-sample minimum threshold; if float, wrapped into a FloatParam + @param max (float or FloatParam, optional, default = None) per-sample maximum threshold; if float, wrapped into a FloatParam + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Thresholded image + """ + min = b.createFloatParameter(min) if isinstance(min, float) else min + max = b.createFloatParameter(max) if isinstance(max, float) else max + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "min": min, + "max": max, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.threshold(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + +def threshold_fixed(*inputs, min=0.0, max=255.0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies thresholding to images with fixed min/max values. + + @param inputs the input image passed to the augmentation + @param min (float, default = 0.0) fixed minimum threshold value + @param max (float, default = 255.0) fixed maximum threshold value + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Thresholded image + """ + kwargs_pybind = { + "input_image": inputs[0], + "min": min, + "max": max, + "is_output": False, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.thresholdFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index 25fd3f800..c76bbfcb9 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1113,6 +1113,10 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("gaussianFilterFixed", &rocalGaussianFilterFixed, py::return_value_policy::reference); + m.def("threshold", &rocalThreshold, + py::return_value_policy::reference); + m.def("thresholdFixed", &rocalThresholdFixed, + py::return_value_policy::reference); m.def("contrast", &rocalContrast, py::return_value_policy::reference); m.def("flip", &rocalFlip, diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index d10e68a8d..be208bc08 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -915,6 +915,16 @@ int test(int test_case, int reader_type, const char *path, const char *outName, float stddev = 0.2f; output = rocalNonLinearBlendFixed(handle, input, output_1, stddev, true, output_tensor_layout, output_tensor_dtype); } break; + case 69: { + std::cout << "Running rocalThreshold" << std::endl; + RocalFloatParam min_param = rocalCreateFloatParameter(64.0f); + RocalFloatParam max_param = rocalCreateFloatParameter(192.0f); + output = rocalThreshold(handle, input, true, min_param, max_param, output_tensor_layout, output_tensor_dtype); + } break; + case 70: { + std::cout << "Running rocalThresholdFixed" << std::endl; + output = rocalThresholdFixed(handle, input, 64.0f, 192.0f, true, output_tensor_layout, output_tensor_dtype); + } case 76: { std::cout << "Running rocalMedianFilter" << std::endl; int kernel = 3; diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 4a25dc560..88c4ff60f 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -343,6 +343,12 @@ def main(): kernel_size=3, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "threshold": + output = fn.threshold(images, + min=64.0, + max=192.0, + output_layout=tensor_layout, + output_dtype=tensor_dtype) elif augmentation_name == "warp_affine": output = fn.warp_affine(images, dest_height=416, dest_width=416, matrix=[1.0, 1.0, 0.5, 0.5, 7.0, 7.0], output_layout=tensor_layout, output_dtype=tensor_dtype, interpolation_type=types.LINEAR_INTERPOLATION) From 11f92ef7db761d93875b0467cdf695c2781f80c4 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Mon, 27 Oct 2025 02:38:11 -0500 Subject: [PATCH 08/77] Add rocAL support for new augmentations Dilate Erode Magnitude Phase --- rocAL/include/api/rocal_api_augmentation.h | 62 +++++++++ .../augmentations/augmentations_nodes.h | 4 + .../filter_augmentations/node_dilate.h | 37 ++++++ .../filter_augmentations/node_erode.h | 36 ++++++ .../filter_augmentations/node_magnitude.h | 30 +++++ .../filter_augmentations/node_phase.h | 30 +++++ rocAL/source/api/rocal_api_augmentation.cpp | 118 ++++++++++++++++++ .../filter_augmentations/node_dilate.cpp | 62 +++++++++ .../filter_augmentations/node_erode.cpp | 63 ++++++++++ .../filter_augmentations/node_magnitude.cpp | 59 +++++++++ .../filter_augmentations/node_phase.cpp | 58 +++++++++ tests/cpp_api/unit_tests/unit_tests.cpp | 20 +++ tests/python_api/unit_test.py | 60 +++++++++ 13 files changed, 639 insertions(+) create mode 100644 rocAL/include/augmentations/filter_augmentations/node_dilate.h create mode 100644 rocAL/include/augmentations/filter_augmentations/node_erode.h create mode 100644 rocAL/include/augmentations/filter_augmentations/node_magnitude.h create mode 100644 rocAL/include/augmentations/filter_augmentations/node_phase.h create mode 100644 rocAL/source/augmentations/filter_augmentations/node_dilate.cpp create mode 100644 rocAL/source/augmentations/filter_augmentations/node_erode.cpp create mode 100644 rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp create mode 100644 rocAL/source/augmentations/filter_augmentations/node_phase.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index fe5876a95..8a418d6cd 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1575,4 +1575,66 @@ extern "C" RocalTensor ROCAL_API_CALL rocalThresholdFixed(RocalContext context, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies dilate to images (morphological operation). + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] kernel_size kernel size for dilate (pixels) + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalDilate(RocalContext context, RocalTensor input, + bool is_output, + int kernel_size = 3, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies erode to images (morphological operation). + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] kernel_size kernel size for erode (pixels) + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalErode(RocalContext context, RocalTensor input, + bool is_output, + int kernel_size = 3, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Computes magnitude given two input tensors. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 First input tensor + * \param [in] input2 Second input tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalMagnitude(RocalContext context, RocalTensor input1, RocalTensor input2, + bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Computes phase given two input tensors. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 First input tensor + * \param [in] input2 Second input tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalPhase(RocalContext context, RocalTensor input1, RocalTensor input2, + bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + #endif // MIVISIONX_ROCAL_API_AUGMENTATION_H diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index c648d8212..84128f9e4 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -76,3 +76,7 @@ THE SOFTWARE. #include "augmentations/filter_augmentations/node_median_filter.h" #include "augmentations/filter_augmentations/node_gaussian_filter.h" #include "augmentations/filter_augmentations/node_threshold.h" +#include "augmentations/filter_augmentations/node_dilate.h" +#include "augmentations/filter_augmentations/node_erode.h" +#include "augmentations/filter_augmentations/node_magnitude.h" +#include "augmentations/filter_augmentations/node_phase.h" diff --git a/rocAL/include/augmentations/filter_augmentations/node_dilate.h b/rocAL/include/augmentations/filter_augmentations/node_dilate.h new file mode 100644 index 000000000..6c2711425 --- /dev/null +++ b/rocAL/include/augmentations/filter_augmentations/node_dilate.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#include "pipeline/node.h" + +class DilateNode : public Node { +public: + explicit DilateNode(const std::vector& inputs, const std::vector& outputs); + DilateNode() = delete; + + // Fixed kernel size across the batch + void init(int kernel_size); + +protected: + void update_node() override; + void create_node() override; + +private: + int _kernel_size = 3; // default kernel size +}; diff --git a/rocAL/include/augmentations/filter_augmentations/node_erode.h b/rocAL/include/augmentations/filter_augmentations/node_erode.h new file mode 100644 index 000000000..4d5f27320 --- /dev/null +++ b/rocAL/include/augmentations/filter_augmentations/node_erode.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#pragma once +#include "pipeline/node.h" + +class ErodeNode : public Node { +public: + explicit ErodeNode(const std::vector& inputs, const std::vector& outputs); + ErodeNode() = delete; + + // Fixed kernel size across the batch + void init(int kernel_size); + +protected: + void update_node() override; + void create_node() override; + +private: + int _kernel_size = 3; // default kernel size +}; diff --git a/rocAL/include/augmentations/filter_augmentations/node_magnitude.h b/rocAL/include/augmentations/filter_augmentations/node_magnitude.h new file mode 100644 index 000000000..a17429070 --- /dev/null +++ b/rocAL/include/augmentations/filter_augmentations/node_magnitude.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#pragma once +#include "pipeline/node.h" + +class MagnitudeNode : public Node { +public: + explicit MagnitudeNode(const std::vector& inputs, const std::vector& outputs); + MagnitudeNode() = delete; + +protected: + void create_node() override; + void update_node() override; +}; diff --git a/rocAL/include/augmentations/filter_augmentations/node_phase.h b/rocAL/include/augmentations/filter_augmentations/node_phase.h new file mode 100644 index 000000000..b3d5329fd --- /dev/null +++ b/rocAL/include/augmentations/filter_augmentations/node_phase.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#pragma once +#include "pipeline/node.h" + +class PhaseNode : public Node { +public: + explicit PhaseNode(const std::vector& inputs, const std::vector& outputs); + PhaseNode() = delete; + +protected: + void create_node() override; + void update_node() override; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index da9c9df71..48a9182eb 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2786,3 +2786,121 @@ RocalTensor rocalLog1p(RocalContext p_context, } return output; } + +// Dilate +extern "C" RocalTensor ROCAL_API_CALL +rocalDilate(RocalContext p_context, + RocalTensor p_input, + bool is_output, + int kernel_size, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(kernel_size); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +// Erode +extern "C" RocalTensor ROCAL_API_CALL +rocalErode(RocalContext p_context, + RocalTensor p_input, + bool is_output, + int kernel_size, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(kernel_size); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +// Magnitude (two inputs) +extern "C" RocalTensor ROCAL_API_CALL +rocalMagnitude(RocalContext p_context, + RocalTensor p_input1, + RocalTensor p_input2, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input1, output); + ROCAL_INVALID_INPUT_ERR(p_input2, output); + auto context = static_cast(p_context); + auto input1 = static_cast(p_input1); + auto input2 = static_cast(p_input2); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input1->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input1, input2}, {output}); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +// Phase (two inputs) +extern "C" RocalTensor ROCAL_API_CALL +rocalPhase(RocalContext p_context, + RocalTensor p_input1, + RocalTensor p_input2, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input1, output); + ROCAL_INVALID_INPUT_ERR(p_input2, output); + auto context = static_cast(p_context); + auto input1 = static_cast(p_input1); + auto input2 = static_cast(p_input2); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input1->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input1, input2}, {output}); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} diff --git a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp new file mode 100644 index 000000000..242aace68 --- /dev/null +++ b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp @@ -0,0 +1,62 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/filter_augmentations/node_dilate.h" +#include "pipeline/exception.h" + +DilateNode::DilateNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) {} + +void DilateNode::init(int kernel_size) { + _kernel_size = kernel_size; +} + +void DilateNode::create_node() { + if (_node) + return; + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); + + vx_uint32 ksize_u32 = static_cast(_kernel_size); + vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &ksize_u32); + + _node = vxExtRppDilate(_graph->get(), + _inputs[0]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + kernel_size_vx, + input_layout_vx, + output_layout_vx, + roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the dilate (vxExtRppDilate) node failed: " + TOSTR(status)) +} + +void DilateNode::update_node() { + // No dynamic per-sample parameters to update +} diff --git a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp new file mode 100644 index 000000000..e282a4b69 --- /dev/null +++ b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp @@ -0,0 +1,63 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. +All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/filter_augmentations/node_erode.h" +#include "pipeline/exception.h" + +ErodeNode::ErodeNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) {} + +void ErodeNode::init(int kernel_size) { + _kernel_size = kernel_size; +} + +void ErodeNode::create_node() { + if (_node) + return; + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); + + vx_uint32 ksize_u32 = static_cast(_kernel_size); + vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &ksize_u32); + + _node = vxExtRppErode(_graph->get(), + _inputs[0]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + kernel_size_vx, + input_layout_vx, + output_layout_vx, + roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the erode (vxExtRppErode) node failed: " + TOSTR(status)) +} + +void ErodeNode::update_node() { + // No dynamic per-sample parameters to update +} diff --git a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp new file mode 100644 index 000000000..7156f6319 --- /dev/null +++ b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp @@ -0,0 +1,59 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. +All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/filter_augmentations/node_magnitude.h" +#include "pipeline/exception.h" + +MagnitudeNode::MagnitudeNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) {} + +void MagnitudeNode::create_node() { + if (_node) + return; + + if (_inputs.size() < 2) + THROW("Magnitude node needs two input tensors") + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); + + _node = vxExtRppMagnitude(_graph->get(), + _inputs[0]->handle(), + _inputs[1]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + input_layout_vx, + output_layout_vx, + roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the magnitude (vxExtRppMagnitude) node failed: " + TOSTR(status)) +} + +void MagnitudeNode::update_node() { + // No dynamic per-sample parameters to update +} diff --git a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp new file mode 100644 index 000000000..53e138eca --- /dev/null +++ b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp @@ -0,0 +1,58 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/filter_augmentations/node_phase.h" +#include "pipeline/exception.h" + +PhaseNode::PhaseNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) {} + +void PhaseNode::create_node() { + if (_node) + return; + + if (_inputs.size() < 2) + THROW("Phase node needs two input tensors") + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); + + _node = vxExtRppPhase(_graph->get(), + _inputs[0]->handle(), + _inputs[1]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + input_layout_vx, + output_layout_vx, + roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the phase (vxExtRppPhase) node failed: " + TOSTR(status)) +} + +void PhaseNode::update_node() { + // No dynamic per-sample parameters to update +} diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index be208bc08..0f266ce77 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -574,6 +574,26 @@ int test(int test_case, int reader_type, const char *path, const char *outName, rocalCreateTFReader(handle, path, true, key2, key8); decoded_output = rocalRawTFRecordSourceSingleShard(handle, path, key1, key8, color_format, 0, 1, false, true, false, decode_max_width, decode_max_height); } break; + case 72: { + std::cout << "Running rocalDilate" << std::endl; + output = rocalDilate(handle, input, true, 3, output_tensor_layout, output_tensor_dtype); + } break; + case 73: { + std::cout << "Running rocalErode" << std::endl; + output = rocalErode(handle, input, true, 3, output_tensor_layout, output_tensor_dtype); + } break; + case 74: { + std::cout << "Running rocalMagnitude" << std::endl; + // Create a second tensor by rotating the input; use as second input to magnitude + RocalTensor input2 = rocalRotate(handle, input, false); + output = rocalMagnitude(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); + } break; + case 75: { + std::cout << "Running rocalPhase" << std::endl; + // Create a second tensor by rotating the input; use as second input to phase + RocalTensor input2 = rocalRotate(handle, input, false); + output = rocalPhase(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); + } break; default: { std::cout << "Running IMAGE READER" << std::endl; pipeline_type = 1; diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 88c4ff60f..fa1e0a174 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -331,6 +331,66 @@ def main(): border_type=0, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "dilate": + # Morphological dilate; fallback to copy if bindings not available + try: + output = fn.dilate(images, + kernel_size=3, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + except Exception as e: + print("fn.dilate not available -- falling back to copy:", e) + output = fn.copy(images, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "erode": + # Morphological erode; fallback to copy if bindings not available + try: + output = fn.erode(images, + kernel_size=3, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + except Exception as e: + print("fn.erode not available -- falling back to copy:", e) + output = fn.copy(images, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "magnitude": + # Create a second tensor by rotating; then compute magnitude; fallback if not available + try: + images2 = fn.rotate(images, + angle=15.0, + dest_width=max_width if max_width else 416, + dest_height=max_height if max_height else 416, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + output = fn.magnitude(images, + images2, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + except Exception as e: + print("fn.magnitude not available -- falling back to copy:", e) + output = fn.copy(images, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "phase": + # Create a second tensor by rotating; then compute phase; fallback if not available + try: + images2 = fn.rotate(images, + angle=-15.0, + dest_width=max_width if max_width else 416, + dest_height=max_height if max_height else 416, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + output = fn.phase(images, + images2, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + except Exception as e: + print("fn.phase not available -- falling back to copy:", e) + output = fn.copy(images, + output_layout=tensor_layout, + output_dtype=tensor_dtype) elif augmentation_name == "gaussian_filter": output = fn.gaussian_filter(images, stddev=1.0, From 0e1ac07e66a8d55b2264ae036d45943d510efc0d Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Mon, 27 Oct 2025 04:55:32 -0500 Subject: [PATCH 09/77] Fix unit tests --- tests/cpp_api/unit_tests/unit_tests.cpp | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 0f266ce77..63bd29a05 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -574,26 +574,6 @@ int test(int test_case, int reader_type, const char *path, const char *outName, rocalCreateTFReader(handle, path, true, key2, key8); decoded_output = rocalRawTFRecordSourceSingleShard(handle, path, key1, key8, color_format, 0, 1, false, true, false, decode_max_width, decode_max_height); } break; - case 72: { - std::cout << "Running rocalDilate" << std::endl; - output = rocalDilate(handle, input, true, 3, output_tensor_layout, output_tensor_dtype); - } break; - case 73: { - std::cout << "Running rocalErode" << std::endl; - output = rocalErode(handle, input, true, 3, output_tensor_layout, output_tensor_dtype); - } break; - case 74: { - std::cout << "Running rocalMagnitude" << std::endl; - // Create a second tensor by rotating the input; use as second input to magnitude - RocalTensor input2 = rocalRotate(handle, input, false); - output = rocalMagnitude(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); - } break; - case 75: { - std::cout << "Running rocalPhase" << std::endl; - // Create a second tensor by rotating the input; use as second input to phase - RocalTensor input2 = rocalRotate(handle, input, false); - output = rocalPhase(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); - } break; default: { std::cout << "Running IMAGE READER" << std::endl; pipeline_type = 1; @@ -960,6 +940,26 @@ int test(int test_case, int reader_type, const char *path, const char *outName, std::cout << "Running rocalGaussianFilterFixed" << std::endl; output = rocalGaussianFilterFixed(handle, input, 0.5, 3, true, output_tensor_layout, output_tensor_dtype); } break; + case 72: { + std::cout << "Running rocalDilate" << std::endl; + output = rocalDilate(handle, input, true, 3, output_tensor_layout, output_tensor_dtype); + } break; + case 73: { + std::cout << "Running rocalErode" << std::endl; + output = rocalErode(handle, input, true, 3, output_tensor_layout, output_tensor_dtype); + } break; + case 74: { + std::cout << "Running rocalMagnitude" << std::endl; + // Create a second tensor by rotating the input; use as second input to magnitude + RocalTensor input2 = rocalRotate(handle, input, false); + output = rocalMagnitude(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); + } break; + case 75: { + std::cout << "Running rocalPhase" << std::endl; + // Create a second tensor by rotating the input; use as second input to phase + RocalTensor input2 = rocalRotate(handle, input, false); + output = rocalPhase(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; From 64b2f53343edb52197065a996164598a4ee4cbe5 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Mon, 27 Oct 2025 05:10:32 -0500 Subject: [PATCH 10/77] Modify copyright --- rocAL/include/augmentations/filter_augmentations/node_dilate.h | 2 +- rocAL/include/augmentations/filter_augmentations/node_erode.h | 2 +- .../include/augmentations/filter_augmentations/node_magnitude.h | 2 +- rocAL/include/augmentations/filter_augmentations/node_phase.h | 2 +- .../geometry_augmentations/node_warp_perspective.h | 2 +- rocAL/source/augmentations/filter_augmentations/node_dilate.cpp | 2 +- rocAL/source/augmentations/filter_augmentations/node_erode.cpp | 2 +- .../augmentations/filter_augmentations/node_magnitude.cpp | 2 +- rocAL/source/augmentations/filter_augmentations/node_phase.cpp | 2 +- .../geometry_augmentations/node_warp_perspective.cpp | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rocAL/include/augmentations/filter_augmentations/node_dilate.h b/rocAL/include/augmentations/filter_augmentations/node_dilate.h index 6c2711425..c085d66bc 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_dilate.h +++ b/rocAL/include/augmentations/filter_augmentations/node_dilate.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/rocAL/include/augmentations/filter_augmentations/node_erode.h b/rocAL/include/augmentations/filter_augmentations/node_erode.h index 4d5f27320..66ed700cb 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_erode.h +++ b/rocAL/include/augmentations/filter_augmentations/node_erode.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/rocAL/include/augmentations/filter_augmentations/node_magnitude.h b/rocAL/include/augmentations/filter_augmentations/node_magnitude.h index a17429070..e376d5906 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_magnitude.h +++ b/rocAL/include/augmentations/filter_augmentations/node_magnitude.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/rocAL/include/augmentations/filter_augmentations/node_phase.h b/rocAL/include/augmentations/filter_augmentations/node_phase.h index b3d5329fd..48b23d563 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_phase.h +++ b/rocAL/include/augmentations/filter_augmentations/node_phase.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h b/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h index bbff0a2df..3247d7075 100644 --- a/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h +++ b/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp index 242aace68..b22c7a6e6 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp index e282a4b69..7a1fb6091 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp index 7156f6319..ab19672a1 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp index 53e138eca..56dcaf7b9 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp index 89ee0ea3c..7945aa271 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From c54d408e1d0eff00a65e253bb793d2a7acd687a7 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 28 Oct 2025 09:09:03 -0500 Subject: [PATCH 11/77] Warp Perspective fixes Remove per-iter updation of perspective array Add unit test for WarpPerspective --- .../node_warp_perspective.h | 2 +- .../node_warp_perspective.cpp | 53 ++++--------------- tests/cpp_api/unit_tests/unit_tests.cpp | 8 +++ 3 files changed, 19 insertions(+), 44 deletions(-) diff --git a/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h b/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h index 3247d7075..a740f3be0 100644 --- a/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h +++ b/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h @@ -40,7 +40,7 @@ class WarpPerspectiveNode : public Node { private: std::vector _perspective; // length 9 or 9 * batch_size - vx_array _perspective_array = nullptr; + vx_array _perspective_array_vx = nullptr; int _interpolation_type = 0; void build_perspective_array(); // replicates per-batch if needed and creates vx_array diff --git a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp index 7945aa271..4ca52bfc2 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp @@ -30,23 +30,17 @@ WarpPerspectiveNode::WarpPerspectiveNode(const std::vector& inputs, con : Node(inputs, outputs) { } -void WarpPerspectiveNode::init(const std::vector& perspective_matrix, ResizeInterpolationType interpolation_type) { - _perspective = perspective_matrix; - _interpolation_type = static_cast(interpolation_type); -} - void WarpPerspectiveNode::build_perspective_array() { // Build per-sample perspective array of length 9 * batch_size. // If a single 9-element matrix is provided, replicate across the batch. - uint batch_size = _batch_size; - const size_t expected_len = static_cast(batch_size) * 9; + const size_t expected_len = static_cast(_batch_size) * 9; std::vector data; data.resize(expected_len); if (_perspective.size() == 9) { // Replicate across batch - for (uint i = 0; i < batch_size; ++i) { + for (uint i = 0; i < _batch_size; ++i) { const size_t base = static_cast(i) * 9; for (int k = 0; k < 9; ++k) { data[base + k] = _perspective[k]; @@ -61,8 +55,8 @@ void WarpPerspectiveNode::build_perspective_array() { // Create vx_array and populate it vx_status status; - _perspective_array = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, expected_len); - status = vxAddArrayItems(_perspective_array, expected_len, data.data(), sizeof(vx_float32)); + _perspective_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, expected_len); + status = vxAddArrayItems(_perspective_array_vx, expected_len, data.data(), sizeof(vx_float32)); if (status != VX_SUCCESS) { THROW("WarpPerspective: vxAddArrayItems failed while creating perspective array: " + TOSTR(status)); } @@ -96,7 +90,7 @@ void WarpPerspectiveNode::create_node() { _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), - _perspective_array, + _perspective_array_vx, interpolation_vx, input_layout_vx, output_layout_vx, @@ -108,36 +102,9 @@ void WarpPerspectiveNode::create_node() { } } -void WarpPerspectiveNode::update_node() { - // Update perspective array if parameters are dynamic - uint batch_size = _batch_size; - const size_t expected_len = static_cast(batch_size) * 9; - - std::vector data; - data.resize(expected_len); - - if (_perspective.size() == 9) { - for (uint i = 0; i < batch_size; ++i) { - const size_t base = static_cast(i) * 9; - for (int k = 0; k < 9; ++k) { - data[base + k] = _perspective[k]; - } - } - } else if (_perspective.size() == expected_len) { - data = _perspective; - } else { - THROW("WarpPerspective update: perspective matrix length must be 9 or 9 * batch_size, got: " + TOSTR(_perspective.size())); - } - - vx_status perspective_status; - perspective_status = vxCopyArrayRange((vx_array)_perspective_array, - 0, - expected_len, - sizeof(vx_float32), - data.data(), - VX_WRITE_ONLY, - VX_MEMORY_TYPE_HOST); - if (perspective_status != VX_SUCCESS) { - THROW("vxCopyArrayRange failed in the WarpPerspective (vxExtRppWarpPerspective) node: " + TOSTR(perspective_status)); - } +void WarpPerspectiveNode::init(const std::vector& perspective_matrix, ResizeInterpolationType interpolation_type) { + _perspective = perspective_matrix; + _interpolation_type = static_cast(interpolation_type); } + +void WarpPerspectiveNode::update_node() {} diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 63bd29a05..b58948746 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -960,6 +960,14 @@ int test(int test_case, int reader_type, const char *path, const char *outName, RocalTensor input2 = rocalRotate(handle, input, false); output = rocalPhase(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); } break; + case 79: { + std::cout << "Running rocalWarpPerspective" << std::endl; + std::vector perspective_1d_matrix = {0.93f, 0.5f, 0.0f, + -0.5f, 0.93f, 0.0f, + 0.005f, 0.005f, 1.0f}; + output = rocalWarpPerspective(handle, input, true, height, width, perspective_1d_matrix, ROCAL_LINEAR_INTERPOLATION); + + }break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; From 2377b2baa1106a65998e116a47570441a6c3720e Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 29 Oct 2025 02:12:47 -0500 Subject: [PATCH 12/77] Fix Threshold augmentation Remove ThresholdFixed Modify params to accept vector --- rocAL/include/api/rocal_api_augmentation.h | 10 +-- .../filter_augmentations/node_threshold.h | 10 +-- rocAL/source/api/rocal_api_augmentation.cpp | 41 +---------- .../filter_augmentations/node_threshold.cpp | 70 +++++++++++++------ tests/cpp_api/unit_tests/unit_tests.cpp | 6 +- 5 files changed, 64 insertions(+), 73 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 8a418d6cd..7beabae50 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1544,17 +1544,19 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext cont * \ingroup group_rocal_augmentations * \param [in] context Rocal context * \param [in] input Input Rocal tensor + * \param [in] min vector specifying the minimum threshold value for each channel. + * Either a single array of length number of channels is replicated across the batch or a per-sample array of length batch*no of channels. + * \param [in] max vector specifying the maximum threshold value for each channel. + * Either a single array of length number of channels is replicated across the batch or a per-sample array of length batch*no of channels. * \param [in] is_output Is the output tensor part of the graph output - * \param [in] min per-sample minimum threshold value - * \param [in] max per-sample maximum threshold value * \param [in] output_layout the layout of the output tensor * \param [in] output_datatype the data type of the output tensor * \return RocalTensor */ extern "C" RocalTensor ROCAL_API_CALL rocalThreshold(RocalContext context, RocalTensor input, + std::vector &min, + std::vector &max, bool is_output, - RocalFloatParam min = NULL, - RocalFloatParam max = NULL, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); diff --git a/rocAL/include/augmentations/filter_augmentations/node_threshold.h b/rocAL/include/augmentations/filter_augmentations/node_threshold.h index a28eadb22..d443c49e6 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_threshold.h +++ b/rocAL/include/augmentations/filter_augmentations/node_threshold.h @@ -31,18 +31,12 @@ class ThresholdNode : public Node { public: ThresholdNode(const std::vector &inputs, const std::vector &outputs); ThresholdNode() = delete; - - // Overloads for dynamic vs fixed parameters - void init(float min_val, float max_val); - void init(FloatParam *min_param, FloatParam *max_param); + void init(std::vector& min_val, std::vector& max_val); protected: void create_node() override; void update_node() override; private: - ParameterVX _min, _max; - // Default ranges for thresholds on U8 inputs; for floating types values are passed as-is - constexpr static float THRESHOLD_MIN_RANGE[2] = {0.0f, 255.0f}; - constexpr static float THRESHOLD_MAX_RANGE[2] = {0.0f, 255.0f}; + std::vector _min, _max; }; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 48a9182eb..ea07e3ede 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -827,9 +827,9 @@ RocalTensor ROCAL_API_CALL rocalThreshold( RocalContext p_context, RocalTensor p_input, + std::vector &min, + std::vector &max, bool is_output, - RocalFloatParam p_min, - RocalFloatParam p_max, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { Tensor* output = nullptr; @@ -837,8 +837,6 @@ rocalThreshold( ROCAL_INVALID_INPUT_ERR(p_input, output); auto context = static_cast(p_context); auto input = static_cast(p_input); - auto min_param = static_cast(p_min); - auto max_param = static_cast(p_max); try { RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); @@ -846,40 +844,7 @@ rocalThreshold( output_info.set_tensor_layout(op_tensor_layout); output_info.set_data_type(op_tensor_dtype); output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(min_param, max_param); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -// New: Threshold (fixed min/max) -RocalTensor ROCAL_API_CALL -rocalThresholdFixed( - RocalContext p_context, - RocalTensor p_input, - float min, - float max, - bool is_output, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(min, max); + context->master_graph->add_node({input}, {output})->init(min, max); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } diff --git a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp index aad4d779c..50d6cf080 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp @@ -25,17 +25,56 @@ THE SOFTWARE. #include "pipeline/exception.h" ThresholdNode::ThresholdNode(const std::vector &inputs, const std::vector &outputs) - : Node(inputs, outputs), - _min(THRESHOLD_MIN_RANGE[0], THRESHOLD_MIN_RANGE[1]), - _max(THRESHOLD_MAX_RANGE[0], THRESHOLD_MAX_RANGE[1]) {} + : Node(inputs, outputs) {} + +void fill_vector_with_threshold_values(std::vector& threshold_batch, + std::vector& threshold_values, + size_t no_of_channels) { + + size_t threshold_vec_size = threshold_batch.size(); + + if (threshold_values.size() == no_of_channels) { + for (int i = 0; i < threshold_vec_size; i+=no_of_channels) { + for (int c = 0; c < no_of_channels; c++) { + threshold_batch[i + c] = threshold_values[c]; + } + } + } else if (threshold_values.size() == threshold_vec_size) { + threshold_batch = threshold_values; + } else if (threshold_values.size() > 0) { + THROW("Threshold: Threshold vector length must be no_of_channels or no_of_channels * batch_size, got: " + TOSTR(threshold_values.size())); + } +} void ThresholdNode::create_node() { if (_node) return; + std::vector min_vec, max_vec; + + // Create per-sample arrays for min and max threshold values - _min.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); - _max.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + auto no_of_channels = _inputs[0]->info().get_channels(); + auto array_size = _batch_size * no_of_channels; + std::vector min_array, max_array; + min_array.resize(array_size, 0.0f); + max_array.resize(array_size, 0.0f); + fill_vector_with_threshold_values(min_array, _min, no_of_channels); + fill_vector_with_threshold_values(max_array, _max, no_of_channels); + + // Create vx_array and populate it + vx_status status; + vx_array min_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, array_size); + status = vxAddArrayItems(min_array_vx, array_size, min_array.data(), sizeof(vx_float32)); + if (status != VX_SUCCESS) { + THROW("Threshold: vxAddArrayItems failed while creating min array: " + TOSTR(status)); + } + + vx_array max_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, array_size); + status = vxAddArrayItems(max_array_vx, array_size, max_array.data(), sizeof(vx_float32)); + if (status != VX_SUCCESS) { + THROW("Threshold: vxAddArrayItems failed while creating max array: " + TOSTR(status)); + } // Tensor layout and ROI type int input_layout = static_cast(_inputs[0]->info().layout()); @@ -51,28 +90,19 @@ void ThresholdNode::create_node() { _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), - _min.default_array(), - _max.default_array(), + min_array_vx, + max_array_vx, input_layout_vx, output_layout_vx, roi_type_vx); - vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the threshold (vxExtRppThreshold) node failed: " + TOSTR(status)) } -void ThresholdNode::init(float min_val, float max_val) { - _min.set_param(min_val); - _max.set_param(max_val); +void ThresholdNode::init(std::vector& min_val, std::vector& max_val) { + _min = min_val; + _max = max_val; } -void ThresholdNode::init(FloatParam *min_param, FloatParam *max_param) { - _min.set_param(core(min_param)); - _max.set_param(core(max_param)); -} - -void ThresholdNode::update_node() { - _min.update_array(); - _max.update_array(); -} +void ThresholdNode::update_node() {} \ No newline at end of file diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index b58948746..19274b21c 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -917,9 +917,9 @@ int test(int test_case, int reader_type, const char *path, const char *outName, } break; case 69: { std::cout << "Running rocalThreshold" << std::endl; - RocalFloatParam min_param = rocalCreateFloatParameter(64.0f); - RocalFloatParam max_param = rocalCreateFloatParameter(192.0f); - output = rocalThreshold(handle, input, true, min_param, max_param, output_tensor_layout, output_tensor_dtype); + std::vector min_threshold = {30.0f, 30.0f, 30.0f}; + std::vector max_threshold = {100.0f, 100.0f, 100.0f}; + output = rocalThreshold(handle, input, min_threshold, max_threshold, true, output_tensor_layout, output_tensor_dtype); } break; case 70: { std::cout << "Running rocalThresholdFixed" << std::endl; From 53b7d371688b80b71184692c9c2dd7f13097f07e Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 29 Oct 2025 06:01:13 -0500 Subject: [PATCH 13/77] Change kernel size to unsigned for Dilate and Erode --- rocAL/include/api/rocal_api_augmentation.h | 4 ++-- .../augmentations/filter_augmentations/node_dilate.h | 4 ++-- .../augmentations/filter_augmentations/node_erode.h | 4 ++-- rocAL/source/api/rocal_api_augmentation.cpp | 12 ++++-------- .../filter_augmentations/node_dilate.cpp | 6 ++---- .../filter_augmentations/node_erode.cpp | 6 ++---- 6 files changed, 14 insertions(+), 22 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 7beabae50..eedf4d60d 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1589,7 +1589,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalThresholdFixed(RocalContext context, */ extern "C" RocalTensor ROCAL_API_CALL rocalDilate(RocalContext context, RocalTensor input, bool is_output, - int kernel_size = 3, + unsigned kernel_size = 3, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); @@ -1605,7 +1605,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalDilate(RocalContext context, RocalTen */ extern "C" RocalTensor ROCAL_API_CALL rocalErode(RocalContext context, RocalTensor input, bool is_output, - int kernel_size = 3, + unsigned kernel_size = 3, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); diff --git a/rocAL/include/augmentations/filter_augmentations/node_dilate.h b/rocAL/include/augmentations/filter_augmentations/node_dilate.h index c085d66bc..ffee22181 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_dilate.h +++ b/rocAL/include/augmentations/filter_augmentations/node_dilate.h @@ -26,12 +26,12 @@ class DilateNode : public Node { DilateNode() = delete; // Fixed kernel size across the batch - void init(int kernel_size); + void init(unsigned kernel_size); protected: void update_node() override; void create_node() override; private: - int _kernel_size = 3; // default kernel size + unsigned _kernel_size = 3; // default kernel size }; diff --git a/rocAL/include/augmentations/filter_augmentations/node_erode.h b/rocAL/include/augmentations/filter_augmentations/node_erode.h index 66ed700cb..954e532fa 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_erode.h +++ b/rocAL/include/augmentations/filter_augmentations/node_erode.h @@ -25,12 +25,12 @@ class ErodeNode : public Node { ErodeNode() = delete; // Fixed kernel size across the batch - void init(int kernel_size); + void init(unsigned kernel_size); protected: void update_node() override; void create_node() override; private: - int _kernel_size = 3; // default kernel size + unsigned _kernel_size = 3; // default kernel size }; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index ea07e3ede..d7b7b9332 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2757,7 +2757,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalDilate(RocalContext p_context, RocalTensor p_input, bool is_output, - int kernel_size, + unsigned kernel_size, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { Tensor* output = nullptr; @@ -2772,9 +2772,7 @@ rocalDilate(RocalContext p_context, output_info.set_tensor_layout(op_tensor_layout); output_info.set_data_type(op_tensor_dtype); output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(kernel_size); + context->master_graph->add_node({input}, {output})->init(kernel_size); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2786,7 +2784,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalErode(RocalContext p_context, RocalTensor p_input, bool is_output, - int kernel_size, + unsigned kernel_size, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { Tensor* output = nullptr; @@ -2801,9 +2799,7 @@ rocalErode(RocalContext p_context, output_info.set_tensor_layout(op_tensor_layout); output_info.set_data_type(op_tensor_dtype); output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(kernel_size); + context->master_graph->add_node({input}, {output})->init(kernel_size); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } diff --git a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp index b22c7a6e6..b7c720ba0 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp @@ -24,7 +24,7 @@ THE SOFTWARE. DilateNode::DilateNode(const std::vector& inputs, const std::vector& outputs) : Node(inputs, outputs) {} -void DilateNode::init(int kernel_size) { +void DilateNode::init(unsigned kernel_size) { _kernel_size = kernel_size; } @@ -40,9 +40,7 @@ void DilateNode::create_node() { vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); - - vx_uint32 ksize_u32 = static_cast(_kernel_size); - vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &ksize_u32); + vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &_kernel_size); _node = vxExtRppDilate(_graph->get(), _inputs[0]->handle(), diff --git a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp index 7a1fb6091..85dcc7b0b 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp @@ -25,7 +25,7 @@ THE SOFTWARE. ErodeNode::ErodeNode(const std::vector& inputs, const std::vector& outputs) : Node(inputs, outputs) {} -void ErodeNode::init(int kernel_size) { +void ErodeNode::init(unsigned kernel_size) { _kernel_size = kernel_size; } @@ -41,9 +41,7 @@ void ErodeNode::create_node() { vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); - - vx_uint32 ksize_u32 = static_cast(_kernel_size); - vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &ksize_u32); + vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &_kernel_size); _node = vxExtRppErode(_graph->get(), _inputs[0]->handle(), From 925eabfd6a313b25969264ddb30d2151196f17a7 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Sun, 26 Oct 2025 09:48:56 -0500 Subject: [PATCH 14/77] Add support for erase augmentation in rocAL --- rocAL/include/api/rocal_api_augmentation.h | 20 +++++ .../augmentations/augmentations_nodes.h | 1 + .../filter_augmentations/node_erase.h | 58 +++++++++++++ rocAL/source/api/rocal_api_augmentation.cpp | 37 +++++++++ .../filter_augmentations/node_erase.cpp | 82 +++++++++++++++++++ rocAL_pybind/amd/rocal/fn.py | 29 +++++++ rocAL_pybind/rocal_pybind.cpp | 4 + tests/cpp_api/unit_tests/unit_tests.cpp | 33 ++++++++ tests/python_api/unit_test.py | 16 ++++ 9 files changed, 280 insertions(+) create mode 100644 rocAL/include/augmentations/filter_augmentations/node_erase.h create mode 100644 rocAL/source/augmentations/filter_augmentations/node_erase.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index eedf4d60d..a3f21173f 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1639,4 +1639,24 @@ extern "C" RocalTensor ROCAL_API_CALL rocalPhase(RocalContext context, RocalTens RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Erases regions in images based on per-sample anchor boxes and colors. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] anchor_box_info Tensor describing per-sample per-box anchors in LTRB format + * \param [in] colors Tensor describing per-sample per-box RGB colors + * \param [in] num_boxes Per-sample number of boxes (parameter) + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalErase(RocalContext context, RocalTensor input, + bool is_output, + RocalTensor anchor_box_info, + RocalTensor colors, + RocalIntParam num_boxes = NULL, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + #endif // MIVISIONX_ROCAL_API_AUGMENTATION_H diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 84128f9e4..2c23d46bb 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -80,3 +80,4 @@ THE SOFTWARE. #include "augmentations/filter_augmentations/node_erode.h" #include "augmentations/filter_augmentations/node_magnitude.h" #include "augmentations/filter_augmentations/node_phase.h" +#include "augmentations/filter_augmentations/node_erase.h" diff --git a/rocAL/include/augmentations/filter_augmentations/node_erase.h b/rocAL/include/augmentations/filter_augmentations/node_erase.h new file mode 100644 index 000000000..19b1649a0 --- /dev/null +++ b/rocAL/include/augmentations/filter_augmentations/node_erase.h @@ -0,0 +1,58 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#include + +#include "pipeline/graph.h" +#include "pipeline/node.h" +#include "parameters/parameter_vx.h" + +// Erase augmentation node: wraps MIVisionX vxExtRppErase +// Inputs: +// - _inputs[0]: source tensor +// - anchor_box_info: aux tensor holding per-sample per-box LTRB anchors +// - colors: aux tensor holding per-sample per-box RGB colors +// - _num_boxes: per-sample number of boxes (vx_array) +// Output: +// - _outputs[0]: destination tensor +class EraseNode : public Node { + public: + EraseNode(const std::vector &inputs, const std::vector &outputs); + EraseNode() = delete; + + // Overloads for dynamic vs fixed parameters + void init(Tensor *anchor_box_info, Tensor *colors, int num_boxes_fixed); + void init(Tensor *anchor_box_info, Tensor *colors, IntParam *num_boxes_param); + + protected: + void create_node() override; + void update_node() override; + + private: + ParameterVX _num_boxes; + Tensor *_anchor = nullptr; + Tensor *_colors = nullptr; + + // Conservative default range for number of boxes per sample + constexpr static int NUM_BOXES_RANGE[2] = {0, 1024}; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index d7b7b9332..f8d9e3166 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -851,6 +851,43 @@ rocalThreshold( return output; } + // New: Erase augmentation +RocalTensor ROCAL_API_CALL +rocalErase( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalTensor p_anchor_box_info, + RocalTensor p_colors, + RocalIntParam p_num_boxes, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto anchor = static_cast(p_anchor_box_info); + auto colors = static_cast(p_colors); + auto num_boxes_param = static_cast(p_num_boxes); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + auto erase_node = context->master_graph->add_node({input}, {output}); + if (num_boxes_param) + erase_node->init(anchor, colors, num_boxes_param); + else + erase_node->init(anchor, colors, 0); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + // New: Gaussian Filter (fixed stddev) RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed( diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp new file mode 100644 index 000000000..a117fa7f6 --- /dev/null +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -0,0 +1,82 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/filter_augmentations/node_erase.h" +#include "pipeline/exception.h" + +EraseNode::EraseNode(const std::vector &inputs, const std::vector &outputs) + : Node(inputs, outputs), + _num_boxes(NUM_BOXES_RANGE[0], NUM_BOXES_RANGE[1]) {} + +void EraseNode::create_node() { + if (_node) + return; + + if (!_anchor || !_colors) + THROW("Erase node requires non-null anchor and colors tensors") + + // Create per-sample array for number of boxes + _num_boxes.create_array(_graph, VX_TYPE_INT32, _batch_size); + + // Tensor layout and ROI type + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_context vx_ctx = vxGetContext((vx_reference)_graph->get()); + vx_scalar input_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &roi_type); + + // Create Erase node via MIVisionX RPP extension + _node = vxExtRppErase(_graph->get(), + _inputs[0]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + _anchor->handle(), + _colors->handle(), + _num_boxes.default_array(), + input_layout_vx, + output_layout_vx, + roi_type_vx); + + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the erase (vxExtRppErase) node failed: " + TOSTR(status)) +} + +void EraseNode::init(Tensor *anchor_box_info, Tensor *colors, int num_boxes_fixed) { + _anchor = anchor_box_info; + _colors = colors; + _num_boxes.set_param(num_boxes_fixed); +} + +void EraseNode::init(Tensor *anchor_box_info, Tensor *colors, IntParam *num_boxes_param) { + _anchor = anchor_box_info; + _colors = colors; + _num_boxes.set_param(core(num_boxes_param)); +} + +void EraseNode::update_node() { + _num_boxes.update_array(); +} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index ebfa51828..f5a417c2f 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1516,3 +1516,32 @@ def threshold_fixed(*inputs, min=0.0, max=255.0, device=None, output_layout=type } output_image = b.thresholdFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (output_image) + +def erase(*inputs, anchor_box_info=None, colors=None, num_boxes=None, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Erases regions in images based on per-sample anchor boxes and colors. + + @param inputs the input image passed to the augmentation + @param anchor_box_info (rocalTensor, required) tensor holding per-sample per-box LTRB anchors (shape: [N, max_boxes, 4]) + @param colors (rocalTensor, required) tensor holding per-sample per-box RGB colors (shape: [N, max_boxes, 3]) + @param num_boxes (int or IntParam, optional, default = None) per-sample number of boxes; if int, wrapped into IntParam + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Image with specified regions erased + """ + if anchor_box_info is None or colors is None: + raise RuntimeError("erase requires anchor_box_info and colors tensors") + + num_boxes = b.createIntParameter(num_boxes) if isinstance(num_boxes, int) else num_boxes + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "anchor_box_info": anchor_box_info, + "colors": colors, + "num_boxes": num_boxes, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.erase(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index c76bbfcb9..f05b3928d 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1117,6 +1117,8 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("thresholdFixed", &rocalThresholdFixed, py::return_value_policy::reference); + m.def("erase", &rocalErase, + py::return_value_policy::reference); m.def("contrast", &rocalContrast, py::return_value_policy::reference); m.def("flip", &rocalFlip, @@ -1147,6 +1149,8 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("gridMask", &rocalGridMask, py::return_value_policy::reference); + m.def("erase", &rocalErase, + py::return_value_policy::reference); m.def("blend", &rocalBlend, py::return_value_policy::reference); m.def("nonLinearBlend", &rocalNonLinearBlend, diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 19274b21c..329c06fee 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -968,6 +968,39 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output = rocalWarpPerspective(handle, input, true, height, width, perspective_1d_matrix, ROCAL_LINEAR_INTERPOLATION); }break; + case 71: { + std::cout << "Running rocalErase" << std::endl; + // Erase requires auxiliary tensors: anchor_box_info [N, max_boxes, 4] and colors [N, max_boxes, 3]. + // Attempt to load them from ROCAL_DATA_PATH; if unavailable, fall back to copy to keep pipeline functional. + RocalTensor anchor = nullptr; + RocalTensor colors = nullptr; + bool erase_ready = false; + + if (strcmp(rocal_data_path.c_str(), "") != 0) { + try { + std::string anchors_path = rocal_data_path + "/rocal_data/erase/anchors.npy"; + std::string colors_path = rocal_data_path + "/rocal_data/erase/colors.npy"; + // Load auxiliary tensors via Numpy reader (expects files to exist in test dataset) + anchor = rocalNumpyFileSource(handle, anchors_path.c_str(), num_threads, RocalTensorLayout::ROCAL_NONE); + colors = rocalNumpyFileSource(handle, colors_path.c_str(), num_threads, RocalTensorLayout::ROCAL_NONE); + if (anchor && colors) { + erase_ready = true; + } + } catch (...) { + std::cout << "Erase aux tensors not found/readable at ROCAL_DATA_PATH -- falling back to copy\n"; + } + } else { + std::cout << "ROCAL_DATA_PATH not set -- falling back to copy for erase test\n"; + } + + if (erase_ready) { + // Use existing uniform_int_param created earlier for per-sample number of boxes + output = rocalErase(handle, input, true, anchor, colors, uniform_int_param, output_tensor_layout, output_tensor_dtype); + } else { + // Fallback path to keep pipeline valid when aux tensors are unavailable + output = rocalCopy(handle, input, true); + } + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index fa1e0a174..eede59cf4 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -474,6 +474,22 @@ def main(): translate_y=0, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "erase": + # Erase requires auxiliary tensors: anchor_box_info [N, max_boxes, 4] and colors [N, max_boxes, 3]. + # If the test environment provides them, import and run erase; otherwise, fall back to copy to keep pipeline functional. + try: + from test_aux_tensors import anchor_tensor, color_tensor, num_boxes_param + output = fn.erase(images, + anchor_box_info=anchor_tensor, + colors=color_tensor, + num_boxes=num_boxes_param, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + except Exception as e: + print("Erase aux tensors not provided -- skipping erase test path:", e) + output = fn.copy(images, + output_layout=tensor_layout, + output_dtype=tensor_dtype) elif augmentation_name == "exposure": output = fn.exposure(images, exposure=1.0, From 775a462aa290fced0169f01ae10b2c9190018482 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Thu, 13 Nov 2025 04:44:00 -0600 Subject: [PATCH 15/77] Erase node with vector inputs --- .../filter_augmentations/node_erase.h | 15 ++ .../filter_augmentations/node_erase.cpp | 222 +++++++++++++++++- 2 files changed, 227 insertions(+), 10 deletions(-) diff --git a/rocAL/include/augmentations/filter_augmentations/node_erase.h b/rocAL/include/augmentations/filter_augmentations/node_erase.h index 19b1649a0..33090c1da 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_erase.h +++ b/rocAL/include/augmentations/filter_augmentations/node_erase.h @@ -22,6 +22,7 @@ THE SOFTWARE. #pragma once #include +#include #include "pipeline/graph.h" #include "pipeline/node.h" @@ -43,6 +44,11 @@ class EraseNode : public Node { // Overloads for dynamic vs fixed parameters void init(Tensor *anchor_box_info, Tensor *colors, int num_boxes_fixed); void init(Tensor *anchor_box_info, Tensor *colors, IntParam *num_boxes_param); + // New: raw vector-based init (replicates across batch as needed) + void init(std::vector anchor, + std::vector shape, + std::vector num_boxes, + std::vector fill_value); protected: void create_node() override; @@ -53,6 +59,15 @@ class EraseNode : public Node { Tensor *_anchor = nullptr; Tensor *_colors = nullptr; + // Raw-vector mode + bool _use_raw_vectors = false; + std::vector _anchor_vec; + std::vector _colors_vec; + std::vector _num_boxes_vec; + vx_tensor _vx_anchor = nullptr; + vx_tensor _vx_colors = nullptr; + vx_array _vx_num_boxes = nullptr; + // Conservative default range for number of boxes per sample constexpr static int NUM_BOXES_RANGE[2] = {0, 1024}; }; diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index a117fa7f6..1b8e786ed 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -32,12 +32,6 @@ void EraseNode::create_node() { if (_node) return; - if (!_anchor || !_colors) - THROW("Erase node requires non-null anchor and colors tensors") - - // Create per-sample array for number of boxes - _num_boxes.create_array(_graph, VX_TYPE_INT32, _batch_size); - // Tensor layout and ROI type int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); @@ -48,14 +42,142 @@ void EraseNode::create_node() { vx_scalar output_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &roi_type); + vx_tensor anchor_tensor = nullptr; + vx_tensor color_tensor = nullptr; + vx_array num_boxes_arr = nullptr; + + if (_use_raw_vectors) { + // Build per-sample num_boxes array (int32) + if (_num_boxes_vec.empty()) { + THROW("Erase raw-vector mode requires non-empty num_boxes vector") + } + // Ensure length == batch; replicate if single value + if (_num_boxes_vec.size() != _batch_size) { + if (_num_boxes_vec.size() == 1) { + _num_boxes_vec.resize(_batch_size, _num_boxes_vec[0]); + } else { + THROW("num_boxes vector length must be 1 or equal to batch size") + } + } + int max_boxes = 0; + for (int nb : _num_boxes_vec) max_boxes = std::max(max_boxes, nb); + if (max_boxes <= 0) max_boxes = 1; // avoid zero-sized tensors + + // Create vx_array for num_boxes + num_boxes_arr = vxCreateArray(vx_ctx, VX_TYPE_INT32, _batch_size); + vx_status st = vxAddArrayItems(num_boxes_arr, _batch_size, _num_boxes_vec.data(), sizeof(int32_t)); + if (st != VX_SUCCESS) THROW("vxAddArrayItems failed while creating num_boxes array: " + TOSTR(st)) + + // Prepare anchor tensor [N, max_boxes, 4] FP32 + vx_size anchor_dims[3] = { (vx_size)_batch_size, (vx_size)max_boxes, (vx_size)4 }; + anchor_tensor = vxCreateTensor(vx_ctx, 3, anchor_dims, VX_TYPE_FLOAT32, 0); + if (vxGetStatus((vx_reference)anchor_tensor) != VX_SUCCESS) + THROW("vxCreateTensor failed for anchor tensor") + + // Prepare color tensor [N, max_boxes, 3] FP32 + vx_size color_dims[3] = { (vx_size)_batch_size, (vx_size)max_boxes, (vx_size)3 }; + color_tensor = vxCreateTensor(vx_ctx, 3, color_dims, VX_TYPE_FLOAT32, 0); + if (vxGetStatus((vx_reference)color_tensor) != VX_SUCCESS) + THROW("vxCreateTensor failed for color tensor") + + // Compute strides (in bytes) + vx_size anchor_strides[3] = { + (vx_size)(max_boxes * 4 * sizeof(float)), // stride for N + (vx_size)(4 * sizeof(float)), // stride for boxes + (vx_size)(sizeof(float)) // stride for channels (4) + }; + vx_size color_strides[3] = { + (vx_size)(max_boxes * 3 * sizeof(float)), // stride for N + (vx_size)(3 * sizeof(float)), // stride for boxes + (vx_size)(sizeof(float)) // stride for channels (3) + }; + + // Fill host buffers for anchors/colors + std::vector anchor_buf(_batch_size * max_boxes * 4, 0.0f); + std::vector color_buf (_batch_size * max_boxes * 3, 0.0f); + + // Determine source interpretation: per-batch concatenation or single-sample replicated + auto total_anchor_needed = 0ul; + for (int nb : _num_boxes_vec) total_anchor_needed += (unsigned long)(nb * 4); + auto total_color_needed = 0ul; + for (int nb : _num_boxes_vec) total_color_needed += (unsigned long)(nb * 3); + + bool anchor_is_batch_concat = (_anchor_vec.size() == total_anchor_needed); + bool color_is_batch_concat = (_colors_vec.size() == total_color_needed); + + // If single-sample provided, assume first sample data replicated/truncated per nb[i] + bool anchor_is_single = (_anchor_vec.size() == (size_t)(4 * std::max(1, max_boxes))); + bool color_is_single = (_colors_vec.size() == (size_t)(3 * std::max(1, max_boxes))); + + // Fill per sample + size_t a_src_off = 0, c_src_off = 0; + for (size_t i = 0; i < _batch_size; ++i) { + int nb = _num_boxes_vec[i]; + // Anchors + for (int b = 0; b < nb; ++b) { + const float* src_a = nullptr; + if (anchor_is_batch_concat) { + src_a = &_anchor_vec[a_src_off + b * 4]; + } else { + // replicate from the first nb anchors of single-sample vector + if ((size_t)((b + 1) * 4) > _anchor_vec.size()) + THROW("anchor_box_info vector smaller than required"); + src_a = &_anchor_vec[b * 4]; + } + size_t dst_idx = (i * max_boxes + b) * 4; + anchor_buf[dst_idx + 0] = src_a[0]; + anchor_buf[dst_idx + 1] = src_a[1]; + anchor_buf[dst_idx + 2] = src_a[2]; + anchor_buf[dst_idx + 3] = src_a[3]; + } + // Colors + for (int b = 0; b < nb; ++b) { + const float* src_c = nullptr; + if (color_is_batch_concat) { + src_c = &_colors_vec[c_src_off + b * 3]; + } else { + if ((size_t)((b + 1) * 3) > _colors_vec.size()) + THROW("colors vector smaller than required"); + src_c = &_colors_vec[b * 3]; + } + size_t dst_idx = (i * max_boxes + b) * 3; + color_buf[dst_idx + 0] = src_c[0]; + color_buf[dst_idx + 1] = src_c[1]; + color_buf[dst_idx + 2] = src_c[2]; + } + if (anchor_is_batch_concat) a_src_off += (size_t)(nb * 4); + if (color_is_batch_concat) c_src_off += (size_t)(nb * 3); + } + + // Copy buffers into vx_tensors + vx_size start[3] = {0, 0, 0}; + vx_size end_a[3] = { (vx_size)_batch_size, (vx_size)max_boxes, (vx_size)4 }; + vx_status st_a = vxCopyTensorPatch(anchor_tensor, 3, start, end_a, anchor_strides, + anchor_buf.data(), VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); + if (st_a != VX_SUCCESS) THROW("vxCopyTensorPatch failed for anchor tensor: " + TOSTR(st_a)) + + vx_size end_c[3] = { (vx_size)_batch_size, (vx_size)max_boxes, (vx_size)3 }; + vx_status st_c = vxCopyTensorPatch(color_tensor, 3, start, end_c, color_strides, + color_buf.data(), VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); + if (st_c != VX_SUCCESS) THROW("vxCopyTensorPatch failed for color tensor: " + TOSTR(st_c)) + } else { + if (!_anchor || !_colors) + THROW("Erase node requires non-null anchor and colors tensors") + // ParameterVX path for num_boxes + _num_boxes.create_array(_graph, VX_TYPE_INT32, _batch_size); + anchor_tensor = _anchor->handle(); + color_tensor = _colors->handle(); + num_boxes_arr = _num_boxes.default_array(); + } + // Create Erase node via MIVisionX RPP extension _node = vxExtRppErase(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), - _anchor->handle(), - _colors->handle(), - _num_boxes.default_array(), + anchor_tensor, + color_tensor, + num_boxes_arr, input_layout_vx, output_layout_vx, roi_type_vx); @@ -69,14 +191,94 @@ void EraseNode::init(Tensor *anchor_box_info, Tensor *colors, int num_boxes_fixe _anchor = anchor_box_info; _colors = colors; _num_boxes.set_param(num_boxes_fixed); + _use_raw_vectors = false; } void EraseNode::init(Tensor *anchor_box_info, Tensor *colors, IntParam *num_boxes_param) { _anchor = anchor_box_info; _colors = colors; _num_boxes.set_param(core(num_boxes_param)); + _use_raw_vectors = false; +} + +// New: raw vector-based init (replicates across batch if needed) +void EraseNode::init(std::vector anchor, + std::vector shape, + std::vector num_boxes + std::vector fill_value) { + + // Validate anchor and shape should be same size + // _anchor_vec = std::move(anchor); + // _shape_vec = std::move(shape); + + _num_boxes_vec.resize(_batch_size); + if (num_boxes.size() == 1) { + std::fill(_num_boxes_vec.begin(), _num_boxes_vec.end(), num_boxes[0]); + } else if (num_boxes.size() == _batch_size) { + _num_boxes_vec = num_boxes; + } else { + THROW("Invalid number of elements passed for num of boxes") + } + _total_boxes = std::accumulate(_num_boxes_vec.begin(), _num_boxes_vec.end(), 0); + + _fill_values_vec.resize(_total_boxes * _batch_size * _inputs[0]->info().get_channels()); + if (fill_value.size() == 1) { + std::fill(_fill_values_vec.begin(), _fill_values_vec.end(), fill_value[0]); + } else if (fill_value.size() == _inputs[0]->info().get_channels()) { + for (int i = 0; i < _batch_size; ++i) + std::copy(_fill_values_vec.begin(), _fill_values_vec.end(), fill_value.begin() + i * fill_value.size()); + } else if (fill_value.size() == _batch_size) { + const int channels = _inputs[0]->info().get_channels(); + for (int i = 0; i < _batch_size; ++i) { + float* dst = _fill_values_vec.data() + static_cast(i) * channels; + std::fill(dst, dst + channels, fill_value[i]); + } + } else if (fill_value.size() == (_total_boxes * _batch_size * _inputs[0]->info().get_channels())) { + _fill_values_vec = std::move(fill_value); + } else { + THROW("Invalid number of values passed for fill value") + } + + _anchor_box_vec.resize(_total_boxes * 4); + if (num_boxes.size() == 1 && anchor.size() == num_boxes[0] * 2) { + for (int i = 0; i < _batch_size; i++) { + for (int n = 0; n < _num_boxes_vec[i]; n++) { + _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 0] = anchor[n * 2]; + _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 1] = anchor[n * 2 + 1]; + } + } + + } else if (anchor.size() == (_total_boxes * 2)) { + for (int i = 0; i < _batch_size; i++) { + for (int n = 0; n < _num_boxes_vec[i]; n++) { + _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 0] = anchor[(i * _num_boxes_vec[i] + n) * 2]; + _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 1] = anchor[(i * _num_boxes_vec[i] + n) * 2 + 1]; + } + } + } + + if (num_boxes.size() == 1 && shape.size() == num_boxes[0] * 2) { + for (int i = 0; i < _batch_size; i++) { + for (int n = 0; n < _num_boxes_vec[i]; n++) { + _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 2] = shape[n * 2]; + _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 3] = shape[n * 2 + 1]; + } + } + + } else if (shape.size() == (_total_boxes * 2)) { + for (int i = 0; i < _batch_size; i++) { + for (int n = 0; n < _num_boxes_vec[i]; n++) { + _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 2] = shape[(i * _num_boxes_vec[i] + n) * 2]; + _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 3] = shape[(i * _num_boxes_vec[i] + n) * 2 + 1]; + } + } + } } void EraseNode::update_node() { + if (_use_raw_vectors) { + // Raw vectors are static; nothing to update per run + return; + } _num_boxes.update_array(); } From c49908b9cd06e8425b15e9730fa7e1c5e262da7e Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 14 Nov 2025 01:01:10 -0600 Subject: [PATCH 16/77] Fix erase augmentation --- rocAL/include/api/rocal_api_augmentation.h | 35 +- .../filter_augmentations/node_erase.h | 8 +- rocAL/source/api/rocal_api_augmentation.cpp | 36 +- .../filter_augmentations/node_erase.cpp | 338 ++++++++++-------- tests/cpp_api/unit_tests/unit_tests.cpp | 62 ++-- 5 files changed, 279 insertions(+), 200 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index a3f21173f..f4b0a2b6a 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1577,6 +1577,27 @@ extern "C" RocalTensor ROCAL_API_CALL rocalThresholdFixed(RocalContext context, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Erases regions in images using raw vectors (no parameters/tensors). + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] anchor_box_info Flattened LTRB anchors: either [4*num_boxes] replicated or [batch*4*num_boxes] + * \param [in] colors Flattened RGB colors per box: either [3*num_boxes] replicated or [batch*3*num_boxes] + * \param [in] num_boxes Per-sample number of boxes: either [1] to replicate or [batch] + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalErase(RocalContext context, RocalTensor input, + bool is_output, + std::vector &anchor, + std::vector &shape, + std::vector &num_boxes, + std::vector &fill_value, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Applies dilate to images (morphological operation). * \ingroup group_rocal_augmentations * \param [in] context Rocal context @@ -1651,12 +1672,12 @@ extern "C" RocalTensor ROCAL_API_CALL rocalPhase(RocalContext context, RocalTens * \param [in] output_datatype the data type of the output tensor * \return RocalTensor */ -extern "C" RocalTensor ROCAL_API_CALL rocalErase(RocalContext context, RocalTensor input, - bool is_output, - RocalTensor anchor_box_info, - RocalTensor colors, - RocalIntParam num_boxes = NULL, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); +extern "C" RocalTensor ROCAL_API_CALL rocalEraseTensor(RocalContext context, RocalTensor input, + bool is_output, + RocalTensor anchor_box_info, + RocalTensor colors, + RocalIntParam num_boxes = NULL, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); #endif // MIVISIONX_ROCAL_API_AUGMENTATION_H diff --git a/rocAL/include/augmentations/filter_augmentations/node_erase.h b/rocAL/include/augmentations/filter_augmentations/node_erase.h index 33090c1da..fcabb581a 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_erase.h +++ b/rocAL/include/augmentations/filter_augmentations/node_erase.h @@ -40,6 +40,7 @@ class EraseNode : public Node { public: EraseNode(const std::vector &inputs, const std::vector &outputs); EraseNode() = delete; + ~EraseNode(); // Overloads for dynamic vs fixed parameters void init(Tensor *anchor_box_info, Tensor *colors, int num_boxes_fixed); @@ -61,12 +62,15 @@ class EraseNode : public Node { // Raw-vector mode bool _use_raw_vectors = false; - std::vector _anchor_vec; - std::vector _colors_vec; + std::vector _anchor_vec; + std::vector _colors_vec, _fill_values_vec, _fill_values; std::vector _num_boxes_vec; vx_tensor _vx_anchor = nullptr; vx_tensor _vx_colors = nullptr; vx_array _vx_num_boxes = nullptr; + void* _anchor_ptr = nullptr; + void* _color_ptr = nullptr; + unsigned _total_boxes = 0; // Conservative default range for number of boxes per sample constexpr static int NUM_BOXES_RANGE[2] = {0, 1024}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index f8d9e3166..0c5ba8cee 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -853,7 +853,7 @@ rocalThreshold( // New: Erase augmentation RocalTensor ROCAL_API_CALL -rocalErase( +rocalEraseTensor( RocalContext p_context, RocalTensor p_input, bool is_output, @@ -888,6 +888,40 @@ rocalErase( return output; } +RocalTensor ROCAL_API_CALL +rocalErase( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + std::vector& anchor, + std::vector& shape, + std::vector& num_boxes, + std::vector& fill_value, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + if (anchor.size() != shape.size()) + THROW("Anchor and shape dimensions do not match") + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + auto erase_node = context->master_graph->add_node({input}, {output}); + // Use raw-vector overload; node will allocate and replicate per batch if needed + erase_node->init(anchor, shape, num_boxes, fill_value); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + // New: Gaussian Filter (fixed stddev) RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed( diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index 1b8e786ed..c2005a39c 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -21,8 +21,11 @@ THE SOFTWARE. */ #include +#include #include "augmentations/filter_augmentations/node_erase.h" #include "pipeline/exception.h" +#include "pipeline/tensor.h" +#include EraseNode::EraseNode(const std::vector &inputs, const std::vector &outputs) : Node(inputs, outputs), @@ -47,119 +50,57 @@ void EraseNode::create_node() { vx_array num_boxes_arr = nullptr; if (_use_raw_vectors) { - // Build per-sample num_boxes array (int32) - if (_num_boxes_vec.empty()) { - THROW("Erase raw-vector mode requires non-empty num_boxes vector") - } - // Ensure length == batch; replicate if single value - if (_num_boxes_vec.size() != _batch_size) { - if (_num_boxes_vec.size() == 1) { - _num_boxes_vec.resize(_batch_size, _num_boxes_vec[0]); - } else { - THROW("num_boxes vector length must be 1 or equal to batch size") - } - } - int max_boxes = 0; - for (int nb : _num_boxes_vec) max_boxes = std::max(max_boxes, nb); - if (max_boxes <= 0) max_boxes = 1; // avoid zero-sized tensors + // Fill up anchor and shape // Create vx_array for num_boxes num_boxes_arr = vxCreateArray(vx_ctx, VX_TYPE_INT32, _batch_size); vx_status st = vxAddArrayItems(num_boxes_arr, _batch_size, _num_boxes_vec.data(), sizeof(int32_t)); if (st != VX_SUCCESS) THROW("vxAddArrayItems failed while creating num_boxes array: " + TOSTR(st)) - // Prepare anchor tensor [N, max_boxes, 4] FP32 - vx_size anchor_dims[3] = { (vx_size)_batch_size, (vx_size)max_boxes, (vx_size)4 }; - anchor_tensor = vxCreateTensor(vx_ctx, 3, anchor_dims, VX_TYPE_FLOAT32, 0); - if (vxGetStatus((vx_reference)anchor_tensor) != VX_SUCCESS) - THROW("vxCreateTensor failed for anchor tensor") - - // Prepare color tensor [N, max_boxes, 3] FP32 - vx_size color_dims[3] = { (vx_size)_batch_size, (vx_size)max_boxes, (vx_size)3 }; - color_tensor = vxCreateTensor(vx_ctx, 3, color_dims, VX_TYPE_FLOAT32, 0); - if (vxGetStatus((vx_reference)color_tensor) != VX_SUCCESS) - THROW("vxCreateTensor failed for color tensor") - - // Compute strides (in bytes) - vx_size anchor_strides[3] = { - (vx_size)(max_boxes * 4 * sizeof(float)), // stride for N - (vx_size)(4 * sizeof(float)), // stride for boxes - (vx_size)(sizeof(float)) // stride for channels (4) - }; - vx_size color_strides[3] = { - (vx_size)(max_boxes * 3 * sizeof(float)), // stride for N - (vx_size)(3 * sizeof(float)), // stride for boxes - (vx_size)(sizeof(float)) // stride for channels (3) - }; - - // Fill host buffers for anchors/colors - std::vector anchor_buf(_batch_size * max_boxes * 4, 0.0f); - std::vector color_buf (_batch_size * max_boxes * 3, 0.0f); - - // Determine source interpretation: per-batch concatenation or single-sample replicated - auto total_anchor_needed = 0ul; - for (int nb : _num_boxes_vec) total_anchor_needed += (unsigned long)(nb * 4); - auto total_color_needed = 0ul; - for (int nb : _num_boxes_vec) total_color_needed += (unsigned long)(nb * 3); - - bool anchor_is_batch_concat = (_anchor_vec.size() == total_anchor_needed); - bool color_is_batch_concat = (_colors_vec.size() == total_color_needed); - - // If single-sample provided, assume first sample data replicated/truncated per nb[i] - bool anchor_is_single = (_anchor_vec.size() == (size_t)(4 * std::max(1, max_boxes))); - bool color_is_single = (_colors_vec.size() == (size_t)(3 * std::max(1, max_boxes))); - - // Fill per sample - size_t a_src_off = 0, c_src_off = 0; - for (size_t i = 0; i < _batch_size; ++i) { - int nb = _num_boxes_vec[i]; - // Anchors - for (int b = 0; b < nb; ++b) { - const float* src_a = nullptr; - if (anchor_is_batch_concat) { - src_a = &_anchor_vec[a_src_off + b * 4]; - } else { - // replicate from the first nb anchors of single-sample vector - if ((size_t)((b + 1) * 4) > _anchor_vec.size()) - THROW("anchor_box_info vector smaller than required"); - src_a = &_anchor_vec[b * 4]; - } - size_t dst_idx = (i * max_boxes + b) * 4; - anchor_buf[dst_idx + 0] = src_a[0]; - anchor_buf[dst_idx + 1] = src_a[1]; - anchor_buf[dst_idx + 2] = src_a[2]; - anchor_buf[dst_idx + 3] = src_a[3]; - } - // Colors - for (int b = 0; b < nb; ++b) { - const float* src_c = nullptr; - if (color_is_batch_concat) { - src_c = &_colors_vec[c_src_off + b * 3]; - } else { - if ((size_t)((b + 1) * 3) > _colors_vec.size()) - THROW("colors vector smaller than required"); - src_c = &_colors_vec[b * 3]; - } - size_t dst_idx = (i * max_boxes + b) * 3; - color_buf[dst_idx + 0] = src_c[0]; - color_buf[dst_idx + 1] = src_c[1]; - color_buf[dst_idx + 2] = src_c[2]; - } - if (anchor_is_batch_concat) a_src_off += (size_t)(nb * 4); - if (color_is_batch_concat) c_src_off += (size_t)(nb * 3); + // Select memory type and VX mem type for handle-backed tensors + auto mem_type = _inputs[0]->info().mem_type(); + vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; + + // Anchor tensor handle + vx_size anchor_dims[2] = { (vx_size)_total_boxes, (vx_size)4 }; + vx_size anchor_stride[2] = { 0, 0 }; + anchor_stride[0] = sizeof(vx_int32); + anchor_stride[1] = anchor_stride[0] * anchor_dims[0]; + + size_t bytes_a = anchor_stride[1] * anchor_dims[1]; + allocate_host_or_pinned_mem(&_anchor_ptr, bytes_a, mem_type); + std::memcpy(_anchor_ptr, _anchor_vec.data(), bytes_a); + + _vx_anchor = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + 2, anchor_dims, VX_TYPE_INT32, 0, anchor_stride, _anchor_ptr, vx_mem); + if (!_vx_anchor) THROW("vxCreateTensorFromHandle for anchor tensor failed"); + { + vx_status s = vxGetStatus((vx_reference)_vx_anchor); + if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle anchor failed: " + TOSTR(s)); } - // Copy buffers into vx_tensors - vx_size start[3] = {0, 0, 0}; - vx_size end_a[3] = { (vx_size)_batch_size, (vx_size)max_boxes, (vx_size)4 }; - vx_status st_a = vxCopyTensorPatch(anchor_tensor, 3, start, end_a, anchor_strides, - anchor_buf.data(), VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); - if (st_a != VX_SUCCESS) THROW("vxCopyTensorPatch failed for anchor tensor: " + TOSTR(st_a)) - - vx_size end_c[3] = { (vx_size)_batch_size, (vx_size)max_boxes, (vx_size)3 }; - vx_status st_c = vxCopyTensorPatch(color_tensor, 3, start, end_c, color_strides, - color_buf.data(), VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); - if (st_c != VX_SUCCESS) THROW("vxCopyTensorPatch failed for color tensor: " + TOSTR(st_c)) + // Color tensor handle + vx_size color_dims[2] = { (vx_size)_total_boxes, (vx_size)_inputs[0]->info().get_channels() }; + vx_size color_stride[2] = { 0, 0 }; + color_stride[0] = sizeof(vx_float32); + color_stride[1] = color_stride[0] * color_dims[0]; + + size_t bytes_c = color_stride[1] * color_dims[1]; + allocate_host_or_pinned_mem(&_color_ptr, bytes_c, mem_type); + std::memcpy(_color_ptr, _fill_values_vec.data(), bytes_c); + + _vx_colors = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + 2, color_dims, VX_TYPE_FLOAT32, 0, color_stride, _color_ptr, vx_mem); + if (!_vx_colors) THROW("vxCreateTensorFromHandle for color tensor failed"); + { + vx_status s = vxGetStatus((vx_reference)_vx_colors); + if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle color failed: " + TOSTR(s)); + } + + // Output tensors for node creation + anchor_tensor = _vx_anchor; + color_tensor = _vx_colors; + _vx_num_boxes = num_boxes_arr; } else { if (!_anchor || !_colors) THROW("Erase node requires non-null anchor and colors tensors") @@ -201,78 +142,131 @@ void EraseNode::init(Tensor *anchor_box_info, Tensor *colors, IntParam *num_boxe _use_raw_vectors = false; } -// New: raw vector-based init (replicates across batch if needed) + // New: raw vector-based init (replicates across batch if needed) void EraseNode::init(std::vector anchor, std::vector shape, - std::vector num_boxes + std::vector num_boxes, std::vector fill_value) { + // Use raw-vector path + _use_raw_vectors = true; - // Validate anchor and shape should be same size - // _anchor_vec = std::move(anchor); - // _shape_vec = std::move(shape); - - _num_boxes_vec.resize(_batch_size); + // Keep fill pattern for colors; create_node expands it to per-box/channel + _fill_values = std::move(fill_value); + + // Normalize num_boxes to batch size + _num_boxes_vec.clear(); if (num_boxes.size() == 1) { - std::fill(_num_boxes_vec.begin(), _num_boxes_vec.end(), num_boxes[0]); - } else if (num_boxes.size() == _batch_size) { - _num_boxes_vec = num_boxes; + _num_boxes_vec.assign(static_cast(_batch_size), static_cast(num_boxes[0])); + } else if (num_boxes.size() == static_cast(_batch_size)) { + _num_boxes_vec.assign(num_boxes.begin(), num_boxes.end()); } else { - THROW("Invalid number of elements passed for num of boxes") + THROW("num_boxes vector length must be 1 or equal to batch size"); + } + + // Compute prefix offsets and total boxes + std::vector prefix(static_cast(_batch_size) + 1, 0); + for (int i = 0; i < _batch_size; ++i) prefix[i + 1] = prefix[i] + _num_boxes_vec[i]; + _total_boxes = static_cast(prefix[_batch_size]); + + auto channels = _inputs[0]->info().get_channels(); + _fill_values_vec.resize(static_cast(_total_boxes) * channels); + + const auto fill_sz = _fill_values.size(); + + if (fill_sz == 1) { + // One scalar for everything + std::fill(_fill_values_vec.begin(), _fill_values_vec.end(), _fill_values[0]); + } + else if (fill_sz == static_cast(channels)) { + // Per-channel pattern replicated to each box + float* dst = _fill_values_vec.data(); + for (int b = 0; b < _total_boxes; ++b) { + std::copy_n(_fill_values.data(), channels, dst); + dst += channels; + } } - _total_boxes = std::accumulate(_num_boxes_vec.begin(), _num_boxes_vec.end(), 0); - - _fill_values_vec.resize(_total_boxes * _batch_size * _inputs[0]->info().get_channels()); - if (fill_value.size() == 1) { - std::fill(_fill_values_vec.begin(), _fill_values_vec.end(), fill_value[0]); - } else if (fill_value.size() == _inputs[0]->info().get_channels()) { - for (int i = 0; i < _batch_size; ++i) - std::copy(_fill_values_vec.begin(), _fill_values_vec.end(), fill_value.begin() + i * fill_value.size()); - } else if (fill_value.size() == _batch_size) { - const int channels = _inputs[0]->info().get_channels(); + else if (fill_sz == static_cast(_batch_size)) { + // Per-sample scalar replicated across its boxes (and channels) + float* dst = _fill_values_vec.data(); for (int i = 0; i < _batch_size; ++i) { - float* dst = _fill_values_vec.data() + static_cast(i) * channels; - std::fill(dst, dst + channels, fill_value[i]); + const int nb = _num_boxes_vec[i]; + const float v = _fill_values[i]; + const size_t count = static_cast(nb) * channels; + std::fill_n(dst, count, v); + dst += count; } - } else if (fill_value.size() == (_total_boxes * _batch_size * _inputs[0]->info().get_channels())) { - _fill_values_vec = std::move(fill_value); - } else { - THROW("Invalid number of values passed for fill value") } - - _anchor_box_vec.resize(_total_boxes * 4); - if (num_boxes.size() == 1 && anchor.size() == num_boxes[0] * 2) { - for (int i = 0; i < _batch_size; i++) { - for (int n = 0; n < _num_boxes_vec[i]; n++) { - _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 0] = anchor[n * 2]; - _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 1] = anchor[n * 2 + 1]; + else if (fill_sz == static_cast(_batch_size) * channels) { + // Per-sample per-channel pattern replicated across that sample’s boxes + float* dst = _fill_values_vec.data(); + const float* src = _fill_values.data(); + for (int i = 0; i < _batch_size; ++i) { + for (int b = 0; b < _num_boxes_vec[i]; ++b) { + std::copy_n(src + i * channels, channels, dst); + dst += channels; } } - - } else if (anchor.size() == (_total_boxes * 2)) { - for (int i = 0; i < _batch_size; i++) { - for (int n = 0; n < _num_boxes_vec[i]; n++) { - _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 0] = anchor[(i * _num_boxes_vec[i] + n) * 2]; - _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 1] = anchor[(i * _num_boxes_vec[i] + n) * 2 + 1]; - } + } + else if (num_boxes.size() == 1 && + fill_sz == static_cast(num_boxes[0]) * channels) { + // Single-sample per-box per-channel replicated across batch. + // All samples must have the same nb equal to num_boxes[0]. + const int nb_single = num_boxes[0]; + float* dst = _fill_values_vec.data(); + for (int i = 0; i < _batch_size; ++i) { + if (_num_boxes_vec[i] != nb_single) + THROW("num_boxes mismatch across samples for single-sample fill pattern"); + const float* src = _fill_values.data(); + std::copy_n(src, static_cast(nb_single) * channels, dst); + dst += static_cast(nb_single) * channels; } } - - if (num_boxes.size() == 1 && shape.size() == num_boxes[0] * 2) { - for (int i = 0; i < _batch_size; i++) { - for (int n = 0; n < _num_boxes_vec[i]; n++) { - _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 2] = shape[n * 2]; - _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 3] = shape[n * 2 + 1]; + else if (fill_sz == static_cast(_total_boxes) * channels) { + // Fully specified flattened values + std::copy(_fill_values.begin(), _fill_values.end(), _fill_values_vec.begin()); + } + else { + THROW("Invalid number of values passed for fill value"); + } + + // Build contiguous [x1, y1, w, h] for all boxes + _anchor_vec.assign(_total_boxes * 4, 0.0f); + + // Case 1: single-sample vectors replicated across batch + if (num_boxes.size() == 1 && + anchor.size() == static_cast(num_boxes[0]) * 2 && + shape.size() == static_cast(num_boxes[0]) * 2) { + const int nb_single = static_cast(num_boxes[0]); + for (int i = 0; i < _batch_size; ++i) { + if (_num_boxes_vec[i] != nb_single) + THROW("num_boxes mismatch across samples for single-sample anchor/shape pattern"); + for (int n = 0; n < nb_single; ++n) { + const size_t dst = (static_cast(prefix[i] + n) * 4); + _anchor_vec[dst + 0] = static_cast(anchor[static_cast(n) * 2 + 0]); // x1 + _anchor_vec[dst + 1] = static_cast(anchor[static_cast(n) * 2 + 1]); // y1 + _anchor_vec[dst + 2] = static_cast(shape [static_cast(n) * 2 + 0]); // w + _anchor_vec[dst + 3] = static_cast(shape [static_cast(n) * 2 + 1]); // h } } - - } else if (shape.size() == (_total_boxes * 2)) { - for (int i = 0; i < _batch_size; i++) { - for (int n = 0; n < _num_boxes_vec[i]; n++) { - _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 2] = shape[(i * _num_boxes_vec[i] + n) * 2]; - _anchor_box_vec[(i * _num_boxes_vec[i] + n) * 4 + 3] = shape[(i * _num_boxes_vec[i] + n) * 2 + 1]; + } + // Case 2: fully specified per-sample concatenated anchor/shape + else if (anchor.size() == _total_boxes * 2 && shape.size() == _total_boxes * 2) { + for (int i = 0; i < _batch_size; ++i) { + const int nb = _num_boxes_vec[i]; + const size_t base = static_cast(prefix[i]); + for (int n = 0; n < nb; ++n) { + const size_t dst = (base + static_cast(n)) * 4; + const size_t src = (base + static_cast(n)) * 2; + _anchor_vec[dst + 0] = static_cast(anchor[src + 0]); // x1 + _anchor_vec[dst + 1] = static_cast(anchor[src + 1]); // y1 + _anchor_vec[dst + 2] = static_cast(shape [src + 0]); // w + _anchor_vec[dst + 3] = static_cast(shape [src + 1]); // h } } } + else { + THROW("Invalid anchor/shape vector sizes"); + } } void EraseNode::update_node() { @@ -282,3 +276,31 @@ void EraseNode::update_node() { } _num_boxes.update_array(); } + +EraseNode::~EraseNode() { + if (_inputs.empty() || !_inputs[0]) return; + auto mem_type = _inputs[0]->info().mem_type(); + + if (_vx_anchor) vxReleaseTensor(&_vx_anchor); + if (_vx_colors) vxReleaseTensor(&_vx_colors); + if (_vx_num_boxes) vxReleaseArray(&_vx_num_boxes); + + if (mem_type == RocalMemType::HIP) { +#if ENABLE_HIP + if (_anchor_ptr) { + hipError_t err = hipHostFree(_anchor_ptr); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipFree failed " << std::to_string(err) << "\n"; + } + if (_color_ptr) { + hipError_t err = hipHostFree(_color_ptr); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipFree failed " << std::to_string(err) << "\n"; + } +#endif + } else { + if (_anchor_ptr) free(_anchor_ptr); + if (_color_ptr) free(_color_ptr); + } + _anchor_ptr = _color_ptr = nullptr; +} diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 329c06fee..970aebe4c 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -968,38 +968,36 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output = rocalWarpPerspective(handle, input, true, height, width, perspective_1d_matrix, ROCAL_LINEAR_INTERPOLATION); }break; - case 71: { - std::cout << "Running rocalErase" << std::endl; - // Erase requires auxiliary tensors: anchor_box_info [N, max_boxes, 4] and colors [N, max_boxes, 3]. - // Attempt to load them from ROCAL_DATA_PATH; if unavailable, fall back to copy to keep pipeline functional. - RocalTensor anchor = nullptr; - RocalTensor colors = nullptr; - bool erase_ready = false; - - if (strcmp(rocal_data_path.c_str(), "") != 0) { - try { - std::string anchors_path = rocal_data_path + "/rocal_data/erase/anchors.npy"; - std::string colors_path = rocal_data_path + "/rocal_data/erase/colors.npy"; - // Load auxiliary tensors via Numpy reader (expects files to exist in test dataset) - anchor = rocalNumpyFileSource(handle, anchors_path.c_str(), num_threads, RocalTensorLayout::ROCAL_NONE); - colors = rocalNumpyFileSource(handle, colors_path.c_str(), num_threads, RocalTensorLayout::ROCAL_NONE); - if (anchor && colors) { - erase_ready = true; - } - } catch (...) { - std::cout << "Erase aux tensors not found/readable at ROCAL_DATA_PATH -- falling back to copy\n"; - } - } else { - std::cout << "ROCAL_DATA_PATH not set -- falling back to copy for erase test\n"; - } - - if (erase_ready) { - // Use existing uniform_int_param created earlier for per-sample number of boxes - output = rocalErase(handle, input, true, anchor, colors, uniform_int_param, output_tensor_layout, output_tensor_dtype); - } else { - // Fallback path to keep pipeline valid when aux tensors are unavailable - output = rocalCopy(handle, input, true); - } + case 87: { + std::cout << "Running rocalErase (vector inputs, single fill value)" << std::endl; + // Use vector-based API: provide anchor [x1,y1], shape [w,h], num_boxes, and a single fill value + // Replicate num_boxes across batch with a single entry + std::vector num_boxes = {1}; + + // Derive two boxes using input width/height; keep within image bounds + unsigned W = static_cast(width); + unsigned H = static_cast(height); + unsigned bw = std::max(1u, W / 4); + unsigned bh = std::max(1u, H / 4); + + // Two anchors (x1, y1) and matching shapes (w, h) for a single-sample pattern + // Pattern will be replicated across the batch since num_boxes.size()==1 + std::vector anchor = {0.125f * W, 0.125f * H}; + // static_cast(W / 8), static_cast(H / 8), + // static_cast(W / 2), static_cast(H / 2) + // }; + std::vector shape = {0.372f * W, 0.375f * H}; + // static_cast(bw), static_cast(bh), + // static_cast(bw), static_cast(bh) + // }; + + // Single fill value replicated for all boxes and channels + std::vector fill_value = {0.0f}; + + // Execute vector-based erase + output = rocalErase(handle, input, true, + anchor, shape, num_boxes, fill_value, + output_tensor_layout, output_tensor_dtype); } break; default: std::cout << "Not a valid option! Exiting!\n"; From 739b0a0d54279a1d79d0ec31b37fe1b05934c644 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 14 Nov 2025 03:32:07 -0600 Subject: [PATCH 17/77] Change num boxes to vx_tensor type --- .../filter_augmentations/node_erase.h | 5 +- .../filter_augmentations/node_erase.cpp | 129 +++++++++--------- 2 files changed, 70 insertions(+), 64 deletions(-) diff --git a/rocAL/include/augmentations/filter_augmentations/node_erase.h b/rocAL/include/augmentations/filter_augmentations/node_erase.h index fcabb581a..3a27784d0 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_erase.h +++ b/rocAL/include/augmentations/filter_augmentations/node_erase.h @@ -64,12 +64,13 @@ class EraseNode : public Node { bool _use_raw_vectors = false; std::vector _anchor_vec; std::vector _colors_vec, _fill_values_vec, _fill_values; - std::vector _num_boxes_vec; + std::vector _num_boxes_vec; vx_tensor _vx_anchor = nullptr; vx_tensor _vx_colors = nullptr; - vx_array _vx_num_boxes = nullptr; + vx_tensor _vx_num_boxes = nullptr; void* _anchor_ptr = nullptr; void* _color_ptr = nullptr; + void* _num_box_ptr = nullptr; unsigned _total_boxes = 0; // Conservative default range for number of boxes per sample diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index c2005a39c..c913c4769 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -47,70 +47,69 @@ void EraseNode::create_node() { vx_tensor anchor_tensor = nullptr; vx_tensor color_tensor = nullptr; - vx_array num_boxes_arr = nullptr; - if (_use_raw_vectors) { - // Fill up anchor and shape - - // Create vx_array for num_boxes - num_boxes_arr = vxCreateArray(vx_ctx, VX_TYPE_INT32, _batch_size); - vx_status st = vxAddArrayItems(num_boxes_arr, _batch_size, _num_boxes_vec.data(), sizeof(int32_t)); - if (st != VX_SUCCESS) THROW("vxAddArrayItems failed while creating num_boxes array: " + TOSTR(st)) - - // Select memory type and VX mem type for handle-backed tensors - auto mem_type = _inputs[0]->info().mem_type(); - vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; - - // Anchor tensor handle - vx_size anchor_dims[2] = { (vx_size)_total_boxes, (vx_size)4 }; - vx_size anchor_stride[2] = { 0, 0 }; - anchor_stride[0] = sizeof(vx_int32); - anchor_stride[1] = anchor_stride[0] * anchor_dims[0]; - - size_t bytes_a = anchor_stride[1] * anchor_dims[1]; - allocate_host_or_pinned_mem(&_anchor_ptr, bytes_a, mem_type); - std::memcpy(_anchor_ptr, _anchor_vec.data(), bytes_a); - - _vx_anchor = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), - 2, anchor_dims, VX_TYPE_INT32, 0, anchor_stride, _anchor_ptr, vx_mem); - if (!_vx_anchor) THROW("vxCreateTensorFromHandle for anchor tensor failed"); - { - vx_status s = vxGetStatus((vx_reference)_vx_anchor); - if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle anchor failed: " + TOSTR(s)); - } + // Select memory type and VX mem type for handle-backed tensors + auto mem_type = _inputs[0]->info().mem_type(); + vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; + + // NumBox tensor handle + vx_size num_box_dims[1] = {_batch_size}; + vx_size num_box_stride[1] = {0}; + num_box_stride[0] = sizeof(vx_uint32); + + size_t bytes_a = num_box_stride[0] * num_box_dims[0]; + allocate_host_or_pinned_mem(&_num_box_ptr, bytes_a, mem_type); + std::memcpy(_num_box_ptr, _num_boxes_vec.data(), bytes_a); + + _vx_num_boxes = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + 1, num_box_dims, VX_TYPE_UINT32, 0, num_box_stride, _num_box_ptr, vx_mem); + if (!_vx_num_boxes) THROW("vxCreateTensorFromHandle for num_box tensor failed"); + { + vx_status s = vxGetStatus((vx_reference)_vx_num_boxes); + if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle num_box failed: " + TOSTR(s)); + } - // Color tensor handle - vx_size color_dims[2] = { (vx_size)_total_boxes, (vx_size)_inputs[0]->info().get_channels() }; - vx_size color_stride[2] = { 0, 0 }; - color_stride[0] = sizeof(vx_float32); - color_stride[1] = color_stride[0] * color_dims[0]; - - size_t bytes_c = color_stride[1] * color_dims[1]; - allocate_host_or_pinned_mem(&_color_ptr, bytes_c, mem_type); - std::memcpy(_color_ptr, _fill_values_vec.data(), bytes_c); - - _vx_colors = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), - 2, color_dims, VX_TYPE_FLOAT32, 0, color_stride, _color_ptr, vx_mem); - if (!_vx_colors) THROW("vxCreateTensorFromHandle for color tensor failed"); - { - vx_status s = vxGetStatus((vx_reference)_vx_colors); - if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle color failed: " + TOSTR(s)); - } + // Anchor tensor handle + vx_size anchor_dims[2] = { (vx_size)_total_boxes, (vx_size)4 }; + vx_size anchor_stride[2] = { 0, 0 }; + anchor_stride[0] = sizeof(vx_int32); + anchor_stride[1] = anchor_stride[0] * anchor_dims[0]; + + size_t bytes_n = anchor_stride[1] * anchor_dims[1]; + allocate_host_or_pinned_mem(&_anchor_ptr, bytes_n, mem_type); + std::memcpy(_anchor_ptr, _anchor_vec.data(), bytes_n); + + _vx_anchor = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + 2, anchor_dims, VX_TYPE_INT32, 0, anchor_stride, _anchor_ptr, vx_mem); + if (!_vx_anchor) THROW("vxCreateTensorFromHandle for anchor tensor failed"); + { + vx_status s = vxGetStatus((vx_reference)_vx_anchor); + if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle anchor failed: " + TOSTR(s)); + } - // Output tensors for node creation - anchor_tensor = _vx_anchor; - color_tensor = _vx_colors; - _vx_num_boxes = num_boxes_arr; - } else { - if (!_anchor || !_colors) - THROW("Erase node requires non-null anchor and colors tensors") - // ParameterVX path for num_boxes - _num_boxes.create_array(_graph, VX_TYPE_INT32, _batch_size); - anchor_tensor = _anchor->handle(); - color_tensor = _colors->handle(); - num_boxes_arr = _num_boxes.default_array(); + // Color tensor handle + vx_size color_dims[2] = { (vx_size)_total_boxes, (vx_size)_inputs[0]->info().get_channels() }; + vx_size color_stride[2] = { 0, 0 }; + color_stride[0] = sizeof(vx_float32); + color_stride[1] = color_stride[0] * color_dims[0]; + + size_t bytes_c = color_stride[1] * color_dims[1]; + allocate_host_or_pinned_mem(&_color_ptr, bytes_c, mem_type); + std::memcpy(_color_ptr, _fill_values_vec.data(), bytes_c); + + _vx_colors = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + 2, color_dims, VX_TYPE_FLOAT32, 0, color_stride, _color_ptr, vx_mem); + if (!_vx_colors) THROW("vxCreateTensorFromHandle for color tensor failed"); + { + vx_status s = vxGetStatus((vx_reference)_vx_colors); + if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle color failed: " + TOSTR(s)); } + // Output tensors for node creation + anchor_tensor = _vx_anchor; + color_tensor = _vx_colors; + // _vx_num_boxes = num_boxes_arr; + // Create Erase node via MIVisionX RPP extension _node = vxExtRppErase(_graph->get(), _inputs[0]->handle(), @@ -118,7 +117,7 @@ void EraseNode::create_node() { _outputs[0]->handle(), anchor_tensor, color_tensor, - num_boxes_arr, + _vx_num_boxes, input_layout_vx, output_layout_vx, roi_type_vx); @@ -283,7 +282,7 @@ EraseNode::~EraseNode() { if (_vx_anchor) vxReleaseTensor(&_vx_anchor); if (_vx_colors) vxReleaseTensor(&_vx_colors); - if (_vx_num_boxes) vxReleaseArray(&_vx_num_boxes); + if (_vx_num_boxes) vxReleaseTensor(&_vx_num_boxes); if (mem_type == RocalMemType::HIP) { #if ENABLE_HIP @@ -297,10 +296,16 @@ EraseNode::~EraseNode() { if (err != hipSuccess) std::cerr << "\n[ERR] hipFree failed " << std::to_string(err) << "\n"; } + if (_num_box_ptr) { + hipError_t err = hipHostFree(_num_box_ptr); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipFree failed " << std::to_string(err) << "\n"; + } #endif } else { if (_anchor_ptr) free(_anchor_ptr); if (_color_ptr) free(_color_ptr); + if (_num_box_ptr) free(_num_box_ptr); } - _anchor_ptr = _color_ptr = nullptr; + _anchor_ptr = _color_ptr = _num_box_ptr = nullptr; } From 51fe74c2191d7bf7588175262eb355fed34dec90 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 14 Nov 2025 03:43:00 -0600 Subject: [PATCH 18/77] Clean up erase augmentation codes --- .../filter_augmentations/node_erase.h | 15 +---- rocAL/source/api/rocal_api_augmentation.cpp | 37 ---------- .../filter_augmentations/node_erase.cpp | 67 +++++-------------- tests/cpp_api/unit_tests/unit_tests.cpp | 64 +++++++++--------- 4 files changed, 53 insertions(+), 130 deletions(-) diff --git a/rocAL/include/augmentations/filter_augmentations/node_erase.h b/rocAL/include/augmentations/filter_augmentations/node_erase.h index 3a27784d0..c379327d2 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_erase.h +++ b/rocAL/include/augmentations/filter_augmentations/node_erase.h @@ -56,23 +56,14 @@ class EraseNode : public Node { void update_node() override; private: - ParameterVX _num_boxes; - Tensor *_anchor = nullptr; - Tensor *_colors = nullptr; - - // Raw-vector mode - bool _use_raw_vectors = false; std::vector _anchor_vec; std::vector _colors_vec, _fill_values_vec, _fill_values; std::vector _num_boxes_vec; - vx_tensor _vx_anchor = nullptr; - vx_tensor _vx_colors = nullptr; - vx_tensor _vx_num_boxes = nullptr; + vx_tensor _anchor_vx = nullptr; + vx_tensor _colors_vx = nullptr; + vx_tensor _num_boxes_vx = nullptr; void* _anchor_ptr = nullptr; void* _color_ptr = nullptr; void* _num_box_ptr = nullptr; unsigned _total_boxes = 0; - - // Conservative default range for number of boxes per sample - constexpr static int NUM_BOXES_RANGE[2] = {0, 1024}; }; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 0c5ba8cee..48f6fd9e8 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -851,43 +851,6 @@ rocalThreshold( return output; } - // New: Erase augmentation -RocalTensor ROCAL_API_CALL -rocalEraseTensor( - RocalContext p_context, - RocalTensor p_input, - bool is_output, - RocalTensor p_anchor_box_info, - RocalTensor p_colors, - RocalIntParam p_num_boxes, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - auto anchor = static_cast(p_anchor_box_info); - auto colors = static_cast(p_colors); - auto num_boxes_param = static_cast(p_num_boxes); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - auto erase_node = context->master_graph->add_node({input}, {output}); - if (num_boxes_param) - erase_node->init(anchor, colors, num_boxes_param); - else - erase_node->init(anchor, colors, 0); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - RocalTensor ROCAL_API_CALL rocalErase( RocalContext p_context, diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index c913c4769..4d9fc4434 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -28,8 +28,7 @@ THE SOFTWARE. #include EraseNode::EraseNode(const std::vector &inputs, const std::vector &outputs) - : Node(inputs, outputs), - _num_boxes(NUM_BOXES_RANGE[0], NUM_BOXES_RANGE[1]) {} + : Node(inputs, outputs) {} void EraseNode::create_node() { if (_node) @@ -45,9 +44,6 @@ void EraseNode::create_node() { vx_scalar output_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &roi_type); - vx_tensor anchor_tensor = nullptr; - vx_tensor color_tensor = nullptr; - // Select memory type and VX mem type for handle-backed tensors auto mem_type = _inputs[0]->info().mem_type(); vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; @@ -61,11 +57,11 @@ void EraseNode::create_node() { allocate_host_or_pinned_mem(&_num_box_ptr, bytes_a, mem_type); std::memcpy(_num_box_ptr, _num_boxes_vec.data(), bytes_a); - _vx_num_boxes = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + vx_tensor _num_boxes_vx = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), 1, num_box_dims, VX_TYPE_UINT32, 0, num_box_stride, _num_box_ptr, vx_mem); - if (!_vx_num_boxes) THROW("vxCreateTensorFromHandle for num_box tensor failed"); + if (!_num_boxes_vx) THROW("vxCreateTensorFromHandle for num_box tensor failed"); { - vx_status s = vxGetStatus((vx_reference)_vx_num_boxes); + vx_status s = vxGetStatus((vx_reference)_num_boxes_vx); if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle num_box failed: " + TOSTR(s)); } @@ -79,11 +75,11 @@ void EraseNode::create_node() { allocate_host_or_pinned_mem(&_anchor_ptr, bytes_n, mem_type); std::memcpy(_anchor_ptr, _anchor_vec.data(), bytes_n); - _vx_anchor = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + vx_tensor _anchor_vx = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), 2, anchor_dims, VX_TYPE_INT32, 0, anchor_stride, _anchor_ptr, vx_mem); - if (!_vx_anchor) THROW("vxCreateTensorFromHandle for anchor tensor failed"); + if (!_anchor_vx) THROW("vxCreateTensorFromHandle for anchor tensor failed"); { - vx_status s = vxGetStatus((vx_reference)_vx_anchor); + vx_status s = vxGetStatus((vx_reference)_anchor_vx); if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle anchor failed: " + TOSTR(s)); } @@ -97,27 +93,22 @@ void EraseNode::create_node() { allocate_host_or_pinned_mem(&_color_ptr, bytes_c, mem_type); std::memcpy(_color_ptr, _fill_values_vec.data(), bytes_c); - _vx_colors = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), - 2, color_dims, VX_TYPE_FLOAT32, 0, color_stride, _color_ptr, vx_mem); - if (!_vx_colors) THROW("vxCreateTensorFromHandle for color tensor failed"); + vx_tensor _colors_vx = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + 2, color_dims, VX_TYPE_FLOAT32, 0, color_stride, _color_ptr, vx_mem); + if (!_colors_vx) THROW("vxCreateTensorFromHandle for color tensor failed"); { - vx_status s = vxGetStatus((vx_reference)_vx_colors); + vx_status s = vxGetStatus((vx_reference)_colors_vx); if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle color failed: " + TOSTR(s)); } - // Output tensors for node creation - anchor_tensor = _vx_anchor; - color_tensor = _vx_colors; - // _vx_num_boxes = num_boxes_arr; - // Create Erase node via MIVisionX RPP extension _node = vxExtRppErase(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), - anchor_tensor, - color_tensor, - _vx_num_boxes, + _anchor_vx, + _colors_vx, + _num_boxes_vx, input_layout_vx, output_layout_vx, roi_type_vx); @@ -127,27 +118,11 @@ void EraseNode::create_node() { THROW("Adding the erase (vxExtRppErase) node failed: " + TOSTR(status)) } -void EraseNode::init(Tensor *anchor_box_info, Tensor *colors, int num_boxes_fixed) { - _anchor = anchor_box_info; - _colors = colors; - _num_boxes.set_param(num_boxes_fixed); - _use_raw_vectors = false; -} - -void EraseNode::init(Tensor *anchor_box_info, Tensor *colors, IntParam *num_boxes_param) { - _anchor = anchor_box_info; - _colors = colors; - _num_boxes.set_param(core(num_boxes_param)); - _use_raw_vectors = false; -} - // New: raw vector-based init (replicates across batch if needed) void EraseNode::init(std::vector anchor, std::vector shape, std::vector num_boxes, std::vector fill_value) { - // Use raw-vector path - _use_raw_vectors = true; // Keep fill pattern for colors; create_node expands it to per-box/channel _fill_values = std::move(fill_value); @@ -268,21 +243,15 @@ void EraseNode::init(std::vector anchor, } } -void EraseNode::update_node() { - if (_use_raw_vectors) { - // Raw vectors are static; nothing to update per run - return; - } - _num_boxes.update_array(); -} +void EraseNode::update_node() {} EraseNode::~EraseNode() { if (_inputs.empty() || !_inputs[0]) return; auto mem_type = _inputs[0]->info().mem_type(); - if (_vx_anchor) vxReleaseTensor(&_vx_anchor); - if (_vx_colors) vxReleaseTensor(&_vx_colors); - if (_vx_num_boxes) vxReleaseTensor(&_vx_num_boxes); + if (_anchor_vx) vxReleaseTensor(&_anchor_vx); + if (_colors_vx) vxReleaseTensor(&_colors_vx); + if (_num_boxes_vx) vxReleaseTensor(&_num_boxes_vx); if (mem_type == RocalMemType::HIP) { #if ENABLE_HIP diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 970aebe4c..da4e5ab49 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -924,7 +924,38 @@ int test(int test_case, int reader_type, const char *path, const char *outName, case 70: { std::cout << "Running rocalThresholdFixed" << std::endl; output = rocalThresholdFixed(handle, input, 64.0f, 192.0f, true, output_tensor_layout, output_tensor_dtype); - } + } break; + case 71: { + std::cout << "Running rocalErase (vector inputs, single fill value)" << std::endl; + // Use vector-based API: provide anchor [x1,y1], shape [w,h], num_boxes, and a single fill value + // Replicate num_boxes across batch with a single entry + std::vector num_boxes = {2}; + + // Derive two boxes using input width/height; keep within image bounds + unsigned W = static_cast(width); + unsigned H = static_cast(height); + unsigned bw = std::max(1u, W / 4); + unsigned bh = std::max(1u, H / 4); + + // Two anchors (x1, y1) and matching shapes (w, h) for a single-sample pattern + // Pattern will be replicated across the batch since num_boxes.size()==1 + std::vector anchor = { + static_cast(W / 8), static_cast(H / 8), + static_cast(W / 2), static_cast(H / 2) + }; + std::vector shape = { + static_cast(bw), static_cast(bh), + static_cast(W - 50), static_cast(H - 25) + }; + + // Single fill value replicated for all boxes and channels + std::vector fill_value = {0.0f}; + + // Execute vector-based erase + output = rocalErase(handle, input, true, + anchor, shape, num_boxes, fill_value, + output_tensor_layout, output_tensor_dtype); + } break; case 76: { std::cout << "Running rocalMedianFilter" << std::endl; int kernel = 3; @@ -968,37 +999,6 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output = rocalWarpPerspective(handle, input, true, height, width, perspective_1d_matrix, ROCAL_LINEAR_INTERPOLATION); }break; - case 87: { - std::cout << "Running rocalErase (vector inputs, single fill value)" << std::endl; - // Use vector-based API: provide anchor [x1,y1], shape [w,h], num_boxes, and a single fill value - // Replicate num_boxes across batch with a single entry - std::vector num_boxes = {1}; - - // Derive two boxes using input width/height; keep within image bounds - unsigned W = static_cast(width); - unsigned H = static_cast(height); - unsigned bw = std::max(1u, W / 4); - unsigned bh = std::max(1u, H / 4); - - // Two anchors (x1, y1) and matching shapes (w, h) for a single-sample pattern - // Pattern will be replicated across the batch since num_boxes.size()==1 - std::vector anchor = {0.125f * W, 0.125f * H}; - // static_cast(W / 8), static_cast(H / 8), - // static_cast(W / 2), static_cast(H / 2) - // }; - std::vector shape = {0.372f * W, 0.375f * H}; - // static_cast(bw), static_cast(bh), - // static_cast(bw), static_cast(bh) - // }; - - // Single fill value replicated for all boxes and channels - std::vector fill_value = {0.0f}; - - // Execute vector-based erase - output = rocalErase(handle, input, true, - anchor, shape, num_boxes, fill_value, - output_tensor_layout, output_tensor_dtype); - } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; From 1aa135ab7c4863d82f9b0d98aafbc2e6dc212ad9 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 4 Nov 2025 06:07:35 -0600 Subject: [PATCH 19/77] Add support for Crop and Patch augmentation --- rocAL/include/api/rocal_api_augmentation.h | 19 +++ .../augmentations/augmentations_nodes.h | 1 + .../node_crop_and_patch.h | 41 ++++++ rocAL/source/api/rocal_api_augmentation.cpp | 36 +++++ .../node_crop_and_patch.cpp | 139 ++++++++++++++++++ rocAL_pybind/amd/rocal/fn.py | 27 ++++ rocAL_pybind/rocal_pybind.cpp | 2 + tests/cpp_api/unit_tests/unit_tests.cpp | 17 +++ 8 files changed, 282 insertions(+) create mode 100644 rocAL/include/augmentations/geometry_augmentations/node_crop_and_patch.h create mode 100644 rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index f4b0a2b6a..1920ee1a6 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -531,6 +531,25 @@ extern "C" RocalTensor ROCAL_API_CALL rocalWarpPerspective(RocalContext context, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Crops and patches regions between two input tensors based on provided ROIs. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 First input tensor + * \param [in] input2 Second input tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] crop_roi Per-sample ROI tensor for crop region + * \param [in] patch_roi Per-sample ROI tensor for patch region + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalCropAndPatch(RocalContext context, + RocalTensor input1, RocalTensor input2, + bool is_output, + std::vector &crop_roi, std::vector &patch_roi, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Applies fish eye effect on images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 2c23d46bb..cfb87bc22 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -81,3 +81,4 @@ THE SOFTWARE. #include "augmentations/filter_augmentations/node_magnitude.h" #include "augmentations/filter_augmentations/node_phase.h" #include "augmentations/filter_augmentations/node_erase.h" +#include "augmentations/geometry_augmentations/node_crop_and_patch.h" diff --git a/rocAL/include/augmentations/geometry_augmentations/node_crop_and_patch.h b/rocAL/include/augmentations/geometry_augmentations/node_crop_and_patch.h new file mode 100644 index 000000000..4f1992136 --- /dev/null +++ b/rocAL/include/augmentations/geometry_augmentations/node_crop_and_patch.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 2025 Advanced Micro Devices, Inc. +All rights reserved. +*/ + +#pragma once +#include "pipeline/graph.h" +#include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" + +// CropAndPatch tensor node: crops a region from input1 and patches into input2 (or vice versa) +// based on the per-sample ROI tensors provided for destination, crop, and patch regions. +class CropAndPatchNode : public Node { +public: + CropAndPatchNode(const std::vector& inputs, const std::vector& outputs); + CropAndPatchNode() = delete; + ~CropAndPatchNode(); + + // Initialize with ROI vectors (either size 4 or N*4) + // Each vector supports per-sample [x, y, w, h] or [l, t, r, b] based on roi type. + void init(const std::vector& crop_roi_vec, + const std::vector& patch_roi_vec); + +protected: + void create_node() override; + void update_node() override; + +private: + // Store ROI specs provided by API; tensors will be created internally in create_node() + std::vector _crop_roi_vec; + std::vector _patch_roi_vec; + + // Internal OpenVX tensors created from ROI vectors (backed by external handles) + vx_tensor _crop_roi_t = nullptr; + vx_tensor _patch_roi_t = nullptr; + + // Backing buffers (host or pinned) for ROI tensors + void* _crop_roi_ptr = nullptr; + void* _patch_roi_ptr = nullptr; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 48f6fd9e8..d4dc82d06 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -1165,6 +1165,42 @@ rocalWarpPerspective( return output; } +RocalTensor ROCAL_API_CALL +rocalCropAndPatch( + RocalContext p_context, + RocalTensor p_input1, + RocalTensor p_input2, + bool is_output, + std::vector& crop_roi_vec, + std::vector& patch_roi_vec, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input1, output); + ROCAL_INVALID_INPUT_ERR(p_input2, output); + auto context = static_cast(p_context); + auto input1 = static_cast(p_input1); + auto input2 = static_cast(p_input2); + try { + // Create output tensor (same shape as input1, but allow layout/datatype override) + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input1->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + + // Pass raw ROI vectors to node; node will create vx_tensors and call vxExtRppCropAndPatch internally + context->master_graph + ->add_node({input1, input2}, {output}) + ->init(crop_roi_vec, patch_roi_vec); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalFishEye( RocalContext p_context, diff --git a/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp b/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp new file mode 100644 index 000000000..da73d8b43 --- /dev/null +++ b/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp @@ -0,0 +1,139 @@ +/* +Copyright (c) 2025 Advanced Micro Devices, Inc. +All rights reserved. +*/ + +#include "augmentations/geometry_augmentations/node_crop_and_patch.h" + +#include +#include +#include "pipeline/exception.h" + +CropAndPatchNode::CropAndPatchNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) {} + +void CropAndPatchNode::create_node() { + if (_node) + return; + + // Validate inputs + if (_crop_roi_vec.empty() || _patch_roi_vec.empty()) + THROW("CropAndPatch node requires non-empty ROI vectors for dst, crop and patch") + + // Determine N (replicate sequence behavior from CropNode) + const auto& dims_in = _inputs[0]->info().dims(); + if (dims_in.empty()) + THROW("Invalid input dims for CropAndPatch"); + vx_size N = static_cast(dims_in[0]); + auto layout = _inputs[0]->info().layout(); + if (layout == RocalTensorlayout::NFCHW || layout == RocalTensorlayout::NFHWC) { + if (dims_in.size() < 2) THROW("Invalid sequence dims for CropAndPatch"); + N = static_cast(dims_in[0] * dims_in[1]); + } + + const vx_size elems_per_sample = 4; + + // Select memory type and VX mem type + auto mem_type = _inputs[0]->info().mem_type(); + vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; + + auto make_and_fill_roi_tensor = [&](const std::vector& vec, void** backing_ptr, vx_tensor* out_t) { + const bool replicate = (vec.size() == elems_per_sample); + const size_t total_expected = static_cast(N) * elems_per_sample; + if (!(replicate || vec.size() == total_expected)) + THROW("ROI vector size mismatch. Expected " + TOSTR(total_expected) + " or 4, got " + TOSTR(vec.size())); + + // Dims [N,4], strides matching node_crop: stride[0]=elem, stride[1]=elem*N + vx_size dims[2] = {N, elems_per_sample}; + vx_size stride[2]; + stride[0] = sizeof(vx_int32); + stride[1] = stride[0] * dims[0]; + + // Allocate backing buffer and create tensor from handle + size_t bytes = stride[1] * dims[1]; + allocate_host_or_pinned_mem(backing_ptr, bytes, mem_type); + + vx_tensor tensor_vx = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + 2, dims, VX_TYPE_INT32, 0, stride, *backing_ptr, vx_mem); + if (!tensor_vx) THROW("vxCreateTensorFromHandle for ROI tensor failed"); + vx_status s = vxGetStatus((vx_reference)tensor_vx); + if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle ROI failed: " + TOSTR(s)); + + // Fill backing buffer following the declared strides + int* iptr = static_cast(*backing_ptr); + // size_t sC = stride[1] / sizeof(int); // N + for (vx_size n = 0; n < N; ++n) { + const int* src = replicate ? vec.data() : (vec.data() + n * elems_per_sample); + for (vx_size k = 0; k < elems_per_sample; ++k) { + iptr[n * elems_per_sample + k] = src[k]; + } + } + *out_t = tensor_vx; + }; + + // Create handle-backed ROI tensors and fill data + make_and_fill_roi_tensor(_crop_roi_vec, &_crop_roi_ptr, &_crop_roi_t); + make_and_fill_roi_tensor(_patch_roi_vec, &_patch_roi_ptr, &_patch_roi_t); + + // Layout and ROI scalars + vx_context vx_ctx = vxGetContext((vx_reference)_graph->get()); + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_scalar input_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &roi_type); + + // Construct the RPP CropAndPatch node + _node = vxExtRppCropAndPatch(_graph->get(), + _inputs[0]->handle(), + _inputs[1]->handle(), + _outputs[0]->handle(), + _inputs[1]->get_roi_tensor(), + _crop_roi_t, + _patch_roi_t, + input_layout_vx, + output_layout_vx, + roi_type_vx); + + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { + THROW("Adding the crop_and_patch (vxExtRppCropAndPatch) node failed: " + TOSTR(status)); + } +} + +void CropAndPatchNode::update_node() {} + +void CropAndPatchNode::init(const std::vector& crop_roi_vec, + const std::vector& patch_roi_vec) { + _crop_roi_vec = crop_roi_vec; + _patch_roi_vec = patch_roi_vec; +} + +CropAndPatchNode::~CropAndPatchNode() { + if (_inputs.empty() || !_inputs[0]) return; + auto mem_type = _inputs[0]->info().mem_type(); + if (_crop_roi_t) vxReleaseTensor(&_crop_roi_t); + if (_patch_roi_t) vxReleaseTensor(&_patch_roi_t); + + if (mem_type == RocalMemType::HIP) { +#if ENABLE_HIP + if (_crop_roi_ptr) { + hipError_t err = hipHostFree(_crop_roi_ptr); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipFree failed " << std::to_string(err) << "\n"; + } + if (_patch_roi_ptr) { + hipError_t err = hipHostFree(_patch_roi_ptr); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipFree failed " << std::to_string(err) << "\n"; + } +#endif + } else { + if (_crop_roi_ptr) free(_crop_roi_ptr); + if (_patch_roi_ptr) free(_patch_roi_ptr); + } + _crop_roi_ptr = _patch_roi_ptr = nullptr; +} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index f5a417c2f..07335c758 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -976,6 +976,33 @@ def crop(*inputs, crop=[0, 0], crop_pos_x=0.5, crop_pos_y=0.5, crop_pos_z=0.5, Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (cropped_image) +def crop_and_patch(*inputs, crop_roi=[0, 0, 0, 0], patch_roi=[0, 0, 0, 0], + device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Crops a region from the second input and patches it into a destination region in the first input. + + ROIs are specified in XYWH format: [x, y, w, h]. + + @param inputs two input tensors; first is destination, second is source for cropping + @param dst_roi (list of int) destination ROI in input0 where patch will be placed + @param crop_roi (list of int) crop ROI in input1 to extract as patch + @param patch_roi (list of int) ROI inside destination region where the patch is pasted + @param output_layout (int) tensor layout for the augmentation output + @param output_dtype (int) tensor dtype for the augmentation output + + @return Output image after crop-and-patch + """ + kwargs_pybind = { + "input_image0": inputs[0], + "input_image1": inputs[1], + "is_output": False, + "crop_roi": crop_roi, + "patch_roi": patch_roi, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.cropAndPatch(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + def color_twist(*inputs, brightness=1.0, contrast=1.0, hue=0.0, saturation=1.0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index f05b3928d..52413ade6 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1135,6 +1135,8 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("warpPerspective", &rocalWarpPerspective, py::return_value_policy::reference); + m.def("cropAndPatch", &rocalCropAndPatch, + py::return_value_policy::reference); m.def("fog", &rocalFog, py::return_value_policy::reference); m.def("fishEye", &rocalFishEye, diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index da4e5ab49..a37632d73 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -999,6 +999,23 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output = rocalWarpPerspective(handle, input, true, height, width, perspective_1d_matrix, ROCAL_LINEAR_INTERPOLATION); }break; + case 81: { + std::cout << "Running rocalCropAndPatch (vector-based ROIs)" << std::endl; + // Create a simple second input (e.g., rotated version) + RocalTensor input2 = rocalRotate(handle, input, false); + // Define XYWH ROIs (replicated across batch if size==4) + // dst_roi: place the patch at top-left corner with size WxH reduced + int roi_w = std::max(1, width / 4); + int roi_h = std::max(1, height / 4); + // crop_roi: crop region from input2 + std::vector crop_roi = {std::max(0, width/8), std::max(0, height/8), roi_w, roi_h}; + // patch_roi: patch location inside destination where crop will be pasted + std::vector patch_roi = {0, 0, roi_w, roi_h}; + output = rocalCropAndPatch(handle, input, input2, true, + crop_roi, patch_roi, + output_tensor_layout, + output_tensor_dtype); + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; From cbf16f64843760b121151777cc7f658298cd43ab Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 4 Nov 2025 06:07:48 -0600 Subject: [PATCH 20/77] Add support for remap augmentation --- rocAL/include/api/rocal_api_augmentation.h | 21 +++ .../augmentations/augmentations_nodes.h | 1 + .../geometry_augmentations/node_remap.h | 42 +++++ rocAL/source/api/rocal_api_augmentation.cpp | 42 +++++ .../geometry_augmentations/node_remap.cpp | 153 ++++++++++++++++++ 5 files changed, 259 insertions(+) create mode 100644 rocAL/include/augmentations/geometry_augmentations/node_remap.h create mode 100644 rocAL/source/augmentations/geometry_augmentations/node_remap.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 1920ee1a6..62fc8411d 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -531,6 +531,27 @@ extern "C" RocalTensor ROCAL_API_CALL rocalWarpPerspective(RocalContext context, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies remap to images using per-pixel row/col lookup tables. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] dest_height output height (0 to use input max height) + * \param [in] dest_width output width (0 to use input max width) + * \param [in] row_remap_table Tensor with remap rows (NHWC, c=1) sized to match output dimensions + * \param [in] col_remap_table Tensor with remap cols (NHWC, c=1) sized to match output dimensions + * \param [in] interpolation_type Interpolation policy + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalRemap(RocalContext context, RocalTensor input, bool is_output, + unsigned dest_height, unsigned dest_width, + std::vector &row_remap, std::vector &col_remap, + RocalResizeInterpolationType interpolation_type = ROCAL_LINEAR_INTERPOLATION, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Crops and patches regions between two input tensors based on provided ROIs. * \ingroup group_rocal_augmentations * \param [in] context Rocal context diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index cfb87bc22..910072891 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -82,3 +82,4 @@ THE SOFTWARE. #include "augmentations/filter_augmentations/node_phase.h" #include "augmentations/filter_augmentations/node_erase.h" #include "augmentations/geometry_augmentations/node_crop_and_patch.h" +#include "augmentations/geometry_augmentations/node_remap.h" diff --git a/rocAL/include/augmentations/geometry_augmentations/node_remap.h b/rocAL/include/augmentations/geometry_augmentations/node_remap.h new file mode 100644 index 000000000..862915945 --- /dev/null +++ b/rocAL/include/augmentations/geometry_augmentations/node_remap.h @@ -0,0 +1,42 @@ +/* +Copyright (c) 2025 Advanced Micro Devices, Inc. +All rights reserved. +*/ + +#pragma once +#include "pipeline/graph.h" +#include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" + +class RemapNode : public Node { +public: + RemapNode(const std::vector& inputs, const std::vector& outputs); + RemapNode() = delete; + ~RemapNode(); + + // Initialize with row/col remap vectors and interpolation policy. + // Vectors can be size H*W (replicated for all N) or N*H*W (per-sample). + void init(const std::vector& row_remap_vec, + const std::vector& col_remap_vec, + ResizeInterpolationType interpolation_type); + +protected: + void create_node() override; + void update_node() override; + +private: + // Data provided by API + std::vector _row_remap_vec; + std::vector _col_remap_vec; + + // Internal vx_tensors created from vectors (backed by external handles) + vx_tensor _row_tbl = nullptr; + vx_tensor _col_tbl = nullptr; + + // Backing buffers (host or pinned) for remap tables + void* _row_tbl_ptr = nullptr; + void* _col_tbl_ptr = nullptr; + + int _interpolation_type = 0; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index d4dc82d06..ac50f84c9 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -1165,6 +1165,48 @@ rocalWarpPerspective( return output; } +RocalTensor ROCAL_API_CALL +rocalRemap( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + unsigned dest_height, + unsigned dest_width, + std::vector& row_remap, + std::vector& col_remap, + RocalResizeInterpolationType interpolation_type, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + // Derive output size if not provided + if (dest_width == 0 || dest_height == 0) { + dest_width = input->info().max_shape()[0]; + dest_height = input->info().max_shape()[1]; + } + + // Create output tensor (may have different width/height than input) + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_data_type(op_tensor_dtype); + output_info.modify_dims_width_and_height(op_tensor_layout, dest_width, dest_height); + output = context->master_graph->create_tensor(output_info, is_output); + + // Pass raw remap vectors; node will create the vx_tensors and call vxExtRppRemap + context->master_graph + ->add_node({input}, {output}) + ->init(row_remap, col_remap, static_cast(interpolation_type)); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalCropAndPatch( RocalContext p_context, diff --git a/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp new file mode 100644 index 000000000..f2c1f40ac --- /dev/null +++ b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp @@ -0,0 +1,153 @@ +/* +Copyright (c) 2025 Advanced Micro Devices, Inc. +All rights reserved. +*/ + +#include "augmentations/geometry_augmentations/node_remap.h" + +#include +#include +#include "pipeline/exception.h" + +RemapNode::RemapNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) {} + +void RemapNode::create_node() { + if (_node) + return; + + // Validate vectors + if (_row_remap_vec.empty() || _col_remap_vec.empty()) + THROW("Remap node requires non-empty row and col remap vectors") + + // Determine N (sequence-aware) and output H,W + const auto& in_dims = _inputs[0]->info().dims(); + if (in_dims.empty()) + THROW("Invalid input dims for Remap"); + vx_size N = static_cast(in_dims[0]); + auto layout = _inputs[0]->info().layout(); + if (layout == RocalTensorlayout::NFCHW || layout == RocalTensorlayout::NFHWC) { + if (in_dims.size() < 2) THROW("Invalid sequence dims for Remap"); + N = static_cast(in_dims[0] * in_dims[1]); + } + + const auto& out_max = _outputs[0]->info().max_shape(); + if (out_max.size() < 2) + THROW("Invalid output tensor shape for Remap"); + // max_shape for images is [W, H] + const vx_size W = static_cast(out_max[0]); + const vx_size H = static_cast(out_max[1]); + + const vx_size elems_per_sample = H * W; + const vx_size total_expected = N * elems_per_sample; + + // Select memory type and VX mem type + auto mem_type = _inputs[0]->info().mem_type(); + vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; + + auto make_and_fill_map_handle = [&](const std::vector& vec, void** backing_ptr, vx_tensor* out_t) { + const bool replicate = (vec.size() == elems_per_sample); + if (!(replicate || vec.size() == total_expected)) + THROW("Remap table size mismatch. Expected " + TOSTR(total_expected) + " or " + TOSTR(elems_per_sample) + ", got " + TOSTR(vec.size())); + + // Create 4D tensor [N, H, W, 1] FP32 (NHWC with C=1), strides from last to first + vx_size dims[4] = {N, H, W, 1}; + vx_size stride[4] = {0, 0, 0, 0}; + stride[0] = sizeof(vx_float32); + stride[1] = stride[0] * dims[0]; + stride[2] = stride[1] * dims[1]; + stride[3] = stride[2] * dims[2]; + + // Allocate buffer and create tensor from handle + size_t bytes = stride[3]; // total bytes for N images + allocate_host_or_pinned_mem(backing_ptr, bytes, mem_type); + + vx_tensor t = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + 4, dims, VX_TYPE_FLOAT32, 0, stride, *backing_ptr, vx_mem); + if (!t) THROW("vxCreateTensorFromHandle for remap table failed"); + vx_status s = vxGetStatus((vx_reference)t); + if (s != VX_SUCCESS) + THROW("vxCreateTensorFromHandle remap table failed: " + TOSTR(s)); + + // Fill backing buffer following declared strides + float* fptr = static_cast(*backing_ptr); + for (vx_size n = 0; n < N; ++n) { + const float* src = replicate ? vec.data() : (vec.data() + n * elems_per_sample); + float *dst = fptr + n * elems_per_sample; + std::memcpy(dst, src, elems_per_sample); + } + *out_t = t; + }; + + // Create handle-backed row/col tables and fill data + make_and_fill_map_handle(_row_remap_vec, &_row_tbl_ptr, &_row_tbl); + make_and_fill_map_handle(_col_remap_vec, &_col_tbl_ptr, &_col_tbl); + + // Scalars for interpolation, layout and ROI + vx_context vx_ctx = vxGetContext((vx_reference)_graph->get()); + + vx_scalar interpolation_vx = + vxCreateScalar(vx_ctx, VX_TYPE_INT32, &_interpolation_type); + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + + vx_scalar input_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &roi_type); + + // Construct the RPP Remap node + _node = vxExtRppRemap(_graph->get(), + _inputs[0]->handle(), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), + _row_tbl, + _col_tbl, + interpolation_vx, + input_layout_vx, + output_layout_vx, + roi_type_vx); + + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { + THROW("Adding the remap (vxExtRppRemap) node failed: " + TOSTR(status)); + } +} + +void RemapNode::update_node() {} + +void RemapNode::init(const std::vector& row_remap_vec, + const std::vector& col_remap_vec, + ResizeInterpolationType interpolation_type) { + _row_remap_vec = row_remap_vec; + _col_remap_vec = col_remap_vec; + _interpolation_type = static_cast(interpolation_type); +} + +RemapNode::~RemapNode() { + if (_inputs.empty() || !_inputs[0]) return; + auto mem_type = _inputs[0]->info().mem_type(); + + if (_row_tbl) vxReleaseTensor(&_row_tbl); + if (_col_tbl) vxReleaseTensor(&_col_tbl); + + if (mem_type == RocalMemType::HIP) { +#if ENABLE_HIP + if (_row_tbl_ptr) { + hipError_t err = hipHostFree(_row_tbl_ptr); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipFree failed " << std::to_string(err) << "\n"; + } + if (_col_tbl_ptr) { + hipError_t err = hipHostFree(_col_tbl_ptr); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipFree failed " << std::to_string(err) << "\n"; + } +#endif + } else { + if (_row_tbl_ptr) free(_row_tbl_ptr); + if (_col_tbl_ptr) free(_col_tbl_ptr); + } + _row_tbl_ptr = _col_tbl_ptr = nullptr; +} From cc0897e0af50f984100de639ad84122eb8f3a01e Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 4 Nov 2025 06:08:43 -0600 Subject: [PATCH 21/77] Add unit trsts and python bindings for remap --- rocAL_pybind/amd/rocal/fn.py | 30 +++++++++++++++++++++++++ rocAL_pybind/rocal_pybind.cpp | 2 ++ tests/cpp_api/unit_tests/unit_tests.cpp | 28 ++++++++++++++++++++++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 07335c758..76c65daf5 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -829,6 +829,36 @@ def warp_perspective(*inputs, dest_width=0, dest_height=0, perspective=[1.0, 0.0 warp_persp_output = b.warpPerspective(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (warp_persp_output) +def remap(*inputs, dest_width=0, dest_height=0, row_remap=[], col_remap=[], + interpolation_type=types.LINEAR_INTERPOLATION, device=None, + output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies pixel remapping using per-sample row/col maps. + + @param inputs the input image tensor + @param dest_width (int, default = 0) destination width; 0 uses input max width + @param dest_height (int, default = 0) destination height; 0 uses input max height + @param row_remap (list of float) flattened HxW y-coordinates for remap + @param col_remap (list of float) flattened HxW x-coordinates for remap + @param interpolation_type (int) interpolation to use (e.g., LINEAR_INTERPOLATION) + @param output_layout (int) tensor layout for the augmentation output + @param output_dtype (int) tensor dtype for the augmentation output + + @return Remapped image + """ + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "dest_height": dest_height, + "dest_width": dest_width, + "row_remap": row_remap, + "col_remap": col_remap, + "interpolation_type": interpolation_type, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.remap(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + def vignette(*inputs, vignette=0.5, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies Vignette effect diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index 52413ade6..89125050a 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1135,6 +1135,8 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("warpPerspective", &rocalWarpPerspective, py::return_value_policy::reference); + m.def("remap", &rocalRemap, + py::return_value_policy::reference); m.def("cropAndPatch", &rocalCropAndPatch, py::return_value_policy::reference); m.def("fog", &rocalFog, diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index a37632d73..6e48d1650 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -999,8 +999,34 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output = rocalWarpPerspective(handle, input, true, height, width, perspective_1d_matrix, ROCAL_LINEAR_INTERPOLATION); }break; + case 80: { + std::cout << "Running rocalRemap (vector-based tables)" << std::endl; + // Build identity remap tables (row = y, col = x) for output size [height,width] + const int H = height; + const int W = width; + std::vector row_remap(H * W); + std::vector col_remap(H * W); + auto half_width = W / 2; + for (int y = 0; y < H; ++y) { + int x = 0; + for (; x < half_width; ++x) { + row_remap[y * W + x] = static_cast(y); + col_remap[y * W + x] = static_cast(half_width - x); + } + for (; x < W; ++x) { + row_remap[y * W + x] = static_cast(y); + col_remap[y * W + x] = static_cast(x); + } + } + // Use bilinear interpolation, default layout/dtype + output = rocalRemap(handle, input, true, + H, W, + row_remap, col_remap, + ROCAL_LINEAR_INTERPOLATION, + output_tensor_layout, output_tensor_dtype); + } break; case 81: { - std::cout << "Running rocalCropAndPatch (vector-based ROIs)" << std::endl; + std::cout << "Running rocalCropAndPatch" << std::endl; // Create a simple second input (e.g., rotated version) RocalTensor input2 = rocalRotate(handle, input, false); // Define XYWH ROIs (replicated across batch if size==4) From 58a8db4a569fd6c388db9e23849bc621a5fbba4c Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 4 Nov 2025 12:17:32 -0600 Subject: [PATCH 22/77] Add support for RICAP --- rocAL/include/api/rocal_api_augmentation.h | 21 ++- .../augmentations/augmentations_nodes.h | 1 + .../geometry_augmentations/node_ricap.h | 44 +++++ rocAL/source/api/rocal_api_augmentation.cpp | 36 ++++ .../geometry_augmentations/node_ricap.cpp | 158 ++++++++++++++++++ tests/cpp_api/unit_tests/unit_tests.cpp | 15 ++ 6 files changed, 264 insertions(+), 11 deletions(-) create mode 100644 rocAL/include/augmentations/geometry_augmentations/node_ricap.h create mode 100644 rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 62fc8411d..f7e3c2183 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1700,24 +1700,23 @@ extern "C" RocalTensor ROCAL_API_CALL rocalPhase(RocalContext context, RocalTens RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); -/*! \brief Erases regions in images based on per-sample anchor boxes and colors. +/*! \brief Random Image Cropping And Patching (RICAP). * \ingroup group_rocal_augmentations * \param [in] context Rocal context * \param [in] input Input Rocal tensor * \param [in] is_output Is the output tensor part of the graph output - * \param [in] anchor_box_info Tensor describing per-sample per-box anchors in LTRB format - * \param [in] colors Tensor describing per-sample per-box RGB colors - * \param [in] num_boxes Per-sample number of boxes (parameter) + * \param [in] permutation vector length 4 or batch*4, with 4 source indices per output sample quadrants + * \param [in] crop_rois vector length 16 or batch*16, per-sample 4 ROIs of [x,y,w,h] or [l,t,r,b] based on roiType * \param [in] output_layout the layout of the output tensor * \param [in] output_datatype the data type of the output tensor * \return RocalTensor */ -extern "C" RocalTensor ROCAL_API_CALL rocalEraseTensor(RocalContext context, RocalTensor input, - bool is_output, - RocalTensor anchor_box_info, - RocalTensor colors, - RocalIntParam num_boxes = NULL, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); +extern "C" RocalTensor ROCAL_API_CALL rocalRicap(RocalContext context, + RocalTensor input, + bool is_output, + std::vector &permutation, + std::vector &crop_rois, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); #endif // MIVISIONX_ROCAL_API_AUGMENTATION_H diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 910072891..465bd2b5b 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -83,3 +83,4 @@ THE SOFTWARE. #include "augmentations/filter_augmentations/node_erase.h" #include "augmentations/geometry_augmentations/node_crop_and_patch.h" #include "augmentations/geometry_augmentations/node_remap.h" +#include "augmentations/geometry_augmentations/node_ricap.h" diff --git a/rocAL/include/augmentations/geometry_augmentations/node_ricap.h b/rocAL/include/augmentations/geometry_augmentations/node_ricap.h new file mode 100644 index 000000000..064df07c5 --- /dev/null +++ b/rocAL/include/augmentations/geometry_augmentations/node_ricap.h @@ -0,0 +1,44 @@ +/* +Copyright (c) 2025 Advanced Micro Devices, Inc. +All rights reserved. +*/ + +#pragma once +#include "pipeline/node.h" +#include "parameters/parameter_vx.h" + +// Ricap tensor node: Random Image Cropping And Patching. +// Inputs: +// - Single input tensor +// - Outputs a tensor with same dims/layout (unless user changes layout via output tensor info) +// Parameters provided via init: +// - permutation vector: length N*4 (4 indices per output sample selecting source samples per quadrant) +// - crop_rois vector: per-sample 4 ROIs (XYWH/LTRB as per roiType) flattened; size either 16 or N*16 ints +// Order per sample: roi0[4], roi1[4], roi2[4], roi3[4] +class RicapNode : public Node { +public: + RicapNode(const std::vector& inputs, const std::vector& outputs); + RicapNode() = delete; + ~RicapNode(); + + // permutation: length 4 or N*4 (replicated if 4) + // crop_rois: length 16 or N*16 (replicated if 16) with per-sample 4x [x,y,w,h] or [l,t,r,b] + void init(const std::vector& permutation, + const std::vector& crop_rois); + +protected: + void create_node() override; + void update_node() override; + +private: + // Parameter storage from API + std::vector _permutation_vec; + std::vector _crop_rois_vec; + + // Internal VX objects created in create_node() + vx_array _perm_array_vx = nullptr; + vx_tensor _crop_rois_t = nullptr; + + // Backing buffer for ROI tensor (host or pinned) + void* _crop_rois_ptr = nullptr; +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index ac50f84c9..d40d59d44 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2977,3 +2977,39 @@ rocalPhase(RocalContext p_context, } return output; } + +// New: RICAP external API +RocalTensor ROCAL_API_CALL +rocalRicap(RocalContext p_context, + RocalTensor p_input, + bool is_output, + std::vector &permutation, + std::vector &crop_rois, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + // Output tensor inherits shape from input; allow layout/datatype override + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + if (op_tensor_layout != RocalTensorlayout::NONE) + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + + output = context->master_graph->create_tensor(output_info, is_output); + + // Wire Ricap node and pass raw vectors; node will build vx objects and call vxExtRppRicap + auto ricap_node = context->master_graph->add_node({input}, {output}); + ricap_node->init(permutation, crop_rois); + // No meta-data changes needed + } catch (const std::exception &e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} diff --git a/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp b/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp new file mode 100644 index 000000000..d45d1e5fe --- /dev/null +++ b/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp @@ -0,0 +1,158 @@ +/* +Copyright (c) 2025 Advanced Micro Devices, Inc. +All rights reserved. +*/ + +#include "augmentations/geometry_augmentations/node_ricap.h" + +#include +#include +#include "pipeline/exception.h" + +RicapNode::RicapNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) {} + +void RicapNode::create_node() { + if (_node) + return; + + // Determine effective batch (sequence-aware) + const auto& dims_in = _inputs[0]->info().dims(); + if (dims_in.empty()) + THROW("Invalid input dims for Ricap"); + vx_size N = static_cast(dims_in[0]); + auto layout = _inputs[0]->info().layout(); + if (layout == RocalTensorlayout::NFCHW || layout == RocalTensorlayout::NFHWC) { + if (dims_in.size() < 2) THROW("Invalid sequence dims for Ricap"); + N = static_cast(dims_in[0] * dims_in[1]); + } + + // Validate inputs + if (_permutation_vec.empty()) + THROW("Ricap requires non-empty permutation vector of length 4 or N*4"); + if (_crop_rois_vec.empty()) + THROW("Ricap requires non-empty crop_rois vector of length 16 or N*16"); + + // Determine mem type and VX mem + auto mem_type = _inputs[0]->info().mem_type(); + vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; + + // 1) Create permutation vx_array (length = N*4, replicate if needed) + { + std::vector perm(N * 4, 0); + if (_permutation_vec.size() == 4) { + for (vx_size n = 0; n < N; ++n) { + for (int k = 0; k < 4; ++k) + perm[n * 4 + k] = static_cast(_permutation_vec[k]); + } + } else if (_permutation_vec.size() == N * 4) { + for (vx_size i = 0; i < N * 4; ++i) + perm[i] = static_cast(_permutation_vec[i]); + } else { + THROW("Ricap permutation vector size must be 4 or N*4. Got " + TOSTR(_permutation_vec.size()) + ", expected " + TOSTR(N * 4)); + } + + _perm_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_UINT32, perm.size()); + if (!_perm_array_vx) THROW("vxCreateArray for permutation failed"); + vx_status s = vxGetStatus((vx_reference)_perm_array_vx); + if (s != VX_SUCCESS) THROW("Permutation array creation failed: " + TOSTR(s)); + s = vxAddArrayItems(_perm_array_vx, perm.size(), perm.data(), sizeof(vx_uint32)); + if (s != VX_SUCCESS) THROW("vxAddArrayItems for permutation failed: " + TOSTR(s)); + } + + // 2) Create crop-roi tensor (dims [N, 16], 4 ROIs per sample x 4 ints per ROI), replicate if vector has only 16 + { + const vx_size elems_per_sample = 16; // 4 ROIs x 4 ints + const bool replicate = (_crop_rois_vec.size() == elems_per_sample); + const size_t total_expected = static_cast(N) * elems_per_sample; + if (!(replicate || _crop_rois_vec.size() == total_expected)) { + THROW("Ricap crop_rois vector size mismatch. Expected " + TOSTR(total_expected) + " or 16, got " + TOSTR(_crop_rois_vec.size())); + } + + vx_size dims[2] = {N, elems_per_sample}; + vx_size stride[2]; + stride[0] = sizeof(vx_int32); + stride[1] = stride[0] * dims[0]; + + // Allocate backing buffer and create tensor from handle + size_t bytes = stride[1] * dims[1]; + allocate_host_or_pinned_mem(&_crop_rois_ptr, bytes, mem_type); + + vx_tensor tensor_vx = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), + 2, dims, VX_TYPE_INT32, 0, stride, _crop_rois_ptr, vx_mem); + if (!tensor_vx) THROW("vxCreateTensorFromHandle for ricap ROI tensor failed"); + vx_status s = vxGetStatus((vx_reference)tensor_vx); + if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle ROI failed: " + TOSTR(s)); + + // Fill backing buffer following the declared strides + int* iptr = static_cast(_crop_rois_ptr); + for (vx_size n = 0; n < N; ++n) { + const int* src = replicate ? _crop_rois_vec.data() : (&_crop_rois_vec[n * elems_per_sample]); + for (vx_size k = 0; k < elems_per_sample; ++k) { + iptr[n * elems_per_sample + k] = src[k]; + } + } + _crop_rois_t = tensor_vx; + } + + // 3) Prepare scalars + vx_context vx_ctx = vxGetContext((vx_reference)_graph->get()); + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + vx_scalar input_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &roi_type); + + // 4) Create VX node + _node = vxExtRppRicap(_graph->get(), + _inputs[0]->handle(), + _outputs[0]->handle(), + _perm_array_vx, + _crop_rois_t, + input_layout_vx, + output_layout_vx, + roi_type_vx); + + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { + THROW("Adding the ricap (vxExtRppRicap) node failed: " + TOSTR(status)); + } +} + +void RicapNode::update_node() { + // No dynamic attributes to update per frame +} + +void RicapNode::init(const std::vector& permutation, + const std::vector& crop_rois) { + _permutation_vec = permutation; + _crop_rois_vec = crop_rois; +} + +RicapNode::~RicapNode() { + if (_inputs.empty() || !_inputs[0]) return; + auto mem_type = _inputs[0]->info().mem_type(); + + if (_perm_array_vx) { + vxReleaseArray(&_perm_array_vx); + _perm_array_vx = nullptr; + } + if (_crop_rois_t) { + vxReleaseTensor(&_crop_rois_t); + _crop_rois_t = nullptr; + } + + if (mem_type == RocalMemType::HIP) { +#if ENABLE_HIP + if (_crop_rois_ptr) { + hipError_t err = hipHostFree(_crop_rois_ptr); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipHostFree failed " << std::to_string(err) << "\n"; + } +#endif + } else { + if (_crop_rois_ptr) free(_crop_rois_ptr); + } + _crop_rois_ptr = nullptr; +} diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 6e48d1650..7dad56172 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -1042,6 +1042,21 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output_tensor_layout, output_tensor_dtype); } break; + case 82: { + std::cout << "Running rocalRicap" << std::endl; + // Permutation for quadrants [q0,q1,q2,q3]; replicate across batch if size==4 + std::vector permutation = {0, 1, 1, 0}; + // Define 4 XYWH ROIs covering image quadrants; replicate across batch if size==16 + int q_w = std::max(1, width / 2); + int q_h = std::max(1, height / 2); + std::vector crop_rois = { + 0, 0, q_w, q_h, // top-left + q_w, 0, q_w, q_h, // top-right + 0, q_h, q_w, q_h, // bottom-left + q_w, q_h, q_w, q_h // bottom-right + }; + output = rocalRicap(handle, input, true, permutation, crop_rois, output_tensor_layout, output_tensor_dtype); + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; From 2e71384fb7046f93f1b6049720af2d807e1d63ad Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 5 Nov 2025 04:53:25 -0600 Subject: [PATCH 23/77] Add support for Bitwise NOT operation --- rocAL/include/api/rocal_api_augmentation.h | 19 +++++++ rocAL/include/api/rocal_api_types.h | 12 +++++ .../augmentations/augmentations_nodes.h | 1 + .../filter_augmentations/node_bitwise_ops.h | 38 ++++++++++++++ rocAL/include/pipeline/commons.h | 9 ++++ rocAL/source/api/rocal_api_augmentation.cpp | 33 ++++++++++++ .../filter_augmentations/node_bitwise_ops.cpp | 51 +++++++++++++++++++ rocAL_pybind/rocal_pybind.cpp | 8 +++ tests/cpp_api/unit_tests/unit_tests.cpp | 22 ++++++++ 9 files changed, 193 insertions(+) create mode 100644 rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h create mode 100644 rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index f7e3c2183..18333467e 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1719,4 +1719,23 @@ extern "C" RocalTensor ROCAL_API_CALL rocalRicap(RocalContext context, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Performs bitwise operations (AND/OR/XOR) elementwise on two input tensors. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 First input tensor (U8) + * \param [in] input2 Second input tensor (U8) + * \param [in] is_output Is the output tensor part of the graph output + * \param [in] op The bitwise operation to perform (AND/OR/XOR) + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor (defaults to U8) + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalBitwiseOps(RocalContext context, + RocalTensor input1, + RocalTensor input2, + bool is_output, + RocalBitwiseOp op, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + #endif // MIVISIONX_ROCAL_API_AUGMENTATION_H diff --git a/rocAL/include/api/rocal_api_types.h b/rocAL/include/api/rocal_api_types.h index 9a74a942b..e214b2d82 100644 --- a/rocAL/include/api/rocal_api_types.h +++ b/rocAL/include/api/rocal_api_types.h @@ -524,4 +524,16 @@ struct DistortionCoeffs { float k3; }; +/*! \brief rocAL Bitwise Operation enum + * \ingroup group_rocal_types + */ +enum RocalBitwiseOp { + /*! \brief Bitwise AND operation */ + ROCAL_BITWISE_AND = 0, + /*! \brief Bitwise OR operation */ + ROCAL_BITWISE_OR = 1, + /*! \brief Bitwise XOR operation */ + ROCAL_BITWISE_XOR = 2 +}; + #endif // MIVISIONX_ROCAL_API_TYPES_H diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 465bd2b5b..c466f8457 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -81,6 +81,7 @@ THE SOFTWARE. #include "augmentations/filter_augmentations/node_magnitude.h" #include "augmentations/filter_augmentations/node_phase.h" #include "augmentations/filter_augmentations/node_erase.h" +#include "augmentations/filter_augmentations/node_bitwise_ops.h" #include "augmentations/geometry_augmentations/node_crop_and_patch.h" #include "augmentations/geometry_augmentations/node_remap.h" #include "augmentations/geometry_augmentations/node_ricap.h" diff --git a/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h b/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h new file mode 100644 index 000000000..0956b1eb8 --- /dev/null +++ b/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h @@ -0,0 +1,38 @@ +/* +Copyright (c) 2025 Advanced Micro Devices, +Inc. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#pragma once +#include "pipeline/node.h" +#include "pipeline/commons.h" + +class BitwiseOpsNode : public Node { +public: + BitwiseOpsNode(const std::vector& inputs, const std::vector& outputs) + : Node(inputs, outputs) {} + BitwiseOpsNode() = delete; + + // Initialize the op to perform + void init(BitwiseOp op) { _op = op; } + +protected: + void create_node() override; + void update_node() override; + +private: + BitwiseOp _op { BitwiseOp::AND }; +}; diff --git a/rocAL/include/pipeline/commons.h b/rocAL/include/pipeline/commons.h index 7fb9c3ffc..2cf515910 100644 --- a/rocAL/include/pipeline/commons.h +++ b/rocAL/include/pipeline/commons.h @@ -265,3 +265,12 @@ enum class OutOfBoundsPolicy { TRIMTOSHAPE, ERROR }; + +/*! \brief Internal Bitwise Operation enum + * Internal version of RocalBitwiseOp for use within rocAL implementation + */ +enum class BitwiseOp { + AND = 0, + OR = 1, + XOR = 2 +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index d40d59d44..d122b005e 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2978,6 +2978,39 @@ rocalPhase(RocalContext p_context, return output; } +// BitwiseOps (two inputs, op selection) +extern "C" RocalTensor ROCAL_API_CALL +rocalBitwiseOps(RocalContext p_context, + RocalTensor p_input1, + RocalTensor p_input2, + bool is_output, + RocalBitwiseOp op, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input1, output); + ROCAL_INVALID_INPUT_ERR(p_input2, output); + + auto context = static_cast(p_context); + auto input1 = static_cast(p_input1); + auto input2 = static_cast(p_input2); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input1->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + + auto node = context->master_graph->add_node({input1, input2}, {output}); + node->init(static_cast(op)); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + // New: RICAP external API RocalTensor ROCAL_API_CALL rocalRicap(RocalContext p_context, diff --git a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp new file mode 100644 index 000000000..a0d8da9db --- /dev/null +++ b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp @@ -0,0 +1,51 @@ +/* +Copyright (c) 2025 +Advanced Micro Devices, Inc. All rights reserved. +*/ +#include +#include "augmentations/filter_augmentations/node_bitwise_ops.h" +#include "pipeline/exception.h" + +void BitwiseOpsNode::create_node() { + if (_node) return; + + if (_inputs.size() < 2) + THROW("BitwiseOps node needs two input tensors") + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + int op = 0; + + switch (_op) { + case BitwiseOp::AND: op = 0; break; + case BitwiseOp::OR: op = 1; break; + case BitwiseOp::XOR: op = 2; break; + default: op = 0; break; + } + + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); + vx_scalar op_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &op); + + // pSrcRoi is carried in _inputs[0] ROI tensor + _node = vxExtRppBitwiseOps(_graph->get(), + _inputs[0]->handle(), // pSrc1 + _inputs[1]->handle(), // pSrc2 + _inputs[0]->get_roi_tensor(), // pSrcRoi (per-sample ROI for inputs) + _outputs[0]->handle(), // pDst + input_layout_vx, + output_layout_vx, + roi_type_vx, + op_type_vx); + + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the bitwise ops (vxExtRppBitwiseOps) node failed: " + TOSTR(status)) +} + +void BitwiseOpsNode::update_node() { + // No per-iteration dynamic parameters +} diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index 89125050a..8689d52f8 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -753,6 +753,12 @@ py::class_(m, "rocalListOfTensorList") .value("LAST_BATCH_DROP", ROCAL_LAST_BATCH_DROP) .value("LAST_BATCH_PARTIAL", ROCAL_LAST_BATCH_PARTIAL) .export_values(); + // Bitwise Ops enum + py::enum_(types_m, "RocalBitwiseOp", "Bitwise operation selector") + .value("BITWISE_AND", ROCAL_BITWISE_AND) + .value("BITWISE_OR", ROCAL_BITWISE_OR) + .value("BITWISE_XOR", ROCAL_BITWISE_XOR) + .export_values(); py::enum_(types_m, "RocalMissingComponentsBehaviour", "Rocal Missing components behavior") .value("MISSING_COMPONENT_ERROR", ROCAL_MISSING_COMPONENT_ERROR) .value("MISSING_COMPONENT_SKIP", ROCAL_MISSING_COMPONENT_SKIP) @@ -1139,6 +1145,8 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("cropAndPatch", &rocalCropAndPatch, py::return_value_policy::reference); + m.def("bitwiseOps", &rocalBitwiseOps, + py::return_value_policy::reference); m.def("fog", &rocalFog, py::return_value_policy::reference); m.def("fishEye", &rocalFishEye, diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 7dad56172..322783e8a 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -1057,6 +1057,28 @@ int test(int test_case, int reader_type, const char *path, const char *outName, }; output = rocalRicap(handle, input, true, permutation, crop_rois, output_tensor_layout, output_tensor_dtype); } break; + case 83: { + std::cout << "Running rocalBitwiseOps AND" << std::endl; + // Create second input tensor (rotate input to get variation) + RocalTensor input2 = rocalRotate(handle, input, false); + output = rocalBitwiseOps(handle, input, input2, true, + RocalBitwiseOp::ROCAL_BITWISE_AND, + output_tensor_layout, output_tensor_dtype); + } break; + case 84: { + std::cout << "Running rocalBitwiseOps OR" << std::endl; + RocalTensor input2 = rocalRotate(handle, input, false); + output = rocalBitwiseOps(handle, input, input2, true, + RocalBitwiseOp::ROCAL_BITWISE_OR, + output_tensor_layout, output_tensor_dtype); + } break; + case 85: { + std::cout << "Running rocalBitwiseOps XOR" << std::endl; + RocalTensor input2 = rocalRotate(handle, input, false); + output = rocalBitwiseOps(handle, input, input2, true, + RocalBitwiseOp::ROCAL_BITWISE_XOR, + output_tensor_layout, output_tensor_dtype); + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; From 199d37a91fe77eacb628142f0a4bba2d91296cbd Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 11 Nov 2025 01:19:39 -0600 Subject: [PATCH 24/77] Add support for Bitwise NOT --- rocAL/include/api/rocal_api_types.h | 4 +++- .../filter_augmentations/node_bitwise_ops.h | 4 ++-- rocAL/include/pipeline/commons.h | 5 +++-- .../filter_augmentations/node_bitwise_ops.cpp | 17 ++++++----------- rocAL_pybind/rocal_pybind.cpp | 1 + tests/cpp_api/unit_tests/unit_tests.cpp | 7 +++++++ 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/rocAL/include/api/rocal_api_types.h b/rocAL/include/api/rocal_api_types.h index e214b2d82..7748aa609 100644 --- a/rocAL/include/api/rocal_api_types.h +++ b/rocAL/include/api/rocal_api_types.h @@ -533,7 +533,9 @@ enum RocalBitwiseOp { /*! \brief Bitwise OR operation */ ROCAL_BITWISE_OR = 1, /*! \brief Bitwise XOR operation */ - ROCAL_BITWISE_XOR = 2 + ROCAL_BITWISE_XOR = 2, + /*! \brief Bitwise NOT operation */ + ROCAL_BITWISE_NOT = 3 }; #endif // MIVISIONX_ROCAL_API_TYPES_H diff --git a/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h b/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h index 0956b1eb8..521bb7ba5 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h +++ b/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h @@ -27,12 +27,12 @@ class BitwiseOpsNode : public Node { BitwiseOpsNode() = delete; // Initialize the op to perform - void init(BitwiseOp op) { _op = op; } + void init(BitwiseOp op) { _operator = op; } protected: void create_node() override; void update_node() override; private: - BitwiseOp _op { BitwiseOp::AND }; + BitwiseOp _operator = BitwiseOp::AND; }; diff --git a/rocAL/include/pipeline/commons.h b/rocAL/include/pipeline/commons.h index 2cf515910..f4c20daf1 100644 --- a/rocAL/include/pipeline/commons.h +++ b/rocAL/include/pipeline/commons.h @@ -271,6 +271,7 @@ enum class OutOfBoundsPolicy { */ enum class BitwiseOp { AND = 0, - OR = 1, - XOR = 2 + OR, + XOR, + NOT }; diff --git a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp index a0d8da9db..caacc16fd 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp @@ -9,20 +9,15 @@ Advanced Micro Devices, Inc. All rights reserved. void BitwiseOpsNode::create_node() { if (_node) return; - if (_inputs.size() < 2) - THROW("BitwiseOps node needs two input tensors") + // For AND/OR/XOR require two inputs; for NOT allow a single input + if ( (_operator != BitwiseOp::NOT && _inputs.size() < 2) || + (_operator == BitwiseOp::NOT && _inputs.size() < 1) ) + THROW("BitwiseOps node needs two input tensors for binary ops and one input tensor for NOT") int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); - int op = 0; - - switch (_op) { - case BitwiseOp::AND: op = 0; break; - case BitwiseOp::OR: op = 1; break; - case BitwiseOp::XOR: op = 2; break; - default: op = 0; break; - } + int op = static_cast(_operator); vx_context ctx = vxGetContext((vx_reference)_graph->get()); vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); @@ -33,7 +28,7 @@ void BitwiseOpsNode::create_node() { // pSrcRoi is carried in _inputs[0] ROI tensor _node = vxExtRppBitwiseOps(_graph->get(), _inputs[0]->handle(), // pSrc1 - _inputs[1]->handle(), // pSrc2 + (_operator == BitwiseOp::NOT ? nullptr : _inputs[1]->handle()), // pSrc2 (optional for NOT) _inputs[0]->get_roi_tensor(), // pSrcRoi (per-sample ROI for inputs) _outputs[0]->handle(), // pDst input_layout_vx, diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index 8689d52f8..3758c216a 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -758,6 +758,7 @@ py::class_(m, "rocalListOfTensorList") .value("BITWISE_AND", ROCAL_BITWISE_AND) .value("BITWISE_OR", ROCAL_BITWISE_OR) .value("BITWISE_XOR", ROCAL_BITWISE_XOR) + .value("BITWISE_NOT", ROCAL_BITWISE_NOT) .export_values(); py::enum_(types_m, "RocalMissingComponentsBehaviour", "Rocal Missing components behavior") .value("MISSING_COMPONENT_ERROR", ROCAL_MISSING_COMPONENT_ERROR) diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 322783e8a..e6672a8b8 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -1079,6 +1079,13 @@ int test(int test_case, int reader_type, const char *path, const char *outName, RocalBitwiseOp::ROCAL_BITWISE_XOR, output_tensor_layout, output_tensor_dtype); } break; + case 86: { + std::cout << "Running rocalBitwiseOps NOT (single input)" << std::endl; + // NOT uses only a single input; pass same tensor for second parameter (ignored internally) + output = rocalBitwiseOps(handle, input, input, true, + RocalBitwiseOp::ROCAL_BITWISE_NOT, + output_tensor_layout, output_tensor_dtype); + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; From 557f137e0ae3d5f5bc486322a90567ff4cbeba79 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 19 Nov 2025 04:07:21 -0600 Subject: [PATCH 25/77] Reorganize code --- rocAL/include/api/rocal_api_augmentation.h | 186 +++---- .../augmentations/augmentations_nodes.h | 6 +- rocAL/source/api/rocal_api_augmentation.cpp | 487 +++++++++--------- rocAL_pybind/amd/rocal/fn.py | 163 +++--- rocAL_pybind/rocal_pybind.cpp | 32 +- tests/cpp_api/unit_tests/unit_tests.cpp | 6 +- tests/python_api/unit_tests.sh | 2 - 7 files changed, 438 insertions(+), 444 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index c10dfc80a..69cb37e86 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -425,39 +425,6 @@ extern "C" RocalTensor ROCAL_API_CALL rocalBlendFixed(RocalContext context, Roca RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); -/*! \brief Non-linear blend of two input images using per-sample stddev parameter. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input1 Input1 Rocal tensor - * \param [in] input2 Input2 Rocal tensor - * \param [in] is_output is the output tensor part of the graph output - * \param [in] stddev Rocal parameter defining the per-sample stddev for non-linear blend - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlend(RocalContext context, RocalTensor input1, RocalTensor input2, - bool is_output, - RocalFloatParam stddev = NULL, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - -/*! \brief Non-linear blend of two input images using a fixed stddev parameter. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input1 Input1 Rocal tensor - * \param [in] input2 Input2 Rocal tensor - * \param [in] stddev fixed stddev for non-linear blend - * \param [in] is_output is the output tensor part of the graph output - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlendFixed(RocalContext context, RocalTensor input1, RocalTensor input2, - float stddev, bool is_output, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - /*! \brief Applies affine transformation to images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context @@ -807,30 +774,6 @@ extern "C" RocalTensor ROCAL_API_CALL rocalPixelate(RocalContext context, RocalT RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); -/*! \brief Applies a grid mask effect to images by overlaying a grid of transparent/opaque tiles. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input Input Rocal tensor - * \param [in] is_output is the output tensor part of the graph output - * \param [in] tile_width width of each grid tile in pixels - * \param [in] grid_ratio ratio of masked area within a tile (0..1) - * \param [in] grid_angle angle of the grid in radians - * \param [in] translate_x translation offset in x for the grid origin - * \param [in] translate_y translation offset in y for the grid origin - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalGridMask(RocalContext context, RocalTensor input, - bool is_output, - unsigned tile_width, - float grid_ratio, - float grid_angle, - unsigned translate_x, - unsigned translate_y, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - /*! \brief Adjusts the exposure in images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context @@ -987,42 +930,6 @@ extern "C" RocalTensor ROCAL_API_CALL rocalColorTwistFixed(RocalContext context, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); -/*! \brief Applies color cast to images by blending a per-sample RGB color with input using alpha. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input Input Rocal tensor - * \param [in] is_output is the output tensor part of the graph output - * \param [in] alpha parameter that controls blending amount for color cast per sample (0..1) - * \param [in] rgb vector specifying the target color to cast. Can be a single triplet [r,g,b] replicated across batch or per-sample triplets of size batch*3 - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalColorCast(RocalContext context, RocalTensor input, - bool is_output, - RocalFloatParam alpha, - std::vector& rgb, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - -/*! \brief Applies color cast to images with fixed parameters. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input Input Rocal tensor - * \param [in] alpha fixed blending amount for color cast (0..1) - * \param [in] rgb vector specifying the target color to cast. Can be a single triplet [r,g,b] replicated across batch or per-sample triplets of size batch*3 - * \param [in] is_output is the output tensor part of the graph output - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalColorCastFixed(RocalContext context, RocalTensor input, - float alpha, - std::vector& rgb, - bool is_output, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - /*! \brief Fused function which performs crop, normalize and flip on images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context @@ -1465,6 +1372,66 @@ extern "C" RocalTensor ROCAL_API_CALL rocalLog1p(RocalContext p_context, RocalTensor p_input, bool is_output); +/*! \brief Applies color cast to images by blending a per-sample RGB color with input using alpha. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] alpha parameter that controls blending amount for color cast per sample (0..1) + * \param [in] rgb vector specifying the target color to cast. Can be a single triplet [r,g,b] replicated across batch or per-sample triplets of size batch*3 + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalColorCast(RocalContext context, RocalTensor input, + bool is_output, + RocalFloatParam alpha, + std::vector& rgb, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies color cast to images with fixed parameters. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] alpha fixed blending amount for color cast (0..1) + * \param [in] rgb vector specifying the target color to cast. Can be a single triplet [r,g,b] replicated across batch or per-sample triplets of size batch*3 + * \param [in] is_output is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalColorCastFixed(RocalContext context, RocalTensor input, + float alpha, + std::vector& rgb, + bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies a grid mask effect to images by overlaying a grid of transparent/opaque tiles. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] tile_width width of each grid tile in pixels + * \param [in] grid_ratio ratio of masked area within a tile (0..1) + * \param [in] grid_angle angle of the grid in radians + * \param [in] translate_x translation offset in x for the grid origin + * \param [in] translate_y translation offset in y for the grid origin + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalGridMask(RocalContext context, RocalTensor input, + bool is_output, + unsigned tile_width, + float grid_ratio, + float grid_angle, + unsigned translate_x, + unsigned translate_y, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Applies median filter to images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context @@ -1519,4 +1486,37 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext cont RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Non-linear blend of two input images using per-sample stddev parameter. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 Input1 Rocal tensor + * \param [in] input2 Input2 Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] stddev Rocal parameter defining the per-sample stddev for non-linear blend + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlend(RocalContext context, RocalTensor input1, RocalTensor input2, + bool is_output, + RocalFloatParam stddev = NULL, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Non-linear blend of two input images using a fixed stddev parameter. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 Input1 Rocal tensor + * \param [in] input2 Input2 Rocal tensor + * \param [in] stddev fixed stddev for non-linear blend + * \param [in] is_output is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlendFixed(RocalContext context, RocalTensor input1, RocalTensor input2, + float stddev, bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + #endif // MIVISIONX_ROCAL_API_AUGMENTATION_H diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 84a4c978e..42e78ee57 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -32,7 +32,6 @@ THE SOFTWARE. #include "augmentations/color_augmentations/node_color_temperature.h" #include "augmentations/effects_augmentations/node_fog.h" #include "augmentations/effects_augmentations/node_pixelate.h" -#include "augmentations/effects_augmentations/node_grid_mask.h" #include "augmentations/geometry_augmentations/node_lens_correction.h" #include "augmentations/color_augmentations/node_gamma.h" #include "augmentations/geometry_augmentations/node_flip.h" @@ -42,11 +41,9 @@ THE SOFTWARE. #include "augmentations/color_augmentations/node_blur.h" #include "augmentations/geometry_augmentations/node_fisheye.h" #include "augmentations/color_augmentations/node_blend.h" -#include "augmentations/color_augmentations/node_non_linear_blend.h" #include "augmentations/geometry_augmentations/node_resize.h" #include "augmentations/geometry_augmentations/node_rotate.h" #include "augmentations/color_augmentations/node_color_twist.h" -#include "augmentations/color_augmentations/node_color_cast.h" #include "augmentations/color_augmentations/node_hue.h" #include "augmentations/color_augmentations/node_saturation.h" #include "augmentations/geometry_augmentations/node_crop_mirror_normalize.h" @@ -72,5 +69,8 @@ THE SOFTWARE. #include "augmentations/audio_augmentations/node_mel_filter_bank.h" #include "augmentations/geometry_augmentations/node_transpose.h" #include "augmentations/arithmetic_augmentations/node_log1p.h" +#include "augmentations/color_augmentations/node_color_cast.h" +#include "augmentations/effects_augmentations/node_grid_mask.h" #include "augmentations/filter_augmentations/node_median_filter.h" #include "augmentations/filter_augmentations/node_gaussian_filter.h" +#include "augmentations/color_augmentations/node_non_linear_blend.h" diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 45e6a1c51..eac814c44 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -759,100 +759,6 @@ rocalBlur( return output; } -// New: Median Filter -RocalTensor ROCAL_API_CALL -rocalMedianFilter( - RocalContext p_context, - RocalTensor p_input, - bool is_output, - unsigned kernel_size, - int border_type, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(kernel_size, border_type); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -// New: Gaussian Filter (dynamic stddev) -RocalTensor ROCAL_API_CALL -rocalGaussianFilter( - RocalContext p_context, - RocalTensor p_input, - bool is_output, - RocalFloatParam p_stddev, - unsigned kernel_size, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - auto stddev = static_cast(p_stddev); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(stddev, kernel_size); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -// New: Gaussian Filter (fixed stddev) -RocalTensor ROCAL_API_CALL -rocalGaussianFilterFixed( - RocalContext p_context, - RocalTensor p_input, - float stddev, - unsigned kernel_size, - bool is_output, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(stddev, kernel_size); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - RocalTensor ROCAL_API_CALL rocalBlend( @@ -917,69 +823,6 @@ rocalBlendFixed( return output; } -RocalTensor ROCAL_API_CALL -rocalNonLinearBlend( - RocalContext p_context, - RocalTensor p_input1, - RocalTensor p_input2, - bool is_output, - RocalFloatParam p_stddev, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input1, output); - ROCAL_INVALID_INPUT_ERR(p_input2, output); - - auto context = static_cast(p_context); - auto input1 = static_cast(p_input1); - auto input2 = static_cast(p_input2); - auto stddev = static_cast(p_stddev); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); - TensorInfo output_info = input1->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_datatype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph->add_node({input1, input2}, {output})->init(stddev); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -RocalTensor ROCAL_API_CALL -rocalNonLinearBlendFixed( - RocalContext p_context, - RocalTensor p_input1, - RocalTensor p_input2, - float stddev, - bool is_output, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input1, output); - ROCAL_INVALID_INPUT_ERR(p_input2, output); - - auto context = static_cast(p_context); - auto input1 = static_cast(p_input1); - auto input2 = static_cast(p_input2); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); - TensorInfo output_info = input1->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_datatype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph->add_node({input1, input2}, {output})->init(stddev); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - RocalTensor ROCAL_API_CALL rocalWarpAffine( RocalContext p_context, @@ -1647,37 +1490,6 @@ rocalPixelate( return output; } -RocalTensor ROCAL_API_CALL -rocalGridMask( - RocalContext p_context, - RocalTensor p_input, - bool is_output, - unsigned tile_width, - float grid_ratio, - float grid_angle, - unsigned translate_x, - unsigned translate_y, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_datatype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph->add_node({input}, {output})->init(tile_width, grid_ratio, grid_angle, translate_x, translate_y); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - RocalTensor ROCAL_API_CALL rocalLensCorrection( RocalContext p_context, @@ -1833,63 +1645,6 @@ rocalColorTwistFixed( return output; } -RocalTensor ROCAL_API_CALL -rocalColorCast( - RocalContext p_context, - RocalTensor p_input, - bool is_output, - RocalFloatParam p_alpha, - std::vector& rgb, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - auto alpha = static_cast(p_alpha); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_datatype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph->add_node({input}, {output})->init(alpha, rgb); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -RocalTensor ROCAL_API_CALL -rocalColorCastFixed( - RocalContext p_context, - RocalTensor p_input, - float alpha, - std::vector& rgb, - bool is_output, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_datatype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph->add_node({input}, {output})->init(alpha, rgb); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - RocalTensor ROCAL_API_CALL rocalCropMirrorNormalize(RocalContext p_context, RocalTensor p_input, unsigned crop_height, unsigned crop_width, float start_x, float start_y, std::vector& mean, @@ -2683,3 +2438,245 @@ RocalTensor rocalLog1p(RocalContext p_context, } return output; } + +RocalTensor ROCAL_API_CALL +rocalColorCast( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_alpha, + std::vector& rgb, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto alpha = static_cast(p_alpha); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(alpha, rgb); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalColorCastFixed( + RocalContext p_context, + RocalTensor p_input, + float alpha, + std::vector& rgb, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(alpha, rgb); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalMedianFilter( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + unsigned kernel_size, + int border_type, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(kernel_size, border_type); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalGaussianFilter( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_stddev, + unsigned kernel_size, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto stddev = static_cast(p_stddev); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(stddev, kernel_size); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalGaussianFilterFixed( + RocalContext p_context, + RocalTensor p_input, + float stddev, + unsigned kernel_size, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(stddev, kernel_size); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalGridMask( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + unsigned tile_width, + float grid_ratio, + float grid_angle, + unsigned translate_x, + unsigned translate_y, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(tile_width, grid_ratio, grid_angle, translate_x, translate_y); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalNonLinearBlend( + RocalContext p_context, + RocalTensor p_input1, + RocalTensor p_input2, + bool is_output, + RocalFloatParam p_stddev, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input1, output); + ROCAL_INVALID_INPUT_ERR(p_input2, output); + + auto context = static_cast(p_context); + auto input1 = static_cast(p_input1); + auto input2 = static_cast(p_input2); + auto stddev = static_cast(p_stddev); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input1->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input1, input2}, {output})->init(stddev); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalNonLinearBlendFixed( + RocalContext p_context, + RocalTensor p_input1, + RocalTensor p_input2, + float stddev, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input1, output); + ROCAL_INVALID_INPUT_ERR(p_input2, output); + + auto context = static_cast(p_context); + auto input1 = static_cast(p_input1); + auto input2 = static_cast(p_input2); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input1->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input1, input2}, {output})->init(stddev); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 289f21507..9aa078745 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -54,39 +54,6 @@ def blend(*inputs, ratio=None, device=None, output_layout=types.NHWC, output_dty Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (blend_image) -def non_linear_blend(*inputs, stddev=None, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): - """!Non-linear blend of two input images using per-sample stddev parameter. - - @param inputs list containing two input images - @param stddev (float, optional, default = None) standard deviation parameter controlling non-linear blend - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output - - @return non-linearly blended image - """ - stddev = b.createFloatParameter(stddev) if isinstance(stddev, float) else stddev - kwargs_pybind = {"input_image0": inputs[0], "input_image1": inputs[1], "is_output": False, "stddev": stddev, - "output_layout": output_layout, "output_dtype": output_dtype} - output_image = b.nonLinearBlend(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (output_image) - -def non_linear_blend_fixed(*inputs, stddev=0.2, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): - """!Non-linear blend of two input images using a fixed stddev parameter. - - @param inputs list containing two input images - @param stddev (float, default = 0.2) fixed standard deviation parameter controlling non-linear blend - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output - - @return non-linearly blended image - """ - kwargs_pybind = {"input_image0": inputs[0], "input_image1": inputs[1], "stddev": stddev, "is_output": False, - "output_layout": output_layout, "output_dtype": output_dtype} - output_image = b.nonLinearBlendFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (output_image) - def snow(*inputs, snow=0.5, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies snow effect on images. @@ -404,37 +371,6 @@ def pixelate(*inputs, device=None, pixelate_percent=50.0, output_layout=types.NH return (pixelate_image) -def grid_mask(*inputs, tile_width=16, grid_ratio=0.5, grid_angle=0.0, translate_x=0, translate_y=0, - device=None, output_layout=types.NHWC, output_dtype=types.UINT8): - """!Applies GridMask effect by overlaying a grid of tiles with a masked ratio. - - @param inputs the input image passed to the augmentation - @param tile_width (int, default = 16) width of each grid tile in pixels - @param grid_ratio (float, default = 0.5) ratio of masked area within a tile (0..1) - @param grid_angle (float, default = 0.0) angle of the grid in radians - @param translate_x (int, default = 0) translation offset in x for the grid origin - @param translate_y (int, default = 0) translation offset in y for the grid origin - @param device (string, optional) Parameter unused for augmentation - @param output_layout (int, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, default = types.UINT8) tensor dtype for the augmentation output - - @return Image with grid mask effect applied - """ - kwargs_pybind = { - "input_image": inputs[0], - "is_output": False, - "tile_width": tile_width, - "grid_ratio": grid_ratio, - "grid_angle": grid_angle, - "translate_x": translate_x, - "translate_y": translate_y, - "output_layout": output_layout, - "output_dtype": output_dtype - } - grid_mask_image = b.gridMask(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (grid_mask_image) - - def rain(*inputs, rain=None, rain_width=0, rain_height=0, rain_transparency=None, rain_slant_angle=0.0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies Rain effect on images @@ -973,24 +909,6 @@ def color_twist(*inputs, brightness=1.0, contrast=1.0, hue=0.0, Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (color_twist_image) -def color_cast(*inputs, alpha=1.0, rgb=[0.0, 0.0, 0.0], device=None, output_layout=types.NHWC, output_dtype=types.UINT8): - """!Applies color cast by blending a target RGB color with the input using alpha. - - @param inputs the input image passed to the augmentation - @param alpha (float or FloatParam, default = 1.0) blending amount for the cast (0..1). If float, wrapped into a FloatParam. - @param rgb (list of floats, default = [0.0, 0.0, 0.0]) target color to cast; can be a single triplet [r,g,b] or per-sample triplets with length batch*3 - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output - - @return Image with color cast applied - """ - alpha = b.createFloatParameter(alpha) if isinstance(alpha, float) else alpha - kwargs_pybind = {"input_image": inputs[0], "is_output": False, "p_alpha": alpha, "rgb": rgb, - "output_layout": output_layout, "output_dtype": output_dtype} - color_cast_image = b.colorCast(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (color_cast_image) - def uniform(*inputs, range=[-1, 1], device=None): """!Applies uniform random number generation to the input images. @@ -1362,6 +1280,53 @@ def log1p(*inputs, output_datatype = types.FLOAT): log_output = b.log1p(Pipeline._current_pipeline._handle ,*(kwargs_pybind.values())) return log_output +def color_cast(*inputs, alpha=1.0, rgb=[0.0, 0.0, 0.0], device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies color cast by blending a target RGB color with the input using alpha. + + @param inputs the input image passed to the augmentation + @param alpha (float or FloatParam, default = 1.0) blending amount for the cast (0..1). If float, wrapped into a FloatParam. + @param rgb (list of floats, default = [0.0, 0.0, 0.0]) target color to cast; can be a single triplet [r,g,b] or per-sample triplets with length batch*3 + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Image with color cast applied + """ + alpha = b.createFloatParameter(alpha) if isinstance(alpha, float) else alpha + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "p_alpha": alpha, "rgb": rgb, + "output_layout": output_layout, "output_dtype": output_dtype} + color_cast_image = b.colorCast(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (color_cast_image) + +def grid_mask(*inputs, tile_width=16, grid_ratio=0.5, grid_angle=0.0, translate_x=0, translate_y=0, + device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies GridMask effect by overlaying a grid of tiles with a masked ratio. + + @param inputs the input image passed to the augmentation + @param tile_width (int, default = 16) width of each grid tile in pixels + @param grid_ratio (float, default = 0.5) ratio of masked area within a tile (0..1) + @param grid_angle (float, default = 0.0) angle of the grid in radians + @param translate_x (int, default = 0) translation offset in x for the grid origin + @param translate_y (int, default = 0) translation offset in y for the grid origin + @param device (string, optional) Parameter unused for augmentation + @param output_layout (int, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, default = types.UINT8) tensor dtype for the augmentation output + + @return Image with grid mask effect applied + """ + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "tile_width": tile_width, + "grid_ratio": grid_ratio, + "grid_angle": grid_angle, + "translate_x": translate_x, + "translate_y": translate_y, + "output_layout": output_layout, + "output_dtype": output_dtype + } + grid_mask_image = b.gridMask(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (grid_mask_image) def median_filter(*inputs, kernel_size=3, border_type=0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies median filter to images. @@ -1434,3 +1399,37 @@ def gaussian_filter_fixed(*inputs, stddev=1.0, kernel_size=3, device=None, outpu } output_image = b.gaussianFilterFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (output_image) + +def non_linear_blend(*inputs, stddev=None, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Non-linear blend of two input images using per-sample stddev parameter. + + @param inputs list containing two input images + @param stddev (float, optional, default = None) standard deviation parameter controlling non-linear blend + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return non-linearly blended image + """ + stddev = b.createFloatParameter(stddev) if isinstance(stddev, float) else stddev + kwargs_pybind = {"input_image0": inputs[0], "input_image1": inputs[1], "is_output": False, "stddev": stddev, + "output_layout": output_layout, "output_dtype": output_dtype} + output_image = b.nonLinearBlend(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + +def non_linear_blend_fixed(*inputs, stddev=0.2, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Non-linear blend of two input images using a fixed stddev parameter. + + @param inputs list containing two input images + @param stddev (float, default = 0.2) fixed standard deviation parameter controlling non-linear blend + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return non-linearly blended image + """ + kwargs_pybind = {"input_image0": inputs[0], "input_image1": inputs[1], "stddev": stddev, "is_output": False, + "output_layout": output_layout, "output_dtype": output_dtype} + output_image = b.nonLinearBlendFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index a581e714e..ca834381b 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1083,10 +1083,6 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("colorTwistFixed", &rocalColorTwistFixed, py::return_value_policy::reference); - m.def("colorCast", &rocalColorCast, - py::return_value_policy::reference); - m.def("colorCastFixed", &rocalColorCastFixed, - py::return_value_policy::reference); m.def("cropMirrorNormalize", &rocalCropMirrorNormalize, py::return_value_policy::reference); m.def("crop", &rocalCrop, @@ -1107,12 +1103,6 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("blur", &rocalBlur, py::return_value_policy::reference); - m.def("medianFilter", &rocalMedianFilter, - py::return_value_policy::reference); - m.def("gaussianFilter", &rocalGaussianFilter, - py::return_value_policy::reference); - m.def("gaussianFilterFixed", &rocalGaussianFilterFixed, - py::return_value_policy::reference); m.def("contrast", &rocalContrast, py::return_value_policy::reference); m.def("flip", &rocalFlip, @@ -1139,14 +1129,8 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("pixelate", &rocalPixelate, py::return_value_policy::reference); - m.def("gridMask", &rocalGridMask, - py::return_value_policy::reference); m.def("blend", &rocalBlend, py::return_value_policy::reference); - m.def("nonLinearBlend", &rocalNonLinearBlend, - py::return_value_policy::reference); - m.def("nonLinearBlendFixed", &rocalNonLinearBlendFixed, - py::return_value_policy::reference); m.def("randomCrop", &rocalRandomCrop, py::return_value_policy::reference); m.def("colorTemp", &rocalColorTemp, @@ -1181,5 +1165,21 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("log1p", &rocalLog1p, py::return_value_policy::reference); + m.def("colorCast", &rocalColorCast, + py::return_value_policy::reference); + m.def("colorCastFixed", &rocalColorCastFixed, + py::return_value_policy::reference); + m.def("gridMask", &rocalGridMask, + py::return_value_policy::reference); + m.def("gaussianFilter", &rocalGaussianFilter, + py::return_value_policy::reference); + m.def("gaussianFilterFixed", &rocalGaussianFilterFixed, + py::return_value_policy::reference); + m.def("medianFilter", &rocalMedianFilter, + py::return_value_policy::reference); + m.def("nonLinearBlend", &rocalNonLinearBlend, + py::return_value_policy::reference); + m.def("nonLinearBlendFixed", &rocalNonLinearBlendFixed, + py::return_value_policy::reference); } } // namespace rocal diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index d10e68a8d..54fa182de 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -915,18 +915,18 @@ int test(int test_case, int reader_type, const char *path, const char *outName, float stddev = 0.2f; output = rocalNonLinearBlendFixed(handle, input, output_1, stddev, true, output_tensor_layout, output_tensor_dtype); } break; - case 76: { + case 69: { std::cout << "Running rocalMedianFilter" << std::endl; int kernel = 3; int border_type = 0; output = rocalMedianFilter(handle, input, true, kernel, border_type, output_tensor_layout, output_tensor_dtype); } break; - case 77: { + case 70: { std::cout << "Running rocalGaussianFilter" << std::endl; // Use existing float_param defined earlier as per-sample stddev output = rocalGaussianFilter(handle, input, true, float_param, 3, output_tensor_layout, output_tensor_dtype); } break; - case 78: { + case 71: { std::cout << "Running rocalGaussianFilterFixed" << std::endl; output = rocalGaussianFilterFixed(handle, input, 0.5, 3, true, output_tensor_layout, output_tensor_dtype); } break; diff --git a/tests/python_api/unit_tests.sh b/tests/python_api/unit_tests.sh index 808d9e78e..a160dd7fb 100755 --- a/tests/python_api/unit_tests.sh +++ b/tests/python_api/unit_tests.sh @@ -96,7 +96,6 @@ do # tf classification python"$ver" unit_test.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name blend --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Blend_${rgb_name[$rgb]}_${device_name}" - python"$ver" unit_test.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name non_linear_blend --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}NonLinearBlend_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name warp_affine --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}WarpAffine_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name blur --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Blur_${rgb_name[$rgb]}_${device_name}" @@ -113,7 +112,6 @@ do # caffe detection python"$ver" unit_test.py --image-dataset-path "$caffe_detection_path" --reader-type "caffe_detection" --augmentation-name saturation --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Saturation_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$caffe_detection_path" --reader-type "caffe_detection" --augmentation-name color_twist --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}ColorTwist_${rgb_name[$rgb]}_${device_name}" - python"$ver" unit_test.py --image-dataset-path "$caffe_detection_path" --reader-type "caffe_detection" --augmentation-name color_cast --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}ColorCast_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$caffe_detection_path" --reader-type "caffe_detection" --augmentation-name rain --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Rain_${rgb_name[$rgb]}_${device_name}" # caffe2 classification From 87fff6b1b3de3827411f40dccec6f1de2e9ce733 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 19 Nov 2025 05:33:13 -0600 Subject: [PATCH 26/77] Minor fix stddev for Non-linear blend --- tests/cpp_api/unit_tests/unit_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 54fa182de..1eefa3a53 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -906,13 +906,13 @@ int test(int test_case, int reader_type, const char *path, const char *outName, case 67: { std::cout << "Running rocalNonLinearBlend" << std::endl; RocalTensor output_1 = rocalRotate(handle, input, false); - RocalFloatParam stddev_param = rocalCreateFloatParameter(0.2f); + RocalFloatParam stddev_param = rocalCreateFloatParameter(40.0f); output = rocalNonLinearBlend(handle, input, output_1, true, stddev_param, output_tensor_layout, output_tensor_dtype); } break; case 68: { std::cout << "Running rocalNonLinearBlendFixed" << std::endl; RocalTensor output_1 = rocalRotateFixed(handle, input, 45, false); - float stddev = 0.2f; + float stddev = 50.0f; output = rocalNonLinearBlendFixed(handle, input, output_1, stddev, true, output_tensor_layout, output_tensor_dtype); } break; case 69: { From c3e86972ee201fbad0bb756071658b58c63b4c09 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 21 Nov 2025 00:15:02 -0600 Subject: [PATCH 27/77] Add python support for newly added kernels Reorganize unit tests --- rocAL_pybind/amd/rocal/fn.py | 133 ++++++++++++++++++------ rocAL_pybind/rocal_pybind.cpp | 26 ++--- tests/cpp_api/unit_tests/unit_tests.cpp | 22 ++-- 3 files changed, 124 insertions(+), 57 deletions(-) diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 0946d8fd0..321352c6f 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -731,40 +731,6 @@ def warp_affine(*inputs, dest_width=0, dest_height=0, matrix=[0, 0, 0, 0, 0, 0], Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (warp_affine_output) -def warp_perspective(*inputs, dest_width=0, dest_height=0, perspective=[1.0, 0.0, 0.0, - 0.0, 1.0, 0.0, - 0.0, 0.0, 1.0], - interpolation_type=types.LINEAR_INTERPOLATION, device=None, - output_layout=types.NHWC, output_dtype=types.UINT8): - """!Applies perspective transformation to images. - - @param inputs the input image passed to the augmentation - @param dest_width (int, optional, default = 0) The length of the X dimension of the transformed image (0 uses input max width) - @param dest_height (int, optional, default = 0) The length of the Y dimension of the transformed image (0 uses input max height) - @param perspective (list of 9 floats, default = identity) 3x3 perspective transform matrix flattened row-major. - Either a single 9-element list replicated across the batch or per-sample data of length batch*9. - @param interpolation_type (int, optional, default = types.LINEAR_INTERPOLATION) Type of interpolation to be used. - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output - - @return Perspective warped images - """ - # Order of arguments must match C API binding signature in rocal_pybind: - # (context, input, is_output, dest_height, dest_width, perspective, interpolation_type, output_layout, output_datatype) - kwargs_pybind = { - "input_image": inputs[0], - "is_output": False, - "dest_height": dest_height, - "dest_width": dest_width, - "perspective": perspective, - "interpolation_type": interpolation_type, - "output_layout": output_layout, - "output_dtype": output_dtype - } - warp_persp_output = b.warpPerspective(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (warp_persp_output) - def vignette(*inputs, vignette=0.5, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies Vignette effect @@ -1515,3 +1481,102 @@ def threshold_fixed(*inputs, min=0.0, max=255.0, device=None, output_layout=type output_image = b.thresholdFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (output_image) +def warp_perspective(*inputs, dest_width=0, dest_height=0, perspective=[1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0], + interpolation_type=types.LINEAR_INTERPOLATION, device=None, + output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies perspective transformation to images. + + @param inputs the input image passed to the augmentation + @param dest_width (int, optional, default = 0) The length of the X dimension of the transformed image (0 uses input max width) + @param dest_height (int, optional, default = 0) The length of the Y dimension of the transformed image (0 uses input max height) + @param perspective (list of 9 floats, default = identity) 3x3 perspective transform matrix flattened row-major. + Either a single 9-element list replicated across the batch or per-sample data of length batch*9. + @param interpolation_type (int, optional, default = types.LINEAR_INTERPOLATION) Type of interpolation to be used. + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Perspective warped images + """ + # Order of arguments must match C API binding signature in rocal_pybind: + # (context, input, is_output, dest_height, dest_width, perspective, interpolation_type, output_layout, output_datatype) + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "dest_height": dest_height, + "dest_width": dest_width, + "perspective": perspective, + "interpolation_type": interpolation_type, + "output_layout": output_layout, + "output_dtype": output_dtype + } + warp_persp_output = b.warpPerspective(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (warp_persp_output) + +def magnitude(*inputs, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Computes the magnitude of complex input images. + + @param inputs list containing two input images (real and imaginary parts) + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Magnitude image + """ + # pybind call arguments + kwargs_pybind = {"input_image0": inputs[0], "input_image1": inputs[1], "is_output": False, + "output_layout": output_layout, "output_dtype": output_dtype} + magnitude_image = b.magnitude(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (magnitude_image) + +def phase(*inputs, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Computes the phase of complex input images. + + @param inputs list containing two input images (real and imaginary parts) + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Phase image + """ + # pybind call arguments + kwargs_pybind = {"input_image0": inputs[0], "input_image1": inputs[1], "is_output": False, + "output_layout": output_layout, "output_dtype": output_dtype} + phase_image = b.phase(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (phase_image) + +def dilate(*inputs, kernel_size=3, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies morphological dilation to images. + + @param inputs the input image passed to the augmentation + @param kernel_size (int, default = 3) kernel size for the dilation operation (pixels), typically odd: 3,5,7 + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Dilated image + """ + # pybind call arguments + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "kernel_size": kernel_size, + "output_layout": output_layout, "output_dtype": output_dtype} + dilated_image = b.dilate(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (dilated_image) + +def erode(*inputs, kernel_size=3, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies morphological erosion to images. + + @param inputs the input image passed to the augmentation + @param kernel_size (int, default = 3) kernel size for the erosion operation (pixels), typically odd: 3,5,7 + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Eroded image + """ + # pybind call arguments + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "kernel_size": kernel_size, + "output_layout": output_layout, "output_dtype": output_dtype} + eroded_image = b.erode(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (eroded_image) diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index 09bb5bc9f..435a82654 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1103,16 +1103,6 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("blur", &rocalBlur, py::return_value_policy::reference); - m.def("medianFilter", &rocalMedianFilter, - py::return_value_policy::reference); - m.def("gaussianFilter", &rocalGaussianFilter, - py::return_value_policy::reference); - m.def("gaussianFilterFixed", &rocalGaussianFilterFixed, - py::return_value_policy::reference); - m.def("threshold", &rocalThreshold, - py::return_value_policy::reference); - m.def("thresholdFixed", &rocalThresholdFixed, - py::return_value_policy::reference); m.def("contrast", &rocalContrast, py::return_value_policy::reference); m.def("flip", &rocalFlip, @@ -1127,8 +1117,6 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("warpAffineFixed", &rocalWarpAffineFixed, py::return_value_policy::reference); - m.def("warpPerspective", &rocalWarpPerspective, - py::return_value_policy::reference); m.def("fog", &rocalFog, py::return_value_policy::reference); m.def("fishEye", &rocalFishEye, @@ -1193,5 +1181,19 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("nonLinearBlendFixed", &rocalNonLinearBlendFixed, py::return_value_policy::reference); + m.def("dilate", &rocalDilateFilter, + py::return_value_policy::reference); + m.def("erode", &rocalErodeFilter, + py::return_value_policy::reference); + m.def("magnitude", &rocalMagnitude, + py::return_value_policy::reference); + m.def("phase", &rocalPhase, + py::return_value_policy::reference); + m.def("threshold", &rocalThreshold, + py::return_value_policy::reference); + m.def("thresholdFixed", &rocalThresholdFixed, + py::return_value_policy::reference); + m.def("warpPerspective", &rocalWarpPerspective, + py::return_value_policy::reference); } } // namespace rocal diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index f86b62bc7..8d527306a 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -916,16 +916,6 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output = rocalNonLinearBlendFixed(handle, input, output_1, stddev, true, output_tensor_layout, output_tensor_dtype); } break; case 69: { - std::cout << "Running rocalThreshold" << std::endl; - std::vector min_threshold = {30.0f, 30.0f, 30.0f}; - std::vector max_threshold = {100.0f, 100.0f, 100.0f}; - output = rocalThreshold(handle, input, min_threshold, max_threshold, true, output_tensor_layout, output_tensor_dtype); - } break; - case 70: { - std::cout << "Running rocalThresholdFixed" << std::endl; - output = rocalThresholdFixed(handle, input, 64.0f, 192.0f, true, output_tensor_layout, output_tensor_dtype); - } - case 76: { std::cout << "Running rocalMedianFilter" << std::endl; int kernel = 3; int border_type = 0; @@ -960,7 +950,17 @@ int test(int test_case, int reader_type, const char *path, const char *outName, RocalTensor input2 = rocalRotate(handle, input, false); output = rocalPhase(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); } break; - case 79: { + case 76: { + std::cout << "Running rocalThreshold" << std::endl; + std::vector min_threshold = {30.0f, 30.0f, 30.0f}; + std::vector max_threshold = {100.0f, 100.0f, 100.0f}; + output = rocalThreshold(handle, input, min_threshold, max_threshold, true, output_tensor_layout, output_tensor_dtype); + } break; + case 77: { + std::cout << "Running rocalThresholdFixed" << std::endl; + output = rocalThresholdFixed(handle, input, 64.0f, 192.0f, true, output_tensor_layout, output_tensor_dtype); + } + case 78: { std::cout << "Running rocalWarpPerspective" << std::endl; std::vector perspective_1d_matrix = {0.93f, 0.5f, 0.0f, -0.5f, 0.93f, 0.0f, From 6f81f41c41882b674bd0a1d286a7c3b3fdc9bc5d Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 21 Nov 2025 01:39:09 -0600 Subject: [PATCH 28/77] Minor changes --- rocAL/source/api/rocal_api_augmentation.cpp | 2 +- rocAL_pybind/amd/rocal/fn.py | 54 ++++++++++----------- tests/python_api/unit_test.py | 21 +++----- 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 1562ba716..8c5a025ad 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -3103,7 +3103,7 @@ rocalRicap(RocalContext p_context, return output; } -extern "C" RocalTensor ROCAL_API_CALL +RocalTensor ROCAL_API_CALL rocalBitwiseOps(RocalContext p_context, RocalTensor p_input1, RocalTensor p_input2, diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 84f6d4cc3..c1fe6b5de 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -878,33 +878,6 @@ def crop(*inputs, crop=[0, 0], crop_pos_x=0.5, crop_pos_y=0.5, crop_pos_z=0.5, Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (cropped_image) -def crop_and_patch(*inputs, crop_roi=[0, 0, 0, 0], patch_roi=[0, 0, 0, 0], - device=None, output_layout=types.NHWC, output_dtype=types.UINT8): - """!Crops a region from the second input and patches it into a destination region in the first input. - - ROIs are specified in XYWH format: [x, y, w, h]. - - @param inputs two input tensors; first is destination, second is source for cropping - @param dst_roi (list of int) destination ROI in input0 where patch will be placed - @param crop_roi (list of int) crop ROI in input1 to extract as patch - @param patch_roi (list of int) ROI inside destination region where the patch is pasted - @param output_layout (int) tensor layout for the augmentation output - @param output_dtype (int) tensor dtype for the augmentation output - - @return Output image after crop-and-patch - """ - kwargs_pybind = { - "input_image0": inputs[0], - "input_image1": inputs[1], - "is_output": False, - "crop_roi": crop_roi, - "patch_roi": patch_roi, - "output_layout": output_layout, - "output_dtype": output_dtype - } - output_image = b.cropAndPatch(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (output_image) - def color_twist(*inputs, brightness=1.0, contrast=1.0, hue=0.0, saturation=1.0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): @@ -1608,6 +1581,33 @@ def erode(*inputs, kernel_size=3, device=None, output_layout=types.NHWC, output_ eroded_image = b.erode(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (eroded_image) +def crop_and_patch(*inputs, crop_roi=[0, 0, 0, 0], patch_roi=[0, 0, 0, 0], + device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Crops a region from the second input and patches it into a destination region in the first input. + + ROIs are specified in XYWH format: [x, y, w, h]. + + @param inputs two input tensors; first is destination, second is source for cropping + @param dst_roi (list of int) destination ROI in input0 where patch will be placed + @param crop_roi (list of int) crop ROI in input1 to extract as patch + @param patch_roi (list of int) ROI inside destination region where the patch is pasted + @param output_layout (int) tensor layout for the augmentation output + @param output_dtype (int) tensor dtype for the augmentation output + + @return Output image after crop-and-patch + """ + kwargs_pybind = { + "input_image0": inputs[0], + "input_image1": inputs[1], + "is_output": False, + "crop_roi": crop_roi, + "patch_roi": patch_roi, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.cropAndPatch(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + def remap(*inputs, dest_width=0, dest_height=0, row_remap=[], col_remap=[], interpolation_type=types.LINEAR_INTERPOLATION, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index eede59cf4..291cce895 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -474,22 +474,15 @@ def main(): translate_y=0, output_layout=tensor_layout, output_dtype=tensor_dtype) - elif augmentation_name == "erase": + # elif augmentation_name == "erase": # Erase requires auxiliary tensors: anchor_box_info [N, max_boxes, 4] and colors [N, max_boxes, 3]. # If the test environment provides them, import and run erase; otherwise, fall back to copy to keep pipeline functional. - try: - from test_aux_tensors import anchor_tensor, color_tensor, num_boxes_param - output = fn.erase(images, - anchor_box_info=anchor_tensor, - colors=color_tensor, - num_boxes=num_boxes_param, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - except Exception as e: - print("Erase aux tensors not provided -- skipping erase test path:", e) - output = fn.copy(images, - output_layout=tensor_layout, - output_dtype=tensor_dtype) + # output = fn.erase(images, + # anchor_box_info=anchor_tensor, + # colors=color_tensor, + # num_boxes=num_boxes_param, + # output_layout=tensor_layout, + # output_dtype=tensor_dtype) elif augmentation_name == "exposure": output = fn.exposure(images, exposure=1.0, From b43260f8fe050fdef12dba8183bd3a19e0598cf7 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 21 Nov 2025 05:27:51 -0600 Subject: [PATCH 29/77] Fix build issues --- rocAL/include/api/rocal_api_augmentation.h | 75 +--------------- rocAL/source/api/rocal_api_augmentation.cpp | 99 +-------------------- rocAL_pybind/amd/rocal/fn.py | 23 ----- rocAL_pybind/rocal_pybind.cpp | 6 +- tests/cpp_api/unit_tests/unit_tests.cpp | 4 - 5 files changed, 8 insertions(+), 199 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 6170b7ba7..da05bc7c7 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1432,61 +1432,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGridMask(RocalContext context, RocalT RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); -/*! \brief Applies median filter to images. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input Input Rocal tensor - * \param [in] is_output Is the output tensor part of the graph output - * \param [in] kernel_size Median filter kernel size (pixels) - * \param [in] border_type Border handling policy (implementation specific) - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalMedianFilter(RocalContext context, RocalTensor input, - bool is_output, - unsigned kernel_size = 3, - int border_type = 0, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - -/*! \brief Applies gaussian filter to images with per-sample stddev parameter. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input Input Rocal tensor - * \param [in] is_output Is the output tensor part of the graph output - * \param [in] stddev Per-sample standard deviation parameter - * \param [in] kernel_size Gaussian filter kernel size (pixels) - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilter(RocalContext context, RocalTensor input, - bool is_output, - RocalFloatParam stddev = NULL, - unsigned kernel_size = 3, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - -/*! \brief Applies gaussian filter to images with fixed stddev. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input Input Rocal tensor - * \param [in] stddev Fixed standard deviation value - * \param [in] kernel_size Gaussian filter kernel size (pixels) - * \param [in] is_output Is the output tensor part of the graph output - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext context, RocalTensor input, - float stddev, - unsigned kernel_size, - bool is_output, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - - /*! \brief Non-linear blend of two input images using per-sample stddev parameter. +/*! \brief Non-linear blend of two input images using per-sample stddev parameter. * \ingroup group_rocal_augmentations * \param [in] context Rocal context * \param [in] input1 Input1 Rocal tensor @@ -1519,7 +1465,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlendFixed(RocalContext cont RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); - /*! \brief Applies median filter to images. +/*! \brief Applies median filter to images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context * \param [in] input Input Rocal tensor @@ -1593,23 +1539,6 @@ extern "C" RocalTensor ROCAL_API_CALL rocalThreshold(RocalContext context, Rocal RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); -/*! \brief Applies thresholding to images with fixed min/max parameters. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input Input Rocal tensor - * \param [in] min fixed minimum threshold value - * \param [in] max fixed maximum threshold value - * \param [in] is_output Is the output tensor part of the graph output - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalThresholdFixed(RocalContext context, RocalTensor input, - float min, float max, - bool is_output, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - /*! \brief Applies dilate to images (morphological operation). * \ingroup group_rocal_augmentations * \param [in] context Rocal context diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 348e78f45..c39461744 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2495,97 +2495,6 @@ rocalColorCastFixed( return output; } -RocalTensor ROCAL_API_CALL -rocalMedianFilter( - RocalContext p_context, - RocalTensor p_input, - bool is_output, - unsigned kernel_size, - int border_type, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(kernel_size, border_type); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -RocalTensor ROCAL_API_CALL -rocalGaussianFilter( - RocalContext p_context, - RocalTensor p_input, - bool is_output, - RocalFloatParam p_stddev, - unsigned kernel_size, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - auto stddev = static_cast(p_stddev); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(stddev, kernel_size); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -RocalTensor ROCAL_API_CALL -rocalGaussianFilterFixed( - RocalContext p_context, - RocalTensor p_input, - float stddev, - unsigned kernel_size, - bool is_output, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(stddev, kernel_size); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - RocalTensor ROCAL_API_CALL rocalGridMask( RocalContext p_context, @@ -2681,7 +2590,7 @@ rocalNonLinearBlendFixed( } // Dilate -extern "C" RocalTensor ROCAL_API_CALL +RocalTensor ROCAL_API_CALL rocalDilate(RocalContext p_context, RocalTensor p_input, bool is_output, @@ -2708,7 +2617,7 @@ rocalDilate(RocalContext p_context, } // Erode -extern "C" RocalTensor ROCAL_API_CALL +RocalTensor ROCAL_API_CALL rocalErode(RocalContext p_context, RocalTensor p_input, bool is_output, @@ -2735,7 +2644,7 @@ rocalErode(RocalContext p_context, } // Magnitude (two inputs) -extern "C" RocalTensor ROCAL_API_CALL +RocalTensor ROCAL_API_CALL rocalMagnitude(RocalContext p_context, RocalTensor p_input1, RocalTensor p_input2, @@ -2765,7 +2674,7 @@ rocalMagnitude(RocalContext p_context, } // Phase (two inputs) -extern "C" RocalTensor ROCAL_API_CALL +RocalTensor ROCAL_API_CALL rocalPhase(RocalContext p_context, RocalTensor p_input1, RocalTensor p_input2, diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 321352c6f..f29e23096 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1458,29 +1458,6 @@ def threshold(*inputs, min=None, max=None, device=None, output_layout=types.NHWC output_image = b.threshold(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (output_image) -def threshold_fixed(*inputs, min=0.0, max=255.0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): - """!Applies thresholding to images with fixed min/max values. - - @param inputs the input image passed to the augmentation - @param min (float, default = 0.0) fixed minimum threshold value - @param max (float, default = 255.0) fixed maximum threshold value - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output - - @return Thresholded image - """ - kwargs_pybind = { - "input_image": inputs[0], - "min": min, - "max": max, - "is_output": False, - "output_layout": output_layout, - "output_dtype": output_dtype - } - output_image = b.thresholdFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (output_image) - def warp_perspective(*inputs, dest_width=0, dest_height=0, perspective=[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0], diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index 435a82654..277c5c310 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1181,9 +1181,9 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("nonLinearBlendFixed", &rocalNonLinearBlendFixed, py::return_value_policy::reference); - m.def("dilate", &rocalDilateFilter, + m.def("dilate", &rocalDilate, py::return_value_policy::reference); - m.def("erode", &rocalErodeFilter, + m.def("erode", &rocalErode, py::return_value_policy::reference); m.def("magnitude", &rocalMagnitude, py::return_value_policy::reference); @@ -1191,8 +1191,6 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("threshold", &rocalThreshold, py::return_value_policy::reference); - m.def("thresholdFixed", &rocalThresholdFixed, - py::return_value_policy::reference); m.def("warpPerspective", &rocalWarpPerspective, py::return_value_policy::reference); } diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 8d527306a..f8d48030b 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -957,10 +957,6 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output = rocalThreshold(handle, input, min_threshold, max_threshold, true, output_tensor_layout, output_tensor_dtype); } break; case 77: { - std::cout << "Running rocalThresholdFixed" << std::endl; - output = rocalThresholdFixed(handle, input, 64.0f, 192.0f, true, output_tensor_layout, output_tensor_dtype); - } - case 78: { std::cout << "Running rocalWarpPerspective" << std::endl; std::vector perspective_1d_matrix = {0.93f, 0.5f, 0.0f, -0.5f, 0.93f, 0.0f, From f99bb78ad7052a9d247129f83d3dbd373951c30f Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 21 Nov 2025 05:42:48 -0600 Subject: [PATCH 30/77] Minor change --- tests/cpp_api/unit_tests/unit_tests.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 086f9b055..921cc24eb 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -964,7 +964,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output = rocalWarpPerspective(handle, input, true, height, width, perspective_1d_matrix, ROCAL_LINEAR_INTERPOLATION); }break; - case 80: { + case 78: { std::cout << "Running rocalRemap (vector-based tables)" << std::endl; // Build identity remap tables (row = y, col = x) for output size [height,width] const int H = height; @@ -990,7 +990,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, ROCAL_LINEAR_INTERPOLATION, output_tensor_layout, output_tensor_dtype); } break; - case 81: { + case 79: { std::cout << "Running rocalCropAndPatch" << std::endl; // Create a simple second input (e.g., rotated version) RocalTensor input2 = rocalRotate(handle, input, false); @@ -1007,7 +1007,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, output_tensor_layout, output_tensor_dtype); } break; - case 82: { + case 80: { std::cout << "Running rocalRicap" << std::endl; // Permutation for quadrants [q0,q1,q2,q3]; replicate across batch if size==4 std::vector permutation = {0, 1, 1, 0}; @@ -1022,7 +1022,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, }; output = rocalRicap(handle, input, true, permutation, crop_rois, output_tensor_layout, output_tensor_dtype); } break; - case 83: { + case 81: { std::cout << "Running rocalBitwiseOps AND" << std::endl; // Create second input tensor (rotate input to get variation) RocalTensor input2 = rocalRotate(handle, input, false); @@ -1030,28 +1030,28 @@ int test(int test_case, int reader_type, const char *path, const char *outName, RocalBitwiseOp::ROCAL_BITWISE_AND, output_tensor_layout, output_tensor_dtype); } break; - case 84: { + case 82: { std::cout << "Running rocalBitwiseOps OR" << std::endl; RocalTensor input2 = rocalRotate(handle, input, false); output = rocalBitwiseOps(handle, input, input2, true, RocalBitwiseOp::ROCAL_BITWISE_OR, output_tensor_layout, output_tensor_dtype); } break; - case 85: { + case 83: { std::cout << "Running rocalBitwiseOps XOR" << std::endl; RocalTensor input2 = rocalRotate(handle, input, false); output = rocalBitwiseOps(handle, input, input2, true, RocalBitwiseOp::ROCAL_BITWISE_XOR, output_tensor_layout, output_tensor_dtype); } break; - case 86: { + case 84: { std::cout << "Running rocalBitwiseOps NOT (single input)" << std::endl; // NOT uses only a single input; pass same tensor for second parameter (ignored internally) output = rocalBitwiseOps(handle, input, input, true, RocalBitwiseOp::ROCAL_BITWISE_NOT, output_tensor_layout, output_tensor_dtype); } break; - case 87: { + case 85: { std::cout << "Running rocalErase (vector inputs, single fill value)" << std::endl; // Use vector-based API: provide anchor [x1,y1], shape [w,h], num_boxes, and a single fill value // Replicate num_boxes across batch with a single entry From bc87cf87dbed6942436fae29b95c78a275a4ba75 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Sun, 23 Nov 2025 23:35:54 -0600 Subject: [PATCH 31/77] Fix issues with Remap --- .../source/augmentations/geometry_augmentations/node_remap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp index f2c1f40ac..0e8aff1bd 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp @@ -74,7 +74,7 @@ void RemapNode::create_node() { for (vx_size n = 0; n < N; ++n) { const float* src = replicate ? vec.data() : (vec.data() + n * elems_per_sample); float *dst = fptr + n * elems_per_sample; - std::memcpy(dst, src, elems_per_sample); + std::memcpy(dst, src, elems_per_sample * sizeof(float)); } *out_t = t; }; From 913167a50e0441aa7319a698f0a94b56b75b5ed3 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 2 Dec 2025 08:48:33 -0600 Subject: [PATCH 32/77] Add new test cases --- tests/cpp_api/unit_tests/testAllScripts.sh | 8 ++++++++ tests/cpp_api/unit_tests/unit_tests.cpp | 16 ++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/cpp_api/unit_tests/testAllScripts.sh b/tests/cpp_api/unit_tests/testAllScripts.sh index 12626f498..ad2b3ac1d 100755 --- a/tests/cpp_api/unit_tests/testAllScripts.sh +++ b/tests/cpp_api/unit_tests/testAllScripts.sh @@ -222,6 +222,14 @@ do ./unit_tests 2 "$coco_detection_path" "${output_path}ROIResize_${rgb_name[$rgb]}_${device_name}" $width $height 60 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}Nop_${rgb_name[$rgb]}_${device_name}" $width $height 61 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}ColorCastRandom_${rgb_name[$rgb]}_${device_name}" $width $height 64 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}ColorCast_${rgb_name[$rgb]}_${device_name}" $width $height 65 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}GridMask_${rgb_name[$rgb]}_${device_name}" $width $height 66 $device $rgb 1 $display + # ./unit_tests 2 "$coco_detection_path" "${output_path}NonLinearBlend_${rgb_name[$rgb]}_${device_name}" $width $height 66 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}MedianFilter_${rgb_name[$rgb]}_${device_name}" $width $height 69 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianFilterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 70 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianFilter_${rgb_name[$rgb]}_${device_name}" $width $height 71 $device $rgb 1 $display + # to_tensor coverage tests for ((memcpy_backend=0;memcpy_backend<=1;memcpy_backend++)) do diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 1eefa3a53..d9777f761 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -886,19 +886,19 @@ int test(int test_case, int reader_type, const char *path, const char *outName, } break; case 64: { std::cout << "Running rocalColorCast" << std::endl; - std::vector rgb = {0.25f, 0.10f, 0.00f}; - output = rocalColorCast(handle, input, true, float_param, rgb, output_tensor_layout, output_tensor_dtype); + std::vector rgb = {12.0f, 0.0f, 100.00f}; + output = rocalColorCast(handle, input, true, nullptr, rgb, output_tensor_layout, output_tensor_dtype); } break; case 65: { std::cout << "Running rocalColorCastFixed" << std::endl; - std::vector rgb = {0.25f, 0.10f, 0.00f}; + std::vector rgb = {12.0f, 0.0f, 100.0f}; output = rocalColorCastFixed(handle, input, 0.5f, rgb, true, output_tensor_layout, output_tensor_dtype); } break; case 66: { std::cout << "Running rocalGridMask" << std::endl; - unsigned tile_width = 32; - float grid_ratio = 0.5f; - float grid_angle = 0.0f; // radians + unsigned tile_width = 40; + float grid_ratio = 0.6f; + float grid_angle = 0.5f; // radians unsigned translate_x = 0; unsigned translate_y = 0; output = rocalGridMask(handle, input, true, tile_width, grid_ratio, grid_angle, translate_x, translate_y, output_tensor_layout, output_tensor_dtype); @@ -924,11 +924,11 @@ int test(int test_case, int reader_type, const char *path, const char *outName, case 70: { std::cout << "Running rocalGaussianFilter" << std::endl; // Use existing float_param defined earlier as per-sample stddev - output = rocalGaussianFilter(handle, input, true, float_param, 3, output_tensor_layout, output_tensor_dtype); + output = rocalGaussianFilter(handle, input, true, nullptr, 3, output_tensor_layout, output_tensor_dtype); } break; case 71: { std::cout << "Running rocalGaussianFilterFixed" << std::endl; - output = rocalGaussianFilterFixed(handle, input, 0.5, 3, true, output_tensor_layout, output_tensor_dtype); + output = rocalGaussianFilterFixed(handle, input, 5.0f, 3, true, output_tensor_layout, output_tensor_dtype); } break; default: std::cout << "Not a valid option! Exiting!\n"; From 982efeb754762d6e3196a435b344efa37c5e6735 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Thu, 4 Dec 2025 12:58:33 -0600 Subject: [PATCH 33/77] Fix params for Golden outputs --- tests/cpp_api/unit_tests/unit_tests.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 17d86de36..9e57471a5 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -941,19 +941,27 @@ int test(int test_case, int reader_type, const char *path, const char *outName, case 74: { std::cout << "Running rocalMagnitude" << std::endl; // Create a second tensor by rotating the input; use as second input to magnitude - RocalTensor input2 = rocalRotate(handle, input, false); + RocalTensor input2 = rocalRotateFixed(handle, input, 45.0f, false); output = rocalMagnitude(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); } break; case 75: { std::cout << "Running rocalPhase" << std::endl; // Create a second tensor by rotating the input; use as second input to phase - RocalTensor input2 = rocalRotate(handle, input, false); + RocalTensor input2 = rocalRotateFixed(handle, input, 45.0f, false); output = rocalPhase(handle, input, input2, true, output_tensor_layout, output_tensor_dtype); } break; case 76: { std::cout << "Running rocalThreshold" << std::endl; - std::vector min_threshold = {30.0f, 30.0f, 30.0f}; - std::vector max_threshold = {100.0f, 100.0f, 100.0f}; + std::vector min_threshold; + std::vector max_threshold; + if (rgb) { + min_threshold = {30.0f, 30.0f, 30.0f}; + max_threshold = {100.0f, 100.0f, 100.0f}; + } else { + min_threshold = {30.0f}; + max_threshold = {100.0f}; + } + output = rocalThreshold(handle, input, min_threshold, max_threshold, true, output_tensor_layout, output_tensor_dtype); } break; case 77: { From ac105748237c89c8de56d27e7087b24dfc166cda Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 5 Dec 2025 05:30:13 -0600 Subject: [PATCH 34/77] Fix the color ptr type in erase --- .../filter_augmentations/node_erase.cpp | 86 +++++++++++++++---- 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index 4d9fc4434..d00fc41ba 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -27,6 +27,25 @@ THE SOFTWARE. #include "pipeline/tensor.h" #include +inline vx_enum interpret_tensor_data_type(RocalTensorDataType data_type) { + switch (data_type) { + case RocalTensorDataType::FP32: + return VX_TYPE_FLOAT32; + case RocalTensorDataType::FP16: + return VX_TYPE_FLOAT16; + case RocalTensorDataType::UINT8: + return VX_TYPE_UINT8; + case RocalTensorDataType::UINT32: + return VX_TYPE_UINT32; + case RocalTensorDataType::INT32: + return VX_TYPE_INT32; + case RocalTensorDataType::INT16: + return VX_TYPE_INT16; + default: + THROW("Unsupported Tensor type " + TOSTR(data_type)) + } +} + EraseNode::EraseNode(const std::vector &inputs, const std::vector &outputs) : Node(inputs, outputs) {} @@ -83,18 +102,53 @@ void EraseNode::create_node() { if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle anchor failed: " + TOSTR(s)); } - // Color tensor handle + // Color tensor handle - match input tensor data type + auto input_data_type = _inputs[0]->info().data_type(); + vx_enum vx_color_type = interpret_tensor_data_type(input_data_type); + size_t color_element_size = tensor_data_size(input_data_type); + vx_size color_dims[2] = { (vx_size)_total_boxes, (vx_size)_inputs[0]->info().get_channels() }; vx_size color_stride[2] = { 0, 0 }; - color_stride[0] = sizeof(vx_float32); + color_stride[0] = color_element_size; color_stride[1] = color_stride[0] * color_dims[0]; size_t bytes_c = color_stride[1] * color_dims[1]; allocate_host_or_pinned_mem(&_color_ptr, bytes_c, mem_type); - std::memcpy(_color_ptr, _fill_values_vec.data(), bytes_c); + + // Convert and copy fill values according to input data type + if (input_data_type == RocalTensorDataType::UINT8) { + uint8_t* color_ptr_u8 = static_cast(_color_ptr); + for (size_t i = 0; i < _fill_values_vec.size(); i++) { + color_ptr_u8[i] = static_cast(std::round(std::max(0.0f, std::min(255.0f, _fill_values_vec[i])))); + } + } else if (input_data_type == RocalTensorDataType::INT16) { + int16_t* color_ptr_i16 = static_cast(_color_ptr); + for (size_t i = 0; i < _fill_values_vec.size(); i++) { + color_ptr_i16[i] = static_cast(std::round(_fill_values_vec[i])); + } + } else if (input_data_type == RocalTensorDataType::UINT32) { + uint32_t* color_ptr_u32 = static_cast(_color_ptr); + for (size_t i = 0; i < _fill_values_vec.size(); i++) { + color_ptr_u32[i] = static_cast(std::round(std::max(0.0f, _fill_values_vec[i]))); + } + } else if (input_data_type == RocalTensorDataType::INT32) { + int32_t* color_ptr_i32 = static_cast(_color_ptr); + for (size_t i = 0; i < _fill_values_vec.size(); i++) { + color_ptr_i32[i] = static_cast(std::round(_fill_values_vec[i])); + } + } else if (input_data_type == RocalTensorDataType::FP16) { + // For FP16, we need to handle it as 16-bit values + uint16_t* color_ptr_f16 = static_cast(_color_ptr); + for (size_t i = 0; i < _fill_values_vec.size(); i++) { + // Convert float to half precision (simplified conversion) + color_ptr_f16[i] = static_cast(_fill_values_vec[i]); + } + } else { // FP32 or default case + std::memcpy(_color_ptr, _fill_values_vec.data(), bytes_c); + } vx_tensor _colors_vx = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), - 2, color_dims, VX_TYPE_FLOAT32, 0, color_stride, _color_ptr, vx_mem); + 2, color_dims, vx_color_type, 0, color_stride, _color_ptr, vx_mem); if (!_colors_vx) THROW("vxCreateTensorFromHandle for color tensor failed"); { vx_status s = vxGetStatus((vx_reference)_colors_vx); @@ -141,6 +195,7 @@ void EraseNode::init(std::vector anchor, std::vector prefix(static_cast(_batch_size) + 1, 0); for (int i = 0; i < _batch_size; ++i) prefix[i + 1] = prefix[i] + _num_boxes_vec[i]; _total_boxes = static_cast(prefix[_batch_size]); + std::cerr << "Total Boxes " << _total_boxes << "\n"; auto channels = _inputs[0]->info().get_channels(); _fill_values_vec.resize(static_cast(_total_boxes) * channels); @@ -170,19 +225,9 @@ void EraseNode::init(std::vector anchor, dst += count; } } - else if (fill_sz == static_cast(_batch_size) * channels) { - // Per-sample per-channel pattern replicated across that sample’s boxes - float* dst = _fill_values_vec.data(); - const float* src = _fill_values.data(); - for (int i = 0; i < _batch_size; ++i) { - for (int b = 0; b < _num_boxes_vec[i]; ++b) { - std::copy_n(src + i * channels, channels, dst); - dst += channels; - } - } - } else if (num_boxes.size() == 1 && fill_sz == static_cast(num_boxes[0]) * channels) { + std::cerr << "Comes over here-----\n"; // Single-sample per-box per-channel replicated across batch. // All samples must have the same nb equal to num_boxes[0]. const int nb_single = num_boxes[0]; @@ -199,6 +244,17 @@ void EraseNode::init(std::vector anchor, // Fully specified flattened values std::copy(_fill_values.begin(), _fill_values.end(), _fill_values_vec.begin()); } + else if (fill_sz == static_cast(_batch_size) * channels) { + // Per-sample per-channel pattern replicated across that sample’s boxes + float* dst = _fill_values_vec.data(); + const float* src = _fill_values.data(); + for (int i = 0; i < _batch_size; ++i) { + for (int b = 0; b < _num_boxes_vec[i]; ++b) { + std::copy_n(src + i * channels, channels, dst); + dst += channels; + } + } + } else { THROW("Invalid number of values passed for fill value"); } From 6f4a6f5334669b6020bb84f07f1eed258830e1a8 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 5 Dec 2025 05:36:14 -0600 Subject: [PATCH 35/77] Fix Erase color tensor --- .../filter_augmentations/node_erase.cpp | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index d00fc41ba..5b41859d0 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -206,6 +206,21 @@ void EraseNode::init(std::vector anchor, // One scalar for everything std::fill(_fill_values_vec.begin(), _fill_values_vec.end(), _fill_values[0]); } + else if (num_boxes.size() == 1 && + fill_sz == static_cast(num_boxes[0]) * channels) { + std::cerr << "Comes over here-----\n"; + // Single-sample per-box per-channel replicated across batch. + // All samples must have the same nb equal to num_boxes[0]. + const int nb_single = num_boxes[0]; + float* dst = _fill_values_vec.data(); + for (int i = 0; i < _batch_size; ++i) { + if (_num_boxes_vec[i] != nb_single) + THROW("num_boxes mismatch across samples for single-sample fill pattern"); + const float* src = _fill_values.data(); + std::copy_n(src, static_cast(nb_single) * channels, dst); + dst += static_cast(nb_single) * channels; + } + } else if (fill_sz == static_cast(channels)) { // Per-channel pattern replicated to each box float* dst = _fill_values_vec.data(); @@ -225,21 +240,6 @@ void EraseNode::init(std::vector anchor, dst += count; } } - else if (num_boxes.size() == 1 && - fill_sz == static_cast(num_boxes[0]) * channels) { - std::cerr << "Comes over here-----\n"; - // Single-sample per-box per-channel replicated across batch. - // All samples must have the same nb equal to num_boxes[0]. - const int nb_single = num_boxes[0]; - float* dst = _fill_values_vec.data(); - for (int i = 0; i < _batch_size; ++i) { - if (_num_boxes_vec[i] != nb_single) - THROW("num_boxes mismatch across samples for single-sample fill pattern"); - const float* src = _fill_values.data(); - std::copy_n(src, static_cast(nb_single) * channels, dst); - dst += static_cast(nb_single) * channels; - } - } else if (fill_sz == static_cast(_total_boxes) * channels) { // Fully specified flattened values std::copy(_fill_values.begin(), _fill_values.end(), _fill_values_vec.begin()); From b0b47baedf4bc78e25a12281e8019f0be9c466f9 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 5 Dec 2025 05:37:38 -0600 Subject: [PATCH 36/77] Add test cases for new augmentations --- tests/cpp_api/unit_tests/testAllScripts.sh | 14 ++++++++++++++ tests/cpp_api/unit_tests/unit_tests.cpp | 19 +++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/tests/cpp_api/unit_tests/testAllScripts.sh b/tests/cpp_api/unit_tests/testAllScripts.sh index ad2b3ac1d..1350af905 100755 --- a/tests/cpp_api/unit_tests/testAllScripts.sh +++ b/tests/cpp_api/unit_tests/testAllScripts.sh @@ -230,6 +230,20 @@ do ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianFilterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 70 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianFilter_${rgb_name[$rgb]}_${device_name}" $width $height 71 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Magnitude_${rgb_name[$rgb]}_${device_name}" $width $height 74 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Phase_${rgb_name[$rgb]}_${device_name}" $width $height 75 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Threshold_${rgb_name[$rgb]}_${device_name}" $width $height 76 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}WarpPerspective_${rgb_name[$rgb]}_${device_name}" $width $height 77 $device $rgb 1 $display + + ./unit_tests 2 "$coco_detection_path" "${output_path}Remap_${rgb_name[$rgb]}_${device_name}" $width $height 78 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}CropAndPatch_${rgb_name[$rgb]}_${device_name}" $width $height 79 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Ricap_${rgb_name[$rgb]}_${device_name}" $width $height 80 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}BitwiseAnd_${rgb_name[$rgb]}_${device_name}" $width $height 81 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}BitwiseOr_${rgb_name[$rgb]}_${device_name}" $width $height 82 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}BitwiseXor_${rgb_name[$rgb]}_${device_name}" $width $height 83 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}BitwiseNot_${rgb_name[$rgb]}_${device_name}" $width $height 84 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Erase_${rgb_name[$rgb]}_${device_name}" $width $height 85 $device $rgb 1 $display + # to_tensor coverage tests for ((memcpy_backend=0;memcpy_backend<=1;memcpy_backend++)) do diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 63360d3eb..47f96074c 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -1001,7 +1001,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, case 79: { std::cout << "Running rocalCropAndPatch" << std::endl; // Create a simple second input (e.g., rotated version) - RocalTensor input2 = rocalRotate(handle, input, false); + RocalTensor input2 = rocalRotateFixed(handle, input, 45, false); // Define XYWH ROIs (replicated across batch if size==4) // dst_roi: place the patch at top-left corner with size WxH reduced int roi_w = std::max(1, width / 4); @@ -1018,7 +1018,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, case 80: { std::cout << "Running rocalRicap" << std::endl; // Permutation for quadrants [q0,q1,q2,q3]; replicate across batch if size==4 - std::vector permutation = {0, 1, 1, 0}; + std::vector permutation = {0, 1, 1, 0, 1, 0, 0, 1}; // Define 4 XYWH ROIs covering image quadrants; replicate across batch if size==16 int q_w = std::max(1, width / 2); int q_h = std::max(1, height / 2); @@ -1033,21 +1033,21 @@ int test(int test_case, int reader_type, const char *path, const char *outName, case 81: { std::cout << "Running rocalBitwiseOps AND" << std::endl; // Create second input tensor (rotate input to get variation) - RocalTensor input2 = rocalRotate(handle, input, false); + RocalTensor input2 = rocalRotateFixed(handle, input, 45, false); output = rocalBitwiseOps(handle, input, input2, true, RocalBitwiseOp::ROCAL_BITWISE_AND, output_tensor_layout, output_tensor_dtype); } break; case 82: { std::cout << "Running rocalBitwiseOps OR" << std::endl; - RocalTensor input2 = rocalRotate(handle, input, false); + RocalTensor input2 = rocalRotateFixed(handle, input, 45, false); output = rocalBitwiseOps(handle, input, input2, true, RocalBitwiseOp::ROCAL_BITWISE_OR, output_tensor_layout, output_tensor_dtype); } break; case 83: { std::cout << "Running rocalBitwiseOps XOR" << std::endl; - RocalTensor input2 = rocalRotate(handle, input, false); + RocalTensor input2 = rocalRotateFixed(handle, input, 45, false); output = rocalBitwiseOps(handle, input, input2, true, RocalBitwiseOp::ROCAL_BITWISE_XOR, output_tensor_layout, output_tensor_dtype); @@ -1083,7 +1083,12 @@ int test(int test_case, int reader_type, const char *path, const char *outName, }; // Single fill value replicated for all boxes and channels - std::vector fill_value = {0.0f}; + std::vector fill_value; + if (rgb) { + fill_value = {0.0f, 0.0f, 240.0f, 0.0f, 60.0f, 0.0f}; + } else { + fill_value = {120.0f, 60.0f}; + } // Execute vector-based erase output = rocalErase(handle, input, true, @@ -1136,6 +1141,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, return -1; } int image_name_length[input_batch_size]; + /* switch (pipeline_type) { case 1: { // classification pipeline RocalTensorList labels = rocalGetImageLabels(handle); @@ -1316,6 +1322,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, return -1; } } + */ auto last_colot_temp = rocalGetIntValue(color_temp_adj); rocalUpdateIntParameter(last_colot_temp + 1, color_temp_adj); From 32af90cac50db34153ae7f6b4e61cefa39a9442c Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 12 Dec 2025 01:44:38 -0600 Subject: [PATCH 37/77] Add NonLinearBlend test cases Avoid running Grayscale for ColorCast --- tests/cpp_api/unit_tests/testAllScripts.sh | 3 ++- tests/cpp_api/unit_tests/unit_tests.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/cpp_api/unit_tests/testAllScripts.sh b/tests/cpp_api/unit_tests/testAllScripts.sh index ad2b3ac1d..2299a536c 100755 --- a/tests/cpp_api/unit_tests/testAllScripts.sh +++ b/tests/cpp_api/unit_tests/testAllScripts.sh @@ -225,7 +225,8 @@ do ./unit_tests 2 "$coco_detection_path" "${output_path}ColorCastRandom_${rgb_name[$rgb]}_${device_name}" $width $height 64 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}ColorCast_${rgb_name[$rgb]}_${device_name}" $width $height 65 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}GridMask_${rgb_name[$rgb]}_${device_name}" $width $height 66 $device $rgb 1 $display - # ./unit_tests 2 "$coco_detection_path" "${output_path}NonLinearBlend_${rgb_name[$rgb]}_${device_name}" $width $height 66 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}NonLinearBlendRandom_${rgb_name[$rgb]}_${device_name}" $width $height 67 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}NonLinearBlend_${rgb_name[$rgb]}_${device_name}" $width $height 68 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}MedianFilter_${rgb_name[$rgb]}_${device_name}" $width $height 69 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianFilterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 70 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianFilter_${rgb_name[$rgb]}_${device_name}" $width $height 71 $device $rgb 1 $display diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index d9777f761..be7f95932 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -597,7 +597,8 @@ int test(int test_case, int reader_type, const char *path, const char *outName, // RocalTensor input = rocalResize(handle, decoded_output, resize_w, resize_h, false); // uncomment when processing images of different size RocalTensor output; - if ((test_case == 48 || test_case == 49 || test_case == 50 || test_case == 21 || test_case == 22 || test_case == 24 || test_case == 16 || test_case == 43 || reader_type == 13 || reader_type == 21 || reader_type == 27 || reader_type == 28) && rgb == 0) { + if ((test_case == 48 || test_case == 49 || test_case == 50 || test_case == 21 || test_case == 22 || test_case == 24 || test_case == 16 || test_case == 43 || + reader_type == 13 || reader_type == 21 || reader_type == 27 || reader_type == 28 || test_case == 64 || test_case == 65) && rgb == 0) { std::cout << "Not a valid option! Exiting!\n"; rocalRelease(handle); return -1; From d4e74edb3edf77c28ff64d3fe3124ad334642c91 Mon Sep 17 00:00:00 2001 From: Fiona Gladwin <121928245+fgladwin@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:16:07 +0530 Subject: [PATCH 38/77] Update rocAL/include/api/rocal_api_augmentation.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- rocAL/include/api/rocal_api_augmentation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 69cb37e86..64a1c85b0 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1486,7 +1486,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext cont RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); - /*! \brief Non-linear blend of two input images using per-sample stddev parameter. +/*! \brief Non-linear blend of two input images using per-sample stddev parameter. * \ingroup group_rocal_augmentations * \param [in] context Rocal context * \param [in] input1 Input1 Rocal tensor From 399b4509188e96075d808f614d6d44903e1e4a14 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 12 Dec 2025 04:54:38 -0600 Subject: [PATCH 39/77] Resolve PR comments --- .../color_augmentations/node_color_cast.cpp | 18 +---- rocAL_pybind/amd/rocal/fn.py | 75 +++++++++---------- 2 files changed, 41 insertions(+), 52 deletions(-) diff --git a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp index 437b09b7f..f7e17e60a 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp @@ -39,13 +39,10 @@ static void fill_rgb_for_batch(std::vector &rgb_out, unsigned batch_size, // Copy per-sample triplets rgb_out = rgb_in; } else { - // Invalid size, default to zeros - for (unsigned i = 0; i < batch_size; ++i) { - unsigned base = i * 3; - rgb_out[base + 0] = 0.0f; - rgb_out[base + 1] = 0.0f; - rgb_out[base + 2] = 0.0f; - } + // Invalid size - fail fast instead of silently defaulting to zeros + THROW("ColorCast: Invalid RGB array size. Expected 3 (single triplet) or " + + std::to_string(batch_size * 3) + " (per-sample triplets), got " + + std::to_string(rgb_in.size())); } } } // namespace @@ -96,11 +93,4 @@ void ColorCastNode::init(float alpha, std::vector rgb) { void ColorCastNode::update_node() { _alpha.update_array(); - // Update the RGB array content if present - if (_rgb_vx_array) { - vx_status status = VX_SUCCESS; - status = vxCopyArrayRange(_rgb_vx_array, 0, _batch_size * 3, sizeof(vx_float32), _rgb.data(), VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); - if (status != 0) - THROW(" vxCopyArrayRange failed in update_node (ColorCast): " + TOSTR(status)) - } } diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 9aa078745..e0d0d6d33 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1283,7 +1283,7 @@ def log1p(*inputs, output_datatype = types.FLOAT): def color_cast(*inputs, alpha=1.0, rgb=[0.0, 0.0, 0.0], device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies color cast by blending a target RGB color with the input using alpha. - @param inputs the input image passed to the augmentation + @param inputs the input image passed to the augmentation @param alpha (float or FloatParam, default = 1.0) blending amount for the cast (0..1). If float, wrapped into a FloatParam. @param rgb (list of floats, default = [0.0, 0.0, 0.0]) target color to cast; can be a single triplet [r,g,b] or per-sample triplets with length batch*3 @param device (string, optional, default = None) Parameter unused for augmentation @@ -1302,15 +1302,15 @@ def grid_mask(*inputs, tile_width=16, grid_ratio=0.5, grid_angle=0.0, translate_ device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies GridMask effect by overlaying a grid of tiles with a masked ratio. - @param inputs the input image passed to the augmentation - @param tile_width (int, default = 16) width of each grid tile in pixels - @param grid_ratio (float, default = 0.5) ratio of masked area within a tile (0..1) - @param grid_angle (float, default = 0.0) angle of the grid in radians - @param translate_x (int, default = 0) translation offset in x for the grid origin - @param translate_y (int, default = 0) translation offset in y for the grid origin - @param device (string, optional) Parameter unused for augmentation - @param output_layout (int, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, default = types.UINT8) tensor dtype for the augmentation output + @param inputs the input image passed to the augmentation + @param tile_width (int, default = 16) width of each grid tile in pixels + @param grid_ratio (float, default = 0.5) ratio of masked area within a tile (0..1) + @param grid_angle (float, default = 0.0) angle of the grid in radians + @param translate_x (int, default = 0) translation offset in x for the grid origin + @param translate_y (int, default = 0) translation offset in y for the grid origin + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output @return Image with grid mask effect applied """ @@ -1331,12 +1331,12 @@ def grid_mask(*inputs, tile_width=16, grid_ratio=0.5, grid_angle=0.0, translate_ def median_filter(*inputs, kernel_size=3, border_type=0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies median filter to images. - @param inputs the input image passed to the augmentation - @param kernel_size (int, default = 3) median filter kernel size (pixels), typically odd: 3,5,7 - @param border_type (int, default = 0) border handling policy (implementation specific) - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + @param inputs the input image passed to the augmentation + @param kernel_size (int, default = 3) median filter kernel size (pixels), typically odd: 3,5,7 + @param border_type (int, default = 0) border handling policy (implementation specific) + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output @return Image after median filtering """ @@ -1355,12 +1355,12 @@ def median_filter(*inputs, kernel_size=3, border_type=0, device=None, output_lay def gaussian_filter(*inputs, stddev=None, kernel_size=3, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies gaussian filter to images with per-sample stddev parameter. - @param inputs the input image passed to the augmentation - @param stddev (float or FloatParam, optional, default = None) per-sample standard deviation parameter; if float, wrapped into a FloatParam - @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + @param inputs the input image passed to the augmentation + @param stddev (float or FloatParam, optional, default = None) per-sample standard deviation parameter; if float, wrapped into a FloatParam + @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output @return Image after gaussian filtering """ @@ -1380,12 +1380,12 @@ def gaussian_filter(*inputs, stddev=None, kernel_size=3, device=None, output_lay def gaussian_filter_fixed(*inputs, stddev=1.0, kernel_size=3, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies gaussian filter to images with fixed stddev. - @param inputs the input image passed to the augmentation - @param stddev (float, default = 1.0) fixed standard deviation value - @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + @param inputs the input image passed to the augmentation + @param stddev (float, default = 1.0) fixed standard deviation value + @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output @return Image after gaussian filtering with fixed stddev """ @@ -1404,10 +1404,10 @@ def non_linear_blend(*inputs, stddev=None, device=None, output_layout=types.NHWC """!Non-linear blend of two input images using per-sample stddev parameter. @param inputs list containing two input images - @param stddev (float, optional, default = None) standard deviation parameter controlling non-linear blend - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + @param stddev (float, optional, default = None) standard deviation parameter controlling non-linear blend + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output @return non-linearly blended image """ @@ -1420,11 +1420,11 @@ def non_linear_blend(*inputs, stddev=None, device=None, output_layout=types.NHWC def non_linear_blend_fixed(*inputs, stddev=0.2, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Non-linear blend of two input images using a fixed stddev parameter. - @param inputs list containing two input images - @param stddev (float, default = 0.2) fixed standard deviation parameter controlling non-linear blend - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + @param inputs list containing two input images + @param stddev (float, default = 0.2) fixed standard deviation parameter controlling non-linear blend + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output @return non-linearly blended image """ @@ -1432,4 +1432,3 @@ def non_linear_blend_fixed(*inputs, stddev=0.2, device=None, output_layout=types "output_layout": output_layout, "output_dtype": output_dtype} output_image = b.nonLinearBlendFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (output_image) - From 60db6362a1f57f57d6f770779104ad0c7a3ccee7 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 12 Dec 2025 05:34:13 -0600 Subject: [PATCH 40/77] Add suitable python test cases and remove unwanted ones --- rocAL_pybind/amd/rocal/fn.py | 42 +---------------- rocAL_pybind/rocal_pybind.cpp | 8 +--- tests/python_api/unit_test.py | 84 ++++++++++++++++------------------ tests/python_api/unit_tests.sh | 6 +++ 4 files changed, 47 insertions(+), 93 deletions(-) diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index e0d0d6d33..8c749b3e7 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1283,7 +1283,7 @@ def log1p(*inputs, output_datatype = types.FLOAT): def color_cast(*inputs, alpha=1.0, rgb=[0.0, 0.0, 0.0], device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies color cast by blending a target RGB color with the input using alpha. - @param inputs the input image passed to the augmentation + @param inputs the input image passed to the augmentation @param alpha (float or FloatParam, default = 1.0) blending amount for the cast (0..1). If float, wrapped into a FloatParam. @param rgb (list of floats, default = [0.0, 0.0, 0.0]) target color to cast; can be a single triplet [r,g,b] or per-sample triplets with length batch*3 @param device (string, optional, default = None) Parameter unused for augmentation @@ -1376,30 +1376,6 @@ def gaussian_filter(*inputs, stddev=None, kernel_size=3, device=None, output_lay output_image = b.gaussianFilter(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (output_image) - -def gaussian_filter_fixed(*inputs, stddev=1.0, kernel_size=3, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): - """!Applies gaussian filter to images with fixed stddev. - - @param inputs the input image passed to the augmentation - @param stddev (float, default = 1.0) fixed standard deviation value - @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output - - @return Image after gaussian filtering with fixed stddev - """ - kwargs_pybind = { - "input_image": inputs[0], - "stddev": stddev, - "kernel_size": kernel_size, - "is_output": False, - "output_layout": output_layout, - "output_dtype": output_dtype - } - output_image = b.gaussianFilterFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (output_image) - def non_linear_blend(*inputs, stddev=None, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Non-linear blend of two input images using per-sample stddev parameter. @@ -1416,19 +1392,3 @@ def non_linear_blend(*inputs, stddev=None, device=None, output_layout=types.NHWC "output_layout": output_layout, "output_dtype": output_dtype} output_image = b.nonLinearBlend(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (output_image) - -def non_linear_blend_fixed(*inputs, stddev=0.2, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): - """!Non-linear blend of two input images using a fixed stddev parameter. - - @param inputs list containing two input images - @param stddev (float, default = 0.2) fixed standard deviation parameter controlling non-linear blend - @param device (string, optional, default = None) Parameter unused for augmentation - @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output - @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output - - @return non-linearly blended image - """ - kwargs_pybind = {"input_image0": inputs[0], "input_image1": inputs[1], "stddev": stddev, "is_output": False, - "output_layout": output_layout, "output_dtype": output_dtype} - output_image = b.nonLinearBlendFixed(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (output_image) diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index ca834381b..033bca449 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1164,22 +1164,16 @@ py::class_(m, "rocalListOfTensorList") m.def("transpose", &rocalTranspose, py::return_value_policy::reference); m.def("log1p", &rocalLog1p, - py::return_value_policy::reference); - m.def("colorCast", &rocalColorCast, py::return_value_policy::reference); - m.def("colorCastFixed", &rocalColorCastFixed, + m.def("colorCast", &rocalColorCast, py::return_value_policy::reference); m.def("gridMask", &rocalGridMask, py::return_value_policy::reference); m.def("gaussianFilter", &rocalGaussianFilter, py::return_value_policy::reference); - m.def("gaussianFilterFixed", &rocalGaussianFilterFixed, - py::return_value_policy::reference); m.def("medianFilter", &rocalMedianFilter, py::return_value_policy::reference); m.def("nonLinearBlend", &rocalNonLinearBlend, py::return_value_policy::reference); - m.def("nonLinearBlendFixed", &rocalNonLinearBlendFixed, - py::return_value_policy::reference); } } // namespace rocal diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 072aa7648..a1e21d5fa 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -325,24 +325,6 @@ def main(): window_size=5, output_layout=tensor_layout, output_dtype=tensor_dtype) - elif augmentation_name == "median_filter": - output = fn.median_filter(images, - kernel_size=3, - border_type=0, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - elif augmentation_name == "gaussian_filter": - output = fn.gaussian_filter(images, - stddev=1.0, - kernel_size=3, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - elif augmentation_name == "gaussian_filter_fixed": - output = fn.gaussian_filter_fixed(images, - stddev=1.0, - kernel_size=3, - output_layout=tensor_layout, - output_dtype=tensor_dtype) elif augmentation_name == "warp_affine": output = fn.warp_affine(images, dest_height=416, dest_width=416, matrix=[1.0, 1.0, 0.5, 0.5, 7.0, 7.0], output_layout=tensor_layout, output_dtype=tensor_dtype, interpolation_type=types.LINEAR_INTERPOLATION) @@ -389,15 +371,6 @@ def main(): output = fn.pixelate(images, output_layout=tensor_layout, output_dtype=tensor_dtype) - elif augmentation_name == "grid_mask": - output = fn.grid_mask(images, - tile_width=32, - grid_ratio=0.5, - grid_angle=0.0, - translate_x=0, - translate_y=0, - output_layout=tensor_layout, - output_dtype=tensor_dtype) elif augmentation_name == "exposure": output = fn.exposure(images, exposure=1.0, @@ -421,12 +394,6 @@ def main(): saturation=0.25, output_layout=tensor_layout, output_dtype=tensor_dtype) - elif augmentation_name == "color_cast": - output = fn.color_cast(images, - alpha=0.5, - rgb=[0.25, 0.10, 0.00], - output_layout=tensor_layout, - output_dtype=tensor_dtype) elif augmentation_name == "crop": output = fn.crop(images, crop=(3, 224, 224), @@ -501,18 +468,6 @@ def main(): ratio=0.5, output_layout=tensor_layout, output_dtype=tensor_dtype) - elif augmentation_name == "non_linear_blend": - output1 = fn.rotate(images, - angle=45.0, - dest_width=416, - dest_height=416, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - output = fn.non_linear_blend(images, - output1, - stddev=0.2, - output_layout=tensor_layout, - output_dtype=tensor_dtype) elif augmentation_name == "resize_crop": output = fn.resize_crop(images, resize_width=416, @@ -538,6 +493,45 @@ def main(): output_dtype=tensor_dtype) num_classes = len(next(os.walk(data_path))[1]) labels_onehot = fn.one_hot(labels, num_classes=num_classes) + elif augmentation_name == "color_cast": + output = fn.color_cast(images, + alpha=0.5, + rgb=[12.0, 0.0, 100.0], + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "grid_mask": + output = fn.grid_mask(images, + tile_width=40, + grid_ratio=0.6, + grid_angle=0.5, + translate_x=0, + translate_y=0, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "non_linear_blend": + output1 = fn.rotate(images, + angle=45.0, + dest_width=416, + dest_height=416, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + output = fn.non_linear_blend(images, + output1, + stddev=50.0, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "median_filter": + output = fn.median_filter(images, + kernel_size=3, + border_type=0, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "gaussian_filter": + output = fn.gaussian_filter(images, + stddev=5.0, + kernel_size=3, + output_layout=tensor_layout, + output_dtype=tensor_dtype) if output_set == 0: pipe.set_outputs(output) diff --git a/tests/python_api/unit_tests.sh b/tests/python_api/unit_tests.sh index a160dd7fb..7dc13159b 100755 --- a/tests/python_api/unit_tests.sh +++ b/tests/python_api/unit_tests.sh @@ -165,6 +165,12 @@ do python"$ver" unit_test.py --image-dataset-path "$caffe2_detection_path" --reader-type "caffe2_detection" --augmentation-name resize --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --interpolation-type 5 --scaling-mode 0 --$backend_arg -f "${output_path}Resize_${rgb_name[$rgb]}_${device_name}_triangular_default_caffe2Detection" python"$ver" unit_test.py --image-dataset-path "$mxnet_path" --reader-type "mxnet" --augmentation-name resize --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --interpolation-type 4 --scaling-mode 0 --$backend_arg -f "${output_path}Resize_${rgb_name[$rgb]}_${device_name}_gaussian_default_mxnet" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name color_cast --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}ColorCast_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name grid_mask --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}GridMask_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name median_filter --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}MedianFilter_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name gaussian_filter --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}GaussianFilter_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name non_linear_blend --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}NonLinearBlend_${rgb_name[$rgb]}_${device_name}" + # Special Case - One Hot Encoded Labels python"$ver" unit_test.py --image-dataset-path "$one_hot_data_path" --augmentation-name one_hot --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}OneHot_${rgb_name[$rgb]}_${device_name}" From a791e9b4580a5bef03128929d4e8af44d835b5f6 Mon Sep 17 00:00:00 2001 From: Fiona-MCW <70996026+fiona-gladwin@users.noreply.github.com> Date: Fri, 12 Dec 2025 17:05:03 +0530 Subject: [PATCH 41/77] Minor changes --- rocAL/include/api/rocal_api_augmentation.h | 2 +- .../color_augmentations/node_non_linear_blend.h | 2 +- .../color_augmentations/node_color_cast.cpp | 2 -- .../filter_augmentations/node_median_filter.cpp | 15 ++++++--------- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 64a1c85b0..ec6c26294 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1438,7 +1438,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGridMask(RocalContext context, RocalT * \param [in] input Input Rocal tensor * \param [in] is_output Is the output tensor part of the graph output * \param [in] kernel_size Median filter kernel size (pixels) - * \param [in] border_type Border handling policy (implementation specific) + * \param [in] border_type Border handling policy * \param [in] output_layout the layout of the output tensor * \param [in] output_datatype the data type of the output tensor * \return RocalTensor diff --git a/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h b/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h index a5c397897..e0f758790 100644 --- a/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h +++ b/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h @@ -30,7 +30,7 @@ class NonLinearBlendNode : public Node { explicit NonLinearBlendNode(const std::vector& inputs, const std::vector& outputs); NonLinearBlendNode() = delete; - // Fixed vs dynamic stddev init + // Fixed and dynamic stddev init void init(float stddev); void init(FloatParam* stddev); diff --git a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp index f7e17e60a..ff0a16725 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp @@ -24,7 +24,6 @@ THE SOFTWARE. #include "augmentations/color_augmentations/node_color_cast.h" #include "pipeline/exception.h" -namespace { static void fill_rgb_for_batch(std::vector &rgb_out, unsigned batch_size, const std::vector &rgb_in) { rgb_out.resize(batch_size * 3); if (rgb_in.size() == 3) { @@ -45,7 +44,6 @@ static void fill_rgb_for_batch(std::vector &rgb_out, unsigned batch_size, std::to_string(rgb_in.size())); } } -} // namespace ColorCastNode::ColorCastNode(const std::vector &inputs, const std::vector &outputs) : Node(inputs, outputs), diff --git a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp index 119f67609..1b6fc001d 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp @@ -23,11 +23,6 @@ THE SOFTWARE. MedianFilterNode::MedianFilterNode(const std::vector& inputs, const std::vector& outputs) : Node(inputs, outputs) {} -void MedianFilterNode::init(int kernel_size, int border_type) { - _kernel_size = kernel_size; - _border_type = border_type; -} - void MedianFilterNode::create_node() { if (_node) return; @@ -41,8 +36,7 @@ void MedianFilterNode::create_node() { vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &_kernel_size); - vx_int32 border_i32 = static_cast(_border_type); - vx_scalar border_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &border_i32); + vx_scalar border_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &_border_type); _node = vxExtRppMedianFilter(_graph->get(), _inputs[0]->handle(), @@ -58,6 +52,9 @@ void MedianFilterNode::create_node() { THROW("Adding the median filter (vxExtRppMedianFilter) node failed: " + TOSTR(status)) } -void MedianFilterNode::update_node() { - // No dynamic per-sample parameters to update +void MedianFilterNode::init(int kernel_size, int border_type) { + _kernel_size = kernel_size; + _border_type = static_cast(border_type); } + +void MedianFilterNode::update_node() {} From 404acc2a8180d1f66a5f0d59a4c9f6070fead000 Mon Sep 17 00:00:00 2001 From: Sundar Rajan Vaithiyanathan Date: Fri, 12 Dec 2025 20:40:04 +0530 Subject: [PATCH 42/77] Resolve copilot comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../augmentations/color_augmentations/node_non_linear_blend.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h b/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h index e0f758790..e9890e72c 100644 --- a/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h +++ b/rocAL/include/augmentations/color_augmentations/node_non_linear_blend.h @@ -40,6 +40,7 @@ class NonLinearBlendNode : public Node { private: ParameterVX _stddev; - // Conservative default range; actual values are user-controlled + // Suggested default range for stddev; actual values are fully user-controlled and not restricted to this range. + // User-provided values outside this range are accepted without clamping or rejection. constexpr static float STDDEV_RANGE[2] = {0.05f, 0.50f}; }; From fad74489043007e3b8602575de0336f4085275f9 Mon Sep 17 00:00:00 2001 From: Sundar Rajan Vaithiyanathan Date: Fri, 12 Dec 2025 20:42:35 +0530 Subject: [PATCH 43/77] Resolve copilot comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../augmentations/color_augmentations/node_color_cast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp index ff0a16725..cfd8eaef4 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp @@ -61,7 +61,7 @@ void ColorCastNode::create_node() { _rgb_vx_array = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, _batch_size * 3); status |= vxAddArrayItems(_rgb_vx_array, _rgb.size(), _rgb.data(), sizeof(vx_float32)); if (status != 0) - THROW(" vxAddArrayItems failed in the ColorCast (vxExtRppColorCast) node: " + TOSTR(status) + " " + TOSTR(status)) + THROW(" vxAddArrayItems failed in the ColorCast (vxExtRppColorCast) node: " + TOSTR(status)) // Layouts & ROI type int input_layout = static_cast(_inputs[0]->info().layout()); From 0a44fdfe80e4523b546f64d131d1b3bb8edf6748 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Mon, 15 Dec 2025 04:48:24 -0600 Subject: [PATCH 44/77] Minor changes --- rocAL/include/api/rocal_api_augmentation.h | 67 +++---- rocAL/source/api/rocal_api_augmentation.cpp | 190 ++++++++++---------- 2 files changed, 125 insertions(+), 132 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 78b3484d3..e6670dd12 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1432,39 +1432,6 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGridMask(RocalContext context, RocalT RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); -/*! \brief Non-linear blend of two input images using per-sample stddev parameter. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input1 Input1 Rocal tensor - * \param [in] input2 Input2 Rocal tensor - * \param [in] is_output is the output tensor part of the graph output - * \param [in] stddev Rocal parameter defining the per-sample stddev for non-linear blend - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlend(RocalContext context, RocalTensor input1, RocalTensor input2, - bool is_output, - RocalFloatParam stddev = NULL, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - -/*! \brief Non-linear blend of two input images using a fixed stddev parameter. - * \ingroup group_rocal_augmentations - * \param [in] context Rocal context - * \param [in] input1 Input1 Rocal tensor - * \param [in] input2 Input2 Rocal tensor - * \param [in] stddev fixed stddev for non-linear blend - * \param [in] is_output is the output tensor part of the graph output - * \param [in] output_layout the layout of the output tensor - * \param [in] output_datatype the data type of the output tensor - * \return RocalTensor - */ -extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlendFixed(RocalContext context, RocalTensor input1, RocalTensor input2, - float stddev, bool is_output, - RocalTensorLayout output_layout = ROCAL_NONE, - RocalTensorOutputType output_datatype = ROCAL_UINT8); - /*! \brief Applies median filter to images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context @@ -1519,6 +1486,40 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext cont RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Non-linear blend of two input images using per-sample stddev parameter. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 Input1 Rocal tensor + * \param [in] input2 Input2 Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] stddev Rocal parameter defining the per-sample stddev for non-linear blend + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlend(RocalContext context, RocalTensor input1, RocalTensor input2, + bool is_output, + RocalFloatParam stddev = NULL, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Non-linear blend of two input images using a fixed stddev parameter. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input1 Input1 Rocal tensor + * \param [in] input2 Input2 Rocal tensor + * \param [in] stddev fixed stddev for non-linear blend + * \param [in] is_output is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalNonLinearBlendFixed(RocalContext context, RocalTensor input1, RocalTensor input2, + float stddev, bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + + /*! \brief Applies thresholding to images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index c39461744..d29f84597 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2495,6 +2495,97 @@ rocalColorCastFixed( return output; } +RocalTensor ROCAL_API_CALL +rocalMedianFilter( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + unsigned kernel_size, + int border_type, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(kernel_size, border_type); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalGaussianFilter( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_stddev, + unsigned kernel_size, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto stddev = static_cast(p_stddev); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(stddev, kernel_size); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalGaussianFilterFixed( + RocalContext p_context, + RocalTensor p_input, + float stddev, + unsigned kernel_size, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_dtype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph + ->add_node({input}, {output}) + ->init(stddev, kernel_size); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalGridMask( RocalContext p_context, @@ -2589,7 +2680,6 @@ rocalNonLinearBlendFixed( return output; } -// Dilate RocalTensor ROCAL_API_CALL rocalDilate(RocalContext p_context, RocalTensor p_input, @@ -2616,7 +2706,6 @@ rocalDilate(RocalContext p_context, return output; } -// Erode RocalTensor ROCAL_API_CALL rocalErode(RocalContext p_context, RocalTensor p_input, @@ -2643,7 +2732,6 @@ rocalErode(RocalContext p_context, return output; } -// Magnitude (two inputs) RocalTensor ROCAL_API_CALL rocalMagnitude(RocalContext p_context, RocalTensor p_input1, @@ -2673,7 +2761,6 @@ rocalMagnitude(RocalContext p_context, return output; } -// Phase (two inputs) RocalTensor ROCAL_API_CALL rocalPhase(RocalContext p_context, RocalTensor p_input1, @@ -2703,101 +2790,6 @@ rocalPhase(RocalContext p_context, return output; } -// New: Median Filter -RocalTensor ROCAL_API_CALL -rocalMedianFilter( - RocalContext p_context, - RocalTensor p_input, - bool is_output, - unsigned kernel_size, - int border_type, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(kernel_size, border_type); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -// New: Gaussian Filter (dynamic stddev) -RocalTensor ROCAL_API_CALL -rocalGaussianFilter( - RocalContext p_context, - RocalTensor p_input, - bool is_output, - RocalFloatParam p_stddev, - unsigned kernel_size, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - auto stddev = static_cast(p_stddev); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(stddev, kernel_size); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -// New: Gaussian Filter (fixed stddev) -RocalTensor ROCAL_API_CALL -rocalGaussianFilterFixed( - RocalContext p_context, - RocalTensor p_input, - float stddev, - unsigned kernel_size, - bool is_output, - RocalTensorLayout output_layout, - RocalTensorOutputType output_datatype) { - Tensor* output = nullptr; - ROCAL_INVALID_CONTEXT_ERR(p_context, output); - ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); - try { - RocalTensorlayout op_tensor_layout = static_cast(output_layout); - RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); - TensorInfo output_info = input->info(); - output_info.set_tensor_layout(op_tensor_layout); - output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - context->master_graph - ->add_node({input}, {output}) - ->init(stddev, kernel_size); - } catch (const std::exception& e) { - ROCAL_PRINT_EXCEPTION(context, e); - } - return output; -} - -// New: Threshold (dynamic min/max) RocalTensor ROCAL_API_CALL rocalThreshold( RocalContext p_context, From 21c5101762e42ad403e648f5b28d468566ea9d34 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 16 Dec 2025 00:49:09 -0600 Subject: [PATCH 45/77] Minor code clean up --- .../node_warp_perspective.h | 3 -- .../filter_augmentations/node_dilate.cpp | 10 ++--- .../filter_augmentations/node_erode.cpp | 10 ++--- .../filter_augmentations/node_magnitude.cpp | 4 +- .../filter_augmentations/node_phase.cpp | 4 +- .../node_warp_perspective.cpp | 37 +++++++------------ 6 files changed, 23 insertions(+), 45 deletions(-) diff --git a/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h b/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h index a740f3be0..830dd1ce9 100644 --- a/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h +++ b/rocAL/include/augmentations/geometry_augmentations/node_warp_perspective.h @@ -40,8 +40,5 @@ class WarpPerspectiveNode : public Node { private: std::vector _perspective; // length 9 or 9 * batch_size - vx_array _perspective_array_vx = nullptr; int _interpolation_type = 0; - - void build_perspective_array(); // replicates per-batch if needed and creates vx_array }; diff --git a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp index b7c720ba0..7ae6f946e 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp @@ -24,10 +24,6 @@ THE SOFTWARE. DilateNode::DilateNode(const std::vector& inputs, const std::vector& outputs) : Node(inputs, outputs) {} -void DilateNode::init(unsigned kernel_size) { - _kernel_size = kernel_size; -} - void DilateNode::create_node() { if (_node) return; @@ -55,6 +51,8 @@ void DilateNode::create_node() { THROW("Adding the dilate (vxExtRppDilate) node failed: " + TOSTR(status)) } -void DilateNode::update_node() { - // No dynamic per-sample parameters to update +void DilateNode::init(unsigned kernel_size) { + _kernel_size = kernel_size; } + +void DilateNode::update_node() {} diff --git a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp index 85dcc7b0b..9b9c097d2 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp @@ -25,10 +25,6 @@ THE SOFTWARE. ErodeNode::ErodeNode(const std::vector& inputs, const std::vector& outputs) : Node(inputs, outputs) {} -void ErodeNode::init(unsigned kernel_size) { - _kernel_size = kernel_size; -} - void ErodeNode::create_node() { if (_node) return; @@ -56,6 +52,8 @@ void ErodeNode::create_node() { THROW("Adding the erode (vxExtRppErode) node failed: " + TOSTR(status)) } -void ErodeNode::update_node() { - // No dynamic per-sample parameters to update +void ErodeNode::init(unsigned kernel_size) { + _kernel_size = kernel_size; } + +void ErodeNode::update_node() {} diff --git a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp index ab19672a1..fdc401d5f 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp @@ -54,6 +54,4 @@ void MagnitudeNode::create_node() { THROW("Adding the magnitude (vxExtRppMagnitude) node failed: " + TOSTR(status)) } -void MagnitudeNode::update_node() { - // No dynamic per-sample parameters to update -} +void MagnitudeNode::update_node() {} diff --git a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp index 56dcaf7b9..006bf8c20 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp @@ -53,6 +53,4 @@ void PhaseNode::create_node() { THROW("Adding the phase (vxExtRppPhase) node failed: " + TOSTR(status)) } -void PhaseNode::update_node() { - // No dynamic per-sample parameters to update -} +void PhaseNode::update_node() {} diff --git a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp index 4ca52bfc2..ecf381cfe 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp @@ -30,16 +30,18 @@ WarpPerspectiveNode::WarpPerspectiveNode(const std::vector& inputs, con : Node(inputs, outputs) { } -void WarpPerspectiveNode::build_perspective_array() { - // Build per-sample perspective array of length 9 * batch_size. - // If a single 9-element matrix is provided, replicate across the batch. +void WarpPerspectiveNode::create_node() { + if (_node) + return; + + // Build and allocate perspective array const size_t expected_len = static_cast(_batch_size) * 9; std::vector data; data.resize(expected_len); if (_perspective.size() == 9) { - // Replicate across batch + // If a single 9-element matrix is provided, replicate across the batch. for (uint i = 0; i < _batch_size; ++i) { const size_t base = static_cast(i) * 9; for (int k = 0; k < 9; ++k) { @@ -55,48 +57,35 @@ void WarpPerspectiveNode::build_perspective_array() { // Create vx_array and populate it vx_status status; - _perspective_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, expected_len); - status = vxAddArrayItems(_perspective_array_vx, expected_len, data.data(), sizeof(vx_float32)); + vx_array perspective_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, expected_len); + status = vxAddArrayItems(perspective_array_vx, expected_len, data.data(), sizeof(vx_float32)); if (status != VX_SUCCESS) { THROW("WarpPerspective: vxAddArrayItems failed while creating perspective array: " + TOSTR(status)); } -} - -void WarpPerspectiveNode::create_node() { - if (_node) - return; - - // Build and allocate perspective array - build_perspective_array(); // Interpolation scalar - vx_scalar interpolation_vx = - vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &_interpolation_type); + vx_scalar interpolation_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &_interpolation_type); // Layout and ROI type scalars int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); - vx_scalar input_layout_vx = - vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); - vx_scalar output_layout_vx = - vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); - vx_scalar roi_type_vx = - vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); // Construct the RPP WarpPerspective node _node = vxExtRppWarpPerspective(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), - _perspective_array_vx, + perspective_array_vx, interpolation_vx, input_layout_vx, output_layout_vx, roi_type_vx); - vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { THROW("Adding the warp perspective (vxExtRppWarpPerspective) node failed: " + TOSTR(status)); } From 297a4768c283558f7d8e9f60b1152245c07ca006 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 16 Dec 2025 01:11:39 -0600 Subject: [PATCH 46/77] Add test cases for Dilate, erode, magnitude, phase and warp perspective --- rocAL/source/api/rocal_api_augmentation.cpp | 4 +- tests/cpp_api/unit_tests/testAllScripts.sh | 7 ++ tests/python_api/unit_test.py | 129 ++++++++------------ tests/python_api/unit_tests.sh | 7 ++ 4 files changed, 69 insertions(+), 78 deletions(-) diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index d29f84597..c0a906066 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2802,8 +2802,8 @@ rocalThreshold( Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); - auto context = static_cast(p_context); - auto input = static_cast(p_input); + auto context = static_cast(p_context); + auto input = static_cast(p_input); try { RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); diff --git a/tests/cpp_api/unit_tests/testAllScripts.sh b/tests/cpp_api/unit_tests/testAllScripts.sh index 2299a536c..b872a598f 100755 --- a/tests/cpp_api/unit_tests/testAllScripts.sh +++ b/tests/cpp_api/unit_tests/testAllScripts.sh @@ -231,6 +231,13 @@ do ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianFilterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 70 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianFilter_${rgb_name[$rgb]}_${device_name}" $width $height 71 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Dilate_${rgb_name[$rgb]}_${device_name}" $width $height 72 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Erode_${rgb_name[$rgb]}_${device_name}" $width $height 73 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Magnitude_${rgb_name[$rgb]}_${device_name}" $width $height 74 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Phase_${rgb_name[$rgb]}_${device_name}" $width $height 75 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}Threshold_${rgb_name[$rgb]}_${device_name}" $width $height 76 $device $rgb 1 $display + ./unit_tests 2 "$coco_detection_path" "${output_path}WarpPerspective_${rgb_name[$rgb]}_${device_name}" $width $height 77 $device $rgb 1 $display + # to_tensor coverage tests for ((memcpy_backend=0;memcpy_backend<=1;memcpy_backend++)) do diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 6f5cdd02b..3520e6983 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -325,66 +325,6 @@ def main(): window_size=5, output_layout=tensor_layout, output_dtype=tensor_dtype) - elif augmentation_name == "dilate": - # Morphological dilate; fallback to copy if bindings not available - try: - output = fn.dilate(images, - kernel_size=3, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - except Exception as e: - print("fn.dilate not available -- falling back to copy:", e) - output = fn.copy(images, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - elif augmentation_name == "erode": - # Morphological erode; fallback to copy if bindings not available - try: - output = fn.erode(images, - kernel_size=3, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - except Exception as e: - print("fn.erode not available -- falling back to copy:", e) - output = fn.copy(images, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - elif augmentation_name == "magnitude": - # Create a second tensor by rotating; then compute magnitude; fallback if not available - try: - images2 = fn.rotate(images, - angle=15.0, - dest_width=max_width if max_width else 416, - dest_height=max_height if max_height else 416, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - output = fn.magnitude(images, - images2, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - except Exception as e: - print("fn.magnitude not available -- falling back to copy:", e) - output = fn.copy(images, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - elif augmentation_name == "phase": - # Create a second tensor by rotating; then compute phase; fallback if not available - try: - images2 = fn.rotate(images, - angle=-15.0, - dest_width=max_width if max_width else 416, - dest_height=max_height if max_height else 416, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - output = fn.phase(images, - images2, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - except Exception as e: - print("fn.phase not available -- falling back to copy:", e) - output = fn.copy(images, - output_layout=tensor_layout, - output_dtype=tensor_dtype) elif augmentation_name == "gaussian_filter": output = fn.gaussian_filter(images, stddev=1.0, @@ -397,25 +337,9 @@ def main(): kernel_size=3, output_layout=tensor_layout, output_dtype=tensor_dtype) - elif augmentation_name == "threshold": - output = fn.threshold(images, - min=64.0, - max=192.0, - output_layout=tensor_layout, - output_dtype=tensor_dtype) elif augmentation_name == "warp_affine": output = fn.warp_affine(images, dest_height=416, dest_width=416, matrix=[1.0, 1.0, 0.5, 0.5, 7.0, 7.0], output_layout=tensor_layout, output_dtype=tensor_dtype, interpolation_type=types.LINEAR_INTERPOLATION) - elif augmentation_name == "warp_perspective": - output = fn.warp_perspective(images, - dest_height=416, - dest_width=416, - perspective=[1.0, 0.0, 0.0, - 0.0, 1.0, 0.0, - 0.001, 0.001, 1.0], - output_layout=tensor_layout, - output_dtype=tensor_dtype, - interpolation_type=types.LINEAR_INTERPOLATION) elif augmentation_name == "fish_eye": output = fn.fish_eye(images, output_layout=tensor_layout, @@ -620,6 +544,59 @@ def main(): kernel_size=3, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "dilate": + output = fn.dilate(images, + kernel_size=3, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "erode": + output = fn.erode(images, + kernel_size=3, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "magnitude": + images2 = fn.rotate(images, + angle=45.0, + dest_width=max_width if max_width else 416, + dest_height=max_height if max_height else 416, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + output = fn.magnitude(images, + images2, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "phase": + images2 = fn.rotate(images, + angle=45.0, + dest_width=max_width if max_width else 416, + dest_height=max_height if max_height else 416, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + output = fn.phase(images, + images2, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "threshold": + min_val = [30.0] + max_val = [100.0] + if color_format == types.RGB: + min_val = [30.0, 30.0, 30.0] + max_val = [100.0, 100.0, 100.0] + output = fn.threshold(images, + min=min_val, + max=max_val, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "warp_perspective": + output = fn.warp_perspective(images, + dest_height=416, + dest_width=416, + perspective=[0.93, 0.5, 0.0, + -0.5, 0.93, 0.0, + 0.005, 0.005, 1.0], + output_layout=tensor_layout, + output_dtype=tensor_dtype, + interpolation_type=types.LINEAR_INTERPOLATION) if output_set == 0: pipe.set_outputs(output) diff --git a/tests/python_api/unit_tests.sh b/tests/python_api/unit_tests.sh index 7dc13159b..93b7f25de 100755 --- a/tests/python_api/unit_tests.sh +++ b/tests/python_api/unit_tests.sh @@ -171,6 +171,13 @@ do python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name gaussian_filter --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}GaussianFilter_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name non_linear_blend --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}NonLinearBlend_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name dilate --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Dilate_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name erode --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Erode_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name magnitude --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Magnitude_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name phase --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Phase_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name threshold --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Threshold_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name warp_perspective --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}WarpPerspective_${rgb_name[$rgb]}_${device_name}" + # Special Case - One Hot Encoded Labels python"$ver" unit_test.py --image-dataset-path "$one_hot_data_path" --augmentation-name one_hot --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}OneHot_${rgb_name[$rgb]}_${device_name}" From 10583ad7b3d7f5151e5f5bf96de33fdbc50a58b1 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 16 Dec 2025 01:13:52 -0600 Subject: [PATCH 47/77] Minor fixes threshold --- .../augmentations/filter_augmentations/node_threshold.h | 2 +- .../augmentations/filter_augmentations/node_threshold.cpp | 5 +---- rocAL_pybind/amd/rocal/fn.py | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/rocAL/include/augmentations/filter_augmentations/node_threshold.h b/rocAL/include/augmentations/filter_augmentations/node_threshold.h index d443c49e6..3bba6e55d 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_threshold.h +++ b/rocAL/include/augmentations/filter_augmentations/node_threshold.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp index 50d6cf080..3b5a5bfbe 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -50,9 +50,6 @@ void ThresholdNode::create_node() { if (_node) return; - std::vector min_vec, max_vec; - - // Create per-sample arrays for min and max threshold values auto no_of_channels = _inputs[0]->info().get_channels(); auto array_size = _batch_size * no_of_channels; diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index fa99d57d1..836bfc057 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1409,9 +1409,9 @@ def threshold(*inputs, min=None, max=None, device=None, output_layout=types.NHWC max = b.createFloatParameter(max) if isinstance(max, float) else max kwargs_pybind = { "input_image": inputs[0], - "is_output": False, "min": min, "max": max, + "is_output": False, "output_layout": output_layout, "output_dtype": output_dtype } From 1723675b97db62e34c971f6a446e113aea943142 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 16 Dec 2025 01:20:10 -0600 Subject: [PATCH 48/77] Resolve copilot comments --- .../augmentations/filter_augmentations/node_threshold.cpp | 8 ++++---- tests/cpp_api/unit_tests/unit_tests.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp index 3b5a5bfbe..539f8a6ce 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp @@ -34,9 +34,9 @@ void fill_vector_with_threshold_values(std::vector& threshold_batch, size_t threshold_vec_size = threshold_batch.size(); if (threshold_values.size() == no_of_channels) { - for (int i = 0; i < threshold_vec_size; i+=no_of_channels) { - for (int c = 0; c < no_of_channels; c++) { - threshold_batch[i + c] = threshold_values[c]; + for (int batch_channel_idx = 0; batch_channel_idx < threshold_vec_size; batch_channel_idx += no_of_channels) { + for (int channel_idx = 0; channel_idx < no_of_channels; channel_idx++) { + threshold_batch[batch_channel_idx + channel_idx] = threshold_values[channel_idx]; } } } else if (threshold_values.size() == threshold_vec_size) { @@ -102,4 +102,4 @@ void ThresholdNode::init(std::vector& min_val, std::vector& max_va _max = max_val; } -void ThresholdNode::update_node() {} \ No newline at end of file +void ThresholdNode::update_node() {} diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index cac947913..084d418d6 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -960,7 +960,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, max_threshold = {100.0f, 100.0f, 100.0f}; } else { min_threshold = {30.0f}; - max_threshold = {100.0f}; + max_threshold = {100.0f}; } output = rocalThreshold(handle, input, min_threshold, max_threshold, true, output_tensor_layout, output_tensor_dtype); @@ -972,7 +972,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, 0.005f, 0.005f, 1.0f}; output = rocalWarpPerspective(handle, input, true, height, width, perspective_1d_matrix, ROCAL_LINEAR_INTERPOLATION); - }break; + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; From a487fd5d8cc3ba733b90e5303d546eb800188926 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 16 Dec 2025 01:38:57 -0600 Subject: [PATCH 49/77] Fix threshold pybind --- rocAL_pybind/amd/rocal/fn.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 836bfc057..35038322d 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1405,8 +1405,6 @@ def threshold(*inputs, min=None, max=None, device=None, output_layout=types.NHWC @return Thresholded image """ - min = b.createFloatParameter(min) if isinstance(min, float) else min - max = b.createFloatParameter(max) if isinstance(max, float) else max kwargs_pybind = { "input_image": inputs[0], "min": min, From 90e2aebeeb3653aa19a46f45d6aadfaab0978042 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 17 Dec 2025 04:19:05 -0600 Subject: [PATCH 50/77] Fix RICAP augmentation, create pinned memory for permutation --- .../geometry_augmentations/node_ricap.h | 16 +- .../geometry_augmentations/node_ricap.cpp | 171 ++++++++++-------- 2 files changed, 105 insertions(+), 82 deletions(-) diff --git a/rocAL/include/augmentations/geometry_augmentations/node_ricap.h b/rocAL/include/augmentations/geometry_augmentations/node_ricap.h index 064df07c5..f7016bc8c 100644 --- a/rocAL/include/augmentations/geometry_augmentations/node_ricap.h +++ b/rocAL/include/augmentations/geometry_augmentations/node_ricap.h @@ -31,14 +31,26 @@ class RicapNode : public Node { void update_node() override; private: + // Unified helper method for tensor creation with optional replication + template + vx_tensor create_tensor_with_replication( + const std::vector& input_vec, + vx_size N, + vx_size elems_per_sample, + void** backing_ptr, + RocalMemType mem_type, + vx_enum vx_data_type, + std::vector&& num_dims); + // Parameter storage from API std::vector _permutation_vec; std::vector _crop_rois_vec; // Internal VX objects created in create_node() - vx_array _perm_array_vx = nullptr; + vx_tensor _perm_tensor_vx = nullptr; vx_tensor _crop_rois_t = nullptr; - // Backing buffer for ROI tensor (host or pinned) + // Backing buffers for tensors (host or pinned) + void* _perm_ptr = nullptr; void* _crop_rois_ptr = nullptr; }; diff --git a/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp b/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp index d45d1e5fe..8e29a1970 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp @@ -12,19 +12,75 @@ All rights reserved. RicapNode::RicapNode(const std::vector& inputs, const std::vector& outputs) : Node(inputs, outputs) {} +// Unified helper function to create and populate a tensor with optional replication +template +vx_tensor RicapNode::create_tensor_with_replication( + const std::vector& input_vec, + vx_size N, + vx_size elems_per_sample, + void** backing_ptr, + RocalMemType mem_type, + vx_enum vx_data_type, + std::vector&& dims) { + + // Calculate total elements needed + const size_t total_elements = N * elems_per_sample; + const bool needs_replication = (input_vec.size() == elems_per_sample); + + // Validate input size + if (!(needs_replication || input_vec.size() == total_elements)) { + THROW("Tensor data size mismatch. Expected " + TOSTR(total_elements) + + " or " + TOSTR(elems_per_sample) + ", got " + TOSTR(input_vec.size())); + } + + // Setup dimensions and strides based on number of dimensions + std::vector strides(dims.size(), 0); + auto num_dims = dims.size(); + strides[0] = sizeof(T); + for (int i = 1; i < dims.size(); i++) { + strides[i] = strides[i - 1] * dims[i - 1]; + } + + // Allocate backing buffer + size_t bytes = sizeof(T) * total_elements; + allocate_host_or_pinned_mem(backing_ptr, bytes, mem_type); + + // Fill backing buffer with data (with replication if needed) + T* ptr = static_cast(*backing_ptr); + if (needs_replication) { + // Replicate the data for each sample in the batch + for (vx_size n = 0; n < N; ++n) { + std::copy(input_vec.begin(), input_vec.end(), ptr + n * elems_per_sample); + } + } else { + // Direct copy of all data + std::copy(input_vec.begin(), input_vec.end(), ptr); + } + + // Create tensor from handle + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; + vx_tensor tensor = vxCreateTensorFromHandle(ctx, num_dims, dims.data(), vx_data_type, 0, strides.data(), *backing_ptr, vx_mem); + + if (!tensor) THROW("vxCreateTensorFromHandle failed"); + + vx_status status = vxGetStatus((vx_reference)tensor); + if (status != VX_SUCCESS) THROW("vxCreateTensorFromHandle failed: " + TOSTR(status)); + + return tensor; +} + void RicapNode::create_node() { if (_node) return; - // Determine effective batch (sequence-aware) - const auto& dims_in = _inputs[0]->info().dims(); - if (dims_in.empty()) - THROW("Invalid input dims for Ricap"); - vx_size N = static_cast(dims_in[0]); + + vx_size N = static_cast(_inputs[0]->info().dims()[0]); auto layout = _inputs[0]->info().layout(); + + // Check for unsupported layouts if (layout == RocalTensorlayout::NFCHW || layout == RocalTensorlayout::NFHWC) { - if (dims_in.size() < 2) THROW("Invalid sequence dims for Ricap"); - N = static_cast(dims_in[0] * dims_in[1]); + THROW("NFHWC and NFCHW types are unsupported for Ricap augmentation"); } // Validate inputs @@ -33,82 +89,32 @@ void RicapNode::create_node() { if (_crop_rois_vec.empty()) THROW("Ricap requires non-empty crop_rois vector of length 16 or N*16"); - // Determine mem type and VX mem + // Determine memory type auto mem_type = _inputs[0]->info().mem_type(); - vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; - - // 1) Create permutation vx_array (length = N*4, replicate if needed) - { - std::vector perm(N * 4, 0); - if (_permutation_vec.size() == 4) { - for (vx_size n = 0; n < N; ++n) { - for (int k = 0; k < 4; ++k) - perm[n * 4 + k] = static_cast(_permutation_vec[k]); - } - } else if (_permutation_vec.size() == N * 4) { - for (vx_size i = 0; i < N * 4; ++i) - perm[i] = static_cast(_permutation_vec[i]); - } else { - THROW("Ricap permutation vector size must be 4 or N*4. Got " + TOSTR(_permutation_vec.size()) + ", expected " + TOSTR(N * 4)); - } - - _perm_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_UINT32, perm.size()); - if (!_perm_array_vx) THROW("vxCreateArray for permutation failed"); - vx_status s = vxGetStatus((vx_reference)_perm_array_vx); - if (s != VX_SUCCESS) THROW("Permutation array creation failed: " + TOSTR(s)); - s = vxAddArrayItems(_perm_array_vx, perm.size(), perm.data(), sizeof(vx_uint32)); - if (s != VX_SUCCESS) THROW("vxAddArrayItems for permutation failed: " + TOSTR(s)); - } - - // 2) Create crop-roi tensor (dims [N, 16], 4 ROIs per sample x 4 ints per ROI), replicate if vector has only 16 - { - const vx_size elems_per_sample = 16; // 4 ROIs x 4 ints - const bool replicate = (_crop_rois_vec.size() == elems_per_sample); - const size_t total_expected = static_cast(N) * elems_per_sample; - if (!(replicate || _crop_rois_vec.size() == total_expected)) { - THROW("Ricap crop_rois vector size mismatch. Expected " + TOSTR(total_expected) + " or 16, got " + TOSTR(_crop_rois_vec.size())); - } - - vx_size dims[2] = {N, elems_per_sample}; - vx_size stride[2]; - stride[0] = sizeof(vx_int32); - stride[1] = stride[0] * dims[0]; - - // Allocate backing buffer and create tensor from handle - size_t bytes = stride[1] * dims[1]; - allocate_host_or_pinned_mem(&_crop_rois_ptr, bytes, mem_type); - - vx_tensor tensor_vx = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), - 2, dims, VX_TYPE_INT32, 0, stride, _crop_rois_ptr, vx_mem); - if (!tensor_vx) THROW("vxCreateTensorFromHandle for ricap ROI tensor failed"); - vx_status s = vxGetStatus((vx_reference)tensor_vx); - if (s != VX_SUCCESS) THROW("vxCreateTensorFromHandle ROI failed: " + TOSTR(s)); - - // Fill backing buffer following the declared strides - int* iptr = static_cast(_crop_rois_ptr); - for (vx_size n = 0; n < N; ++n) { - const int* src = replicate ? _crop_rois_vec.data() : (&_crop_rois_vec[n * elems_per_sample]); - for (vx_size k = 0; k < elems_per_sample; ++k) { - iptr[n * elems_per_sample + k] = src[k]; - } - } - _crop_rois_t = tensor_vx; - } - - // 3) Prepare scalars + + + // Create permutation tensor (1D tensor with 4 elements per sample) + _perm_tensor_vx = create_tensor_with_replication( + _permutation_vec, N, 4, &_perm_ptr, mem_type, VX_TYPE_UINT32, {N, 4}); + + // Create crop ROI tensor (2D tensor with 16 elements per sample: 4 ROIs x 4 values) + _crop_rois_t = create_tensor_with_replication( + _crop_rois_vec, N, 16, &_crop_rois_ptr, mem_type, VX_TYPE_INT32, {N, 16}); + // Create scalars for layout and ROI type vx_context vx_ctx = vxGetContext((vx_reference)_graph->get()); int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); + vx_scalar input_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &input_layout); vx_scalar output_layout_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &roi_type); - // 4) Create VX node + // Create the Ricap node _node = vxExtRppRicap(_graph->get(), _inputs[0]->handle(), _outputs[0]->handle(), - _perm_array_vx, + _perm_tensor_vx, _crop_rois_t, input_layout_vx, output_layout_vx, @@ -120,23 +126,21 @@ void RicapNode::create_node() { } } -void RicapNode::update_node() { - // No dynamic attributes to update per frame -} - void RicapNode::init(const std::vector& permutation, const std::vector& crop_rois) { _permutation_vec = permutation; _crop_rois_vec = crop_rois; } +void RicapNode::update_node() {} + RicapNode::~RicapNode() { if (_inputs.empty() || !_inputs[0]) return; auto mem_type = _inputs[0]->info().mem_type(); - if (_perm_array_vx) { - vxReleaseArray(&_perm_array_vx); - _perm_array_vx = nullptr; + if (_perm_tensor_vx) { + vxReleaseTensor(&_perm_tensor_vx); + _perm_tensor_vx = nullptr; } if (_crop_rois_t) { vxReleaseTensor(&_crop_rois_t); @@ -145,14 +149,21 @@ RicapNode::~RicapNode() { if (mem_type == RocalMemType::HIP) { #if ENABLE_HIP - if (_crop_rois_ptr) { + if (_perm_ptr) { + hipError_t err = hipHostFree(_perm_ptr); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipHostFree failed for perm_ptr: " << std::to_string(err) << "\n"; + } + if (_crop_rois_ptr) { hipError_t err = hipHostFree(_crop_rois_ptr); if (err != hipSuccess) - std::cerr << "\n[ERR] hipHostFree failed " << std::to_string(err) << "\n"; + std::cerr << "\n[ERR] hipHostFree failed for crop_rois_ptr: " << std::to_string(err) << "\n"; } #endif } else { + if (_perm_ptr) free(_perm_ptr); if (_crop_rois_ptr) free(_crop_rois_ptr); } + _perm_ptr = nullptr; _crop_rois_ptr = nullptr; } From 423888cb5f4c6d112e05d8b98a9311b002e9f791 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 17 Dec 2025 04:43:37 -0600 Subject: [PATCH 51/77] Minor change --- rocAL/include/api/rocal_api_augmentation.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 5e135cb36..3f7b0db26 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1627,9 +1627,9 @@ extern "C" RocalTensor ROCAL_API_CALL rocalWarpPerspective(RocalContext context, * \param [in] context Rocal context * \param [in] input Input Rocal tensor * \param [in] is_output Is the output tensor part of the graph output - * \param [in] anchor_box_info Flattened LTRB anchors: either [4*num_boxes] replicated or [batch*4*num_boxes] - * \param [in] colors Flattened RGB colors per box: either [3*num_boxes] replicated or [batch*3*num_boxes] - * \param [in] num_boxes Per-sample number of boxes: either [1] to replicate or [batch] + * \param [in] anchor_box_info LTRB anchors: either [4*num_boxes] replicated or [batch*4*num_boxes] + * \param [in] colors RGB colors per box: either [3*num_boxes] replicated or [batch*3*num_boxes] + * \param [in] num_boxes Number of boxes to be erased * \param [in] output_layout the layout of the output tensor * \param [in] output_datatype the data type of the output tensor * \return RocalTensor From 5425302a25cd1b1ed505d6acf41c214684e60a62 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 17 Dec 2025 05:22:25 -0600 Subject: [PATCH 52/77] Minor changes --- .../filter_augmentations/node_erase.h | 12 +------- rocAL/source/api/rocal_api_augmentation.cpp | 24 ++------------- .../filter_augmentations/node_bitwise_ops.cpp | 12 ++++---- .../filter_augmentations/node_erase.cpp | 29 +++++++------------ .../geometry_augmentations/node_remap.cpp | 16 ++-------- 5 files changed, 22 insertions(+), 71 deletions(-) diff --git a/rocAL/include/augmentations/filter_augmentations/node_erase.h b/rocAL/include/augmentations/filter_augmentations/node_erase.h index c379327d2..6917a864d 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_erase.h +++ b/rocAL/include/augmentations/filter_augmentations/node_erase.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,24 +28,14 @@ THE SOFTWARE. #include "pipeline/node.h" #include "parameters/parameter_vx.h" -// Erase augmentation node: wraps MIVisionX vxExtRppErase -// Inputs: -// - _inputs[0]: source tensor -// - anchor_box_info: aux tensor holding per-sample per-box LTRB anchors -// - colors: aux tensor holding per-sample per-box RGB colors -// - _num_boxes: per-sample number of boxes (vx_array) -// Output: -// - _outputs[0]: destination tensor class EraseNode : public Node { public: EraseNode(const std::vector &inputs, const std::vector &outputs); EraseNode() = delete; ~EraseNode(); - // Overloads for dynamic vs fixed parameters void init(Tensor *anchor_box_info, Tensor *colors, int num_boxes_fixed); void init(Tensor *anchor_box_info, Tensor *colors, IntParam *num_boxes_param); - // New: raw vector-based init (replicates across batch as needed) void init(std::vector anchor, std::vector shape, std::vector num_boxes, diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index ae79be04e..1dc4db65e 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2883,7 +2883,6 @@ rocalErase( output_info.set_data_type(op_tensor_dtype); output = context->master_graph->create_tensor(output_info, is_output); auto erase_node = context->master_graph->add_node({input}, {output}); - // Use raw-vector overload; node will allocate and replicate per batch if needed erase_node->init(anchor, shape, num_boxes, fill_value); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -2909,24 +2908,17 @@ rocalRemap( auto context = static_cast(p_context); auto input = static_cast(p_input); try { - // Derive output size if not provided if (dest_width == 0 || dest_height == 0) { dest_width = input->info().max_shape()[0]; dest_height = input->info().max_shape()[1]; } - - // Create output tensor (may have different width/height than input) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); TensorInfo output_info = input->info(); output_info.set_data_type(op_tensor_dtype); output_info.modify_dims_width_and_height(op_tensor_layout, dest_width, dest_height); output = context->master_graph->create_tensor(output_info, is_output); - - // Pass raw remap vectors; node will create the vx_tensors and call vxExtRppRemap - context->master_graph - ->add_node({input}, {output}) - ->init(row_remap, col_remap, static_cast(interpolation_type)); + context->master_graph->add_node({input}, {output})->init(row_remap, col_remap, static_cast(interpolation_type)); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2951,18 +2943,13 @@ rocalCropAndPatch( auto input1 = static_cast(p_input1); auto input2 = static_cast(p_input2); try { - // Create output tensor (same shape as input1, but allow layout/datatype override) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); TensorInfo output_info = input1->info(); output_info.set_tensor_layout(op_tensor_layout); output_info.set_data_type(op_tensor_dtype); output = context->master_graph->create_tensor(output_info, is_output); - - // Pass raw ROI vectors to node; node will create vx_tensors and call vxExtRppCropAndPatch internally - context->master_graph - ->add_node({input1, input2}, {output}) - ->init(crop_roi_vec, patch_roi_vec); + context->master_graph->add_node({input1, input2}, {output})->init(crop_roi_vec, patch_roi_vec); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2984,20 +2971,15 @@ rocalRicap(RocalContext p_context, auto context = static_cast(p_context); auto input = static_cast(p_input); try { - // Output tensor inherits shape from input; allow layout/datatype override RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_dtype = static_cast(output_datatype); TensorInfo output_info = input->info(); if (op_tensor_layout != RocalTensorlayout::NONE) output_info.set_tensor_layout(op_tensor_layout); output_info.set_data_type(op_tensor_dtype); - output = context->master_graph->create_tensor(output_info, is_output); - - // Wire Ricap node and pass raw vectors; node will build vx objects and call vxExtRppRicap auto ricap_node = context->master_graph->add_node({input}, {output}); ricap_node->init(permutation, crop_rois); - // No meta-data changes needed } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -3015,7 +2997,6 @@ rocalBitwiseOps(RocalContext p_context, Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input1, output); - ROCAL_INVALID_INPUT_ERR(p_input2, output); auto context = static_cast(p_context); auto input1 = static_cast(p_input1); @@ -3027,7 +3008,6 @@ rocalBitwiseOps(RocalContext p_context, output_info.set_tensor_layout(op_tensor_layout); output_info.set_data_type(op_tensor_dtype); output = context->master_graph->create_tensor(output_info, is_output); - auto node = context->master_graph->add_node({input1, input2}, {output}); node->init(static_cast(op)); } catch (const std::exception& e) { diff --git a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp index caacc16fd..294de0cc8 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp @@ -27,10 +27,10 @@ void BitwiseOpsNode::create_node() { // pSrcRoi is carried in _inputs[0] ROI tensor _node = vxExtRppBitwiseOps(_graph->get(), - _inputs[0]->handle(), // pSrc1 - (_operator == BitwiseOp::NOT ? nullptr : _inputs[1]->handle()), // pSrc2 (optional for NOT) - _inputs[0]->get_roi_tensor(), // pSrcRoi (per-sample ROI for inputs) - _outputs[0]->handle(), // pDst + _inputs[0]->handle(), + (_operator == BitwiseOp::NOT ? nullptr : _inputs[1]->handle()), + _inputs[0]->get_roi_tensor(), + _outputs[0]->handle(), input_layout_vx, output_layout_vx, roi_type_vx, @@ -41,6 +41,4 @@ void BitwiseOpsNode::create_node() { THROW("Adding the bitwise ops (vxExtRppBitwiseOps) node failed: " + TOSTR(status)) } -void BitwiseOpsNode::update_node() { - // No per-iteration dynamic parameters -} +void BitwiseOpsNode::update_node() { } diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index 5b41859d0..bbca3b0aa 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -181,12 +181,12 @@ void EraseNode::init(std::vector anchor, // Keep fill pattern for colors; create_node expands it to per-box/channel _fill_values = std::move(fill_value); - // Normalize num_boxes to batch size + // Replicate num boxes for each image or copy the per sample input provided _num_boxes_vec.clear(); if (num_boxes.size() == 1) { _num_boxes_vec.assign(static_cast(_batch_size), static_cast(num_boxes[0])); } else if (num_boxes.size() == static_cast(_batch_size)) { - _num_boxes_vec.assign(num_boxes.begin(), num_boxes.end()); + _num_boxes_vec = num_boxes; } else { THROW("num_boxes vector length must be 1 or equal to batch size"); } @@ -195,7 +195,6 @@ void EraseNode::init(std::vector anchor, std::vector prefix(static_cast(_batch_size) + 1, 0); for (int i = 0; i < _batch_size; ++i) prefix[i + 1] = prefix[i] + _num_boxes_vec[i]; _total_boxes = static_cast(prefix[_batch_size]); - std::cerr << "Total Boxes " << _total_boxes << "\n"; auto channels = _inputs[0]->info().get_channels(); _fill_values_vec.resize(static_cast(_total_boxes) * channels); @@ -208,7 +207,6 @@ void EraseNode::init(std::vector anchor, } else if (num_boxes.size() == 1 && fill_sz == static_cast(num_boxes[0]) * channels) { - std::cerr << "Comes over here-----\n"; // Single-sample per-box per-channel replicated across batch. // All samples must have the same nb equal to num_boxes[0]. const int nb_single = num_boxes[0]; @@ -220,16 +218,14 @@ void EraseNode::init(std::vector anchor, std::copy_n(src, static_cast(nb_single) * channels, dst); dst += static_cast(nb_single) * channels; } - } - else if (fill_sz == static_cast(channels)) { + } else if (fill_sz == static_cast(channels)) { // Per-channel pattern replicated to each box float* dst = _fill_values_vec.data(); for (int b = 0; b < _total_boxes; ++b) { std::copy_n(_fill_values.data(), channels, dst); dst += channels; } - } - else if (fill_sz == static_cast(_batch_size)) { + } else if (fill_sz == static_cast(_batch_size)) { // Per-sample scalar replicated across its boxes (and channels) float* dst = _fill_values_vec.data(); for (int i = 0; i < _batch_size; ++i) { @@ -239,12 +235,10 @@ void EraseNode::init(std::vector anchor, std::fill_n(dst, count, v); dst += count; } - } - else if (fill_sz == static_cast(_total_boxes) * channels) { + } else if (fill_sz == static_cast(_total_boxes) * channels) { // Fully specified flattened values - std::copy(_fill_values.begin(), _fill_values.end(), _fill_values_vec.begin()); - } - else if (fill_sz == static_cast(_batch_size) * channels) { + _fill_values_vec = _fill_values; + } else if (fill_sz == static_cast(_batch_size) * channels) { // Per-sample per-channel pattern replicated across that sample’s boxes float* dst = _fill_values_vec.data(); const float* src = _fill_values.data(); @@ -254,15 +248,14 @@ void EraseNode::init(std::vector anchor, dst += channels; } } - } - else { + } else { THROW("Invalid number of values passed for fill value"); } - + // Build contiguous [x1, y1, w, h] for all boxes _anchor_vec.assign(_total_boxes * 4, 0.0f); - // Case 1: single-sample vectors replicated across batch + // Single-sample vectors replicated across batch if (num_boxes.size() == 1 && anchor.size() == static_cast(num_boxes[0]) * 2 && shape.size() == static_cast(num_boxes[0]) * 2) { @@ -279,7 +272,7 @@ void EraseNode::init(std::vector anchor, } } } - // Case 2: fully specified per-sample concatenated anchor/shape + // Fully specified per-sample concatenated anchor/shape else if (anchor.size() == _total_boxes * 2 && shape.size() == _total_boxes * 2) { for (int i = 0; i < _batch_size; ++i) { const int nb = _num_boxes_vec[i]; diff --git a/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp index 0e8aff1bd..7959de2c0 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp @@ -85,9 +85,7 @@ void RemapNode::create_node() { // Scalars for interpolation, layout and ROI vx_context vx_ctx = vxGetContext((vx_reference)_graph->get()); - - vx_scalar interpolation_vx = - vxCreateScalar(vx_ctx, VX_TYPE_INT32, &_interpolation_type); + vx_scalar interpolation_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &_interpolation_type); int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); @@ -98,16 +96,8 @@ void RemapNode::create_node() { vx_scalar roi_type_vx = vxCreateScalar(vx_ctx, VX_TYPE_INT32, &roi_type); // Construct the RPP Remap node - _node = vxExtRppRemap(_graph->get(), - _inputs[0]->handle(), - _inputs[0]->get_roi_tensor(), - _outputs[0]->handle(), - _row_tbl, - _col_tbl, - interpolation_vx, - input_layout_vx, - output_layout_vx, - roi_type_vx); + _node = vxExtRppRemap(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), _row_tbl, + _col_tbl, interpolation_vx, input_layout_vx, output_layout_vx, roi_type_vx); vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { From 3212a9eda8abef7e8802c9d7b052ec35adcd805c Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Fri, 19 Dec 2025 11:36:59 -0600 Subject: [PATCH 53/77] Create a vx_tensor of UINT8 type for RGB array --- .../color_augmentations/node_color_cast.h | 8 +-- .../color_augmentations/node_color_cast.cpp | 55 ++++++++++++++++--- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/rocAL/include/augmentations/color_augmentations/node_color_cast.h b/rocAL/include/augmentations/color_augmentations/node_color_cast.h index cd4963892..8938c2a51 100644 --- a/rocAL/include/augmentations/color_augmentations/node_color_cast.h +++ b/rocAL/include/augmentations/color_augmentations/node_color_cast.h @@ -29,6 +29,7 @@ class ColorCastNode : public Node { public: ColorCastNode(const std::vector &inputs, const std::vector &outputs); ColorCastNode() = delete; + ~ColorCastNode(); // Per-sample alpha as random parameter, and RGB triplet(s) void init(FloatParam *alpha_param, std::vector rgb); @@ -40,12 +41,9 @@ class ColorCastNode : public Node { void update_node() override; private: - // Per-sample alpha (size batch_size) ParameterVX _alpha; - // Flat RGB triplets (size batch_size * 3) std::vector _rgb; - vx_array _rgb_vx_array = nullptr; - - // Reasonable range for alpha [0, 1] + vx_tensor _rgb_tensor = nullptr; + void* _rgb_memory = nullptr; constexpr static float ALPHA_RANGE[2] = {0.0f, 1.0f}; }; diff --git a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp index cfd8eaef4..bce977c3a 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp @@ -21,8 +21,10 @@ THE SOFTWARE. */ #include +#include #include "augmentations/color_augmentations/node_color_cast.h" #include "pipeline/exception.h" +#include "pipeline/tensor.h" static void fill_rgb_for_batch(std::vector &rgb_out, unsigned batch_size, const std::vector &rgb_in) { rgb_out.resize(batch_size * 3); @@ -56,12 +58,37 @@ void ColorCastNode::create_node() { // Create per-sample arrays _alpha.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); - // Create and populate the RGB array (flat size = batch_size * 3) - vx_status status = VX_SUCCESS; - _rgb_vx_array = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, _batch_size * 3); - status |= vxAddArrayItems(_rgb_vx_array, _rgb.size(), _rgb.data(), sizeof(vx_float32)); - if (status != 0) - THROW(" vxAddArrayItems failed in the ColorCast (vxExtRppColorCast) node: " + TOSTR(status)) + // Create vx_tensor for the RGB values + const vx_size num_of_dims = 2; + vx_size stride[num_of_dims]; + std::vector rgb_tensor_dims = {_batch_size, 3}; + + // Calculate strides for uint8 data type + stride[0] = sizeof(vx_uint8); + stride[1] = stride[0] * rgb_tensor_dims[0]; + + // Determine memory type based on input tensor + vx_enum mem_type = VX_MEMORY_TYPE_HOST; + if (_inputs[0]->info().mem_type() == RocalMemType::HIP) + mem_type = VX_MEMORY_TYPE_HIP; + + // Allocate pinned memory for RGB values + size_t rgb_buffer_size = rgb_tensor_dims[1] * stride[1]; + allocate_host_or_pinned_mem(&_rgb_memory, rgb_buffer_size, _inputs[0]->info().mem_type()); + + // Convert float RGB values to uint8 and store in the allocated memory + vx_uint8* rgb_uint8_ptr = static_cast(_rgb_memory); + for (size_t i = 0; i < _rgb.size(); ++i) { + rgb_uint8_ptr[i] = static_cast(_rgb[i]); + } + + // Create tensor from the allocated memory + _rgb_tensor = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), num_of_dims, + rgb_tensor_dims.data(), VX_TYPE_UINT8, 0, + stride, _rgb_memory, mem_type); + vx_status status; + if ((status = vxGetStatus((vx_reference)_rgb_tensor)) != VX_SUCCESS) + THROW("Error: vxCreateTensorFromHandle(_rgb_tensor) failed: " + TOSTR(status)) // Layouts & ROI type int input_layout = static_cast(_inputs[0]->info().layout()); @@ -71,9 +98,8 @@ void ColorCastNode::create_node() { vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); - // Build node _node = vxExtRppColorCast(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), - _rgb_vx_array, _alpha.default_array(), input_layout_vx, output_layout_vx, roi_type_vx); + _rgb_tensor, _alpha.default_array(), input_layout_vx, output_layout_vx, roi_type_vx); vx_status nstatus; if ((nstatus = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the ColorCast (vxExtRppColorCast) node failed: " + TOSTR(nstatus)) @@ -92,3 +118,16 @@ void ColorCastNode::init(float alpha, std::vector rgb) { void ColorCastNode::update_node() { _alpha.update_array(); } + +ColorCastNode::~ColorCastNode() { + if (_inputs[0]->info().mem_type() == RocalMemType::HIP) { +#if ENABLE_HIP + hipError_t err = hipHostFree(_rgb_memory); + if (err != hipSuccess) + std::cerr << "\n[ERR] hipHostFree failed " << std::to_string(err) << "\n"; +#endif + } else { + if (_rgb_memory) free(_rgb_memory); + } + if (_rgb_tensor) vxReleaseTensor(&_rgb_tensor); +} \ No newline at end of file From a54ffbedf40d62b085b753b0bd8c7e413ea61ee9 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 23 Dec 2025 01:16:29 -0600 Subject: [PATCH 54/77] Add python support for the new augmentations --- rocAL_pybind/amd/rocal/fn.py | 106 ++++++++++++++++++++---- rocAL_pybind/amd/rocal/types.py | 11 +++ rocAL_pybind/rocal_pybind.cpp | 10 +-- tests/python_api/unit_test.py | 138 ++++++++++++++++++++++++++++++++ tests/python_api/unit_tests.sh | 9 +++ 5 files changed, 255 insertions(+), 19 deletions(-) diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index f3efd4c37..b01101dec 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1573,30 +1573,108 @@ def remap(*inputs, dest_width=0, dest_height=0, row_remap=[], col_remap=[], output_image = b.remap(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (output_image) -def erase(*inputs, anchor_box_info=None, colors=None, num_boxes=None, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): - """!Erases regions in images based on per-sample anchor boxes and colors. - +def erase(*inputs, anchor=None, shape=None, num_boxes=None, fill_value=None, + anchor_box_info=None, colors=None, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Erases regions in images. Supports both vector-based and tensor-based APIs. + + Vector-based API (when anchor, shape, num_boxes, fill_value are provided): + @param anchor (list of float) anchor points (x1, y1) for each box + @param shape (list of float) shape (w, h) for each box + @param num_boxes (list of int) number of boxes per sample + @param fill_value (list of float) fill values for erased regions + + Tensor-based API (when anchor_box_info and colors are provided): + @param anchor_box_info (rocalTensor) tensor holding per-sample per-box LTRB anchors + @param colors (rocalTensor) tensor holding per-sample per-box RGB colors + + Common parameters: @param inputs the input image passed to the augmentation - @param anchor_box_info (rocalTensor, required) tensor holding per-sample per-box LTRB anchors (shape: [N, max_boxes, 4]) - @param colors (rocalTensor, required) tensor holding per-sample per-box RGB colors (shape: [N, max_boxes, 3]) - @param num_boxes (int or IntParam, optional, default = None) per-sample number of boxes; if int, wrapped into IntParam @param device (string, optional, default = None) Parameter unused for augmentation @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output @return Image with specified regions erased """ - if anchor_box_info is None or colors is None: - raise RuntimeError("erase requires anchor_box_info and colors tensors") + # Check which API is being used + if anchor is not None and shape is not None and num_boxes is not None and fill_value is not None: + # Vector-based API + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "anchor": anchor, + "shape": shape, + "num_boxes": num_boxes, + "fill_value": fill_value, + "output_layout": output_layout, + "output_dtype": output_dtype + } + elif anchor_box_info is not None and colors is not None: + # Tensor-based API + num_boxes = b.createIntParameter(num_boxes) if isinstance(num_boxes, int) else num_boxes + kwargs_pybind = { + "input_image": inputs[0], + "is_output": False, + "anchor_box_info": anchor_box_info, + "colors": colors, + "num_boxes": num_boxes, + "output_layout": output_layout, + "output_dtype": output_dtype + } + else: + raise RuntimeError("erase requires either (anchor, shape, num_boxes, fill_value) for vector API or (anchor_box_info, colors) for tensor API") + + output_image = b.erase(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + +def ricap(*inputs, permutation=[], crop_rois=[], device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies RICAP (Random Image Cropping And Patching) augmentation. + + RICAP creates a new training image by combining four cropped regions from the input batch. + + @param inputs the input image passed to the augmentation + @param permutation (list of int) permutation indices for quadrants (length 4 or batch*4) + @param crop_rois (list of int) XYWH ROIs for cropping (length 16 or batch*16) + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output - num_boxes = b.createIntParameter(num_boxes) if isinstance(num_boxes, int) else num_boxes + @return RICAP augmented image + """ kwargs_pybind = { "input_image": inputs[0], "is_output": False, - "anchor_box_info": anchor_box_info, - "colors": colors, - "num_boxes": num_boxes, + "permutation": permutation, + "crop_rois": crop_rois, "output_layout": output_layout, "output_dtype": output_dtype } - output_image = b.erase(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) - return (output_image) \ No newline at end of file + output_image = b.ricap(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) + +def bitwise_ops(*inputs, op=None, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies bitwise operations on input images. + + @param inputs list containing input image(s); for NOT operation, only first is used + @param op (RocalBitwiseOp) bitwise operation type (BITWISE_AND, BITWISE_OR, BITWISE_XOR, BITWISE_NOT) + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output + @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output + + @return Image after bitwise operation + """ + if op is None: + raise RuntimeError("bitwise_ops requires 'op' parameter specifying the operation type") + + # For NOT operation, we only need one input, but the API expects two + if len(inputs) == 1: + inputs = [inputs[0], inputs[0]] + + kwargs_pybind = { + "input_image0": inputs[0], + "input_image1": inputs[1], + "is_output": False, + "op": op, + "output_layout": output_layout, + "output_dtype": output_dtype + } + output_image = b.bitwiseOps(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (output_image) diff --git a/rocAL_pybind/amd/rocal/types.py b/rocAL_pybind/amd/rocal/types.py index c676ed058..71f7fcb9c 100644 --- a/rocAL_pybind/amd/rocal/types.py +++ b/rocAL_pybind/amd/rocal/types.py @@ -126,6 +126,12 @@ from rocal_pybind.types import MISSING_COMPONENT_SKIP from rocal_pybind.types import MISSING_COMPONENT_EMPTY +# RocalBitwiseOpType +from rocal_pybind.types import BITWISE_AND +from rocal_pybind.types import BITWISE_OR +from rocal_pybind.types import BITWISE_XOR +from rocal_pybind.types import BITWISE_NOT + _known_types = { OK: ("OK", OK), @@ -211,6 +217,11 @@ MISSING_COMPONENT_ERROR : ("MISSING_COMPONENT_ERROR", MISSING_COMPONENT_ERROR), MISSING_COMPONENT_SKIP : ("MISSING_COMPONENT_SKIP", MISSING_COMPONENT_SKIP), MISSING_COMPONENT_EMPTY : ("MISSING_COMPONENT_EMPTY", MISSING_COMPONENT_EMPTY), + + BITWISE_AND : ("BITWISE_AND", BITWISE_AND), + BITWISE_OR : ("BITWISE_OR", BITWISE_OR), + BITWISE_XOR : ("BITWISE_OR", BITWISE_XOR), + BITWISE_NOT : ("BITWISE_NOT", BITWISE_NOT), } def data_type_function(dtype): diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index dbd19f9ca..347c00404 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -753,6 +753,11 @@ py::class_(m, "rocalListOfTensorList") .value("LAST_BATCH_DROP", ROCAL_LAST_BATCH_DROP) .value("LAST_BATCH_PARTIAL", ROCAL_LAST_BATCH_PARTIAL) .export_values(); + py::enum_(types_m, "RocalMissingComponentsBehaviour", "Rocal Missing components behavior") + .value("MISSING_COMPONENT_ERROR", ROCAL_MISSING_COMPONENT_ERROR) + .value("MISSING_COMPONENT_SKIP", ROCAL_MISSING_COMPONENT_SKIP) + .value("MISSING_COMPONENT_EMPTY", ROCAL_MISSING_COMPONENT_EMPTY) + .export_values(); // Bitwise Ops enum py::enum_(types_m, "RocalBitwiseOp", "Bitwise operation selector") .value("BITWISE_AND", ROCAL_BITWISE_AND) @@ -760,11 +765,6 @@ py::class_(m, "rocalListOfTensorList") .value("BITWISE_XOR", ROCAL_BITWISE_XOR) .value("BITWISE_NOT", ROCAL_BITWISE_NOT) .export_values(); - py::enum_(types_m, "RocalMissingComponentsBehaviour", "Rocal Missing components behavior") - .value("MISSING_COMPONENT_ERROR", ROCAL_MISSING_COMPONENT_ERROR) - .value("MISSING_COMPONENT_SKIP", ROCAL_MISSING_COMPONENT_SKIP) - .value("MISSING_COMPONENT_EMPTY", ROCAL_MISSING_COMPONENT_EMPTY) - .export_values(); py::class_(m, "ROIxywh") .def(py::init<>()) .def_readwrite("x", &ROIxywh::x) diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 3520e6983..3f2a5514a 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -597,6 +597,144 @@ def main(): output_layout=tensor_layout, output_dtype=tensor_dtype, interpolation_type=types.LINEAR_INTERPOLATION) + elif augmentation_name == "remap": + # Build identity remap tables with horizontal flip for left half + H = max_height + W = max_width + row_remap = [] + col_remap = [] + half_width = W // 2 + for y in range(H): + for x in range(half_width): + row_remap.append(float(y)) + col_remap.append(float(half_width - x)) + for x in range(half_width, W): + row_remap.append(float(y)) + col_remap.append(float(x)) + output = fn.remap(images, + dest_height=H, + dest_width=W, + row_remap=row_remap, + col_remap=col_remap, + interpolation_type=types.LINEAR_INTERPOLATION, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "crop_and_patch": + # Create a second input (rotated version) + images2 = fn.rotate(images, + angle=45.0, + dest_width=max_width, + dest_height=max_height, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + # Define XYWH ROIs + roi_w = max(1, (max_width) // 4) + roi_h = max(1, (max_height) // 4) + crop_roi = [max(0, (max_width) // 8), + max(0, (max_height) // 8), + roi_w, roi_h] + patch_roi = [0, 0, roi_w, roi_h] + output = fn.crop_and_patch(images, + images2, + crop_roi=crop_roi, + patch_roi=patch_roi, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "ricap": + # Permutation for quadrants [q0,q1,q2,q3]; replicate across batch + permutation = [0, 1, 1, 0, 1, 0, 0, 1] + # Define 4 XYWH ROIs covering image quadrants + q_w = max(1, (max_width) // 2) + q_h = max(1, (max_height) // 2) + crop_rois = [ + 0, 0, q_w, q_h, # top-left + q_w, 0, q_w, q_h, # top-right + 0, q_h, q_w, q_h, # bottom-left + q_w, q_h, q_w, q_h # bottom-right + ] + output = fn.ricap(images, + permutation=permutation, + crop_rois=crop_rois, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "bitwise_and": + # Create second input tensor (rotate input to get variation) + images2 = fn.rotate(images, + angle=45.0, + dest_width=max_width, + dest_height=max_height, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + output = fn.bitwise_ops(images, + images2, + op=types.BITWISE_AND, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "bitwise_or": + images2 = fn.rotate(images, + angle=45.0, + dest_width=max_width, + dest_height=max_height, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + output = fn.bitwise_ops(images, + images2, + op=types.BITWISE_OR, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "bitwise_xor": + images2 = fn.rotate(images, + angle=45.0, + dest_width=max_width, + dest_height=max_height, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + output = fn.bitwise_ops(images, + images2, + op=types.BITWISE_XOR, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "bitwise_not": + # NOT uses only a single input + output = fn.bitwise_ops(images, + images, # second parameter ignored for NOT + op=types.BITWISE_NOT, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "erase": + # Use vector-based API with anchor [x1,y1], shape [w,h], num_boxes, and fill values + num_boxes = [2] # Two boxes per sample + + # Derive two boxes using input width/height + W = max_width + H = max_height + bw = max(1, W // 4) + bh = max(1, H // 4) + + # Two anchors (x1, y1) and matching shapes (w, h) + anchor = [ + float(W // 8), float(H // 8), + float(W // 2), float(H // 2) + ] + shape = [ + float(bw), float(bh), + float(W - 50), float(H - 25) + ] + + # Fill values for each box and channel + if color_format == types.RGB: + fill_value = [0.0, 0.0, 240.0, 0.0, 60.0, 0.0] + else: + fill_value = [120.0, 60.0] + + output = fn.erase(images, + anchor=anchor, + shape=shape, + num_boxes=num_boxes, + fill_value=fill_value, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + if output_set == 0: pipe.set_outputs(output) diff --git a/tests/python_api/unit_tests.sh b/tests/python_api/unit_tests.sh index 93b7f25de..81cd45b3b 100755 --- a/tests/python_api/unit_tests.sh +++ b/tests/python_api/unit_tests.sh @@ -178,6 +178,15 @@ do python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name threshold --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Threshold_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name warp_perspective --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}WarpPerspective_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name remap --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Remap_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name crop_and_patch --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}CropAndPatch_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name ricap --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Ricap_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name bitwise_and --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}BitwiseAnd_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name bitwise_or --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}BitwiseOr_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name bitwise_xor --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}BitwiseXor_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name bitwise_not --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}BitwiseNot_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name erase --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Erase_${rgb_name[$rgb]}_${device_name}" + # Special Case - One Hot Encoded Labels python"$ver" unit_test.py --image-dataset-path "$one_hot_data_path" --augmentation-name one_hot --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}OneHot_${rgb_name[$rgb]}_${device_name}" From a0657a277ba2a6068f140baa0d450c15d0a2f24c Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 23 Dec 2025 01:17:44 -0600 Subject: [PATCH 55/77] Minor change --- tests/python_api/unit_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 3520e6983..78d212f5a 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -557,8 +557,8 @@ def main(): elif augmentation_name == "magnitude": images2 = fn.rotate(images, angle=45.0, - dest_width=max_width if max_width else 416, - dest_height=max_height if max_height else 416, + dest_width=max_width, + dest_height=max_height, output_layout=tensor_layout, output_dtype=tensor_dtype) output = fn.magnitude(images, @@ -568,8 +568,8 @@ def main(): elif augmentation_name == "phase": images2 = fn.rotate(images, angle=45.0, - dest_width=max_width if max_width else 416, - dest_height=max_height if max_height else 416, + dest_width=max_width, + dest_height=max_height, output_layout=tensor_layout, output_dtype=tensor_dtype) output = fn.phase(images, From 78a3afd967276a49f67c5c642a974622d3bfdf42 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 23 Dec 2025 05:24:15 -0600 Subject: [PATCH 56/77] Add VX_RPP version check for new augmentations --- .../augmentations/color_augmentations/node_color_cast.cpp | 5 +++++ .../color_augmentations/node_non_linear_blend.cpp | 5 +++++ .../augmentations/effects_augmentations/node_grid_mask.cpp | 5 +++++ .../filter_augmentations/node_gaussian_filter.cpp | 5 +++++ .../filter_augmentations/node_median_filter.cpp | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp index bce977c3a..08ce51e75 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include +#include #include #include "augmentations/color_augmentations/node_color_cast.h" #include "pipeline/exception.h" @@ -55,6 +56,7 @@ void ColorCastNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) // Create per-sample arrays _alpha.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); @@ -103,6 +105,9 @@ void ColorCastNode::create_node() { vx_status nstatus; if ((nstatus = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the ColorCast (vxExtRppColorCast) node failed: " + TOSTR(nstatus)) +#else + THROW("ColorCastNode: vxExtRppColorCast requires amd_rpp version >= 3.2.0"); +#endif } void ColorCastNode::init(FloatParam *alpha_param, std::vector rgb) { diff --git a/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp index a8f04039e..c61912aef 100644 --- a/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/color_augmentations/node_non_linear_blend.h" #include "pipeline/exception.h" @@ -33,6 +34,7 @@ void NonLinearBlendNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) if (_inputs.size() < 2) THROW("NonLinearBlend node needs two input images") @@ -55,6 +57,9 @@ void NonLinearBlendNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the NonLinearBlend (vxExtRppNonLinearBlend) node failed: " + TOSTR(status)) +#else + THROW("NonLinearBlendNode: vxExtRppNonLinearBlend requires amd_rpp version >= 3.2.0"); +#endif } void NonLinearBlendNode::init(float stddev) { diff --git a/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp index 82ce41a3f..87cc91339 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp @@ -23,6 +23,7 @@ THE SOFTWARE. #include "augmentations/effects_augmentations/node_grid_mask.h" #include +#include #include "pipeline/exception.h" @@ -33,6 +34,7 @@ void GridMaskNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); @@ -65,6 +67,9 @@ void GridMaskNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the grid mask (vxExtRppGridMask) node failed: " + TOSTR(status)) +#else + THROW("GridMaskNode: vxExtRppGridMask requires amd_rpp version >= 3.2.0"); +#endif } void GridMaskNode::init(unsigned tile_width, float grid_ratio, float grid_angle_radians, unsigned translate_x, unsigned translate_y) { diff --git a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp index 026daac4a..e4cfc7d64 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp @@ -17,6 +17,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +#include #include "augmentations/filter_augmentations/node_gaussian_filter.h" #include "pipeline/exception.h" @@ -37,6 +38,7 @@ void GaussianFilterNode::init(FloatParam* stddev_param, int kernel_size) { void GaussianFilterNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) // Per-sample stddev array _stddev.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); @@ -64,6 +66,9 @@ void GaussianFilterNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the gaussian filter (vxExtRppGaussianFilter) node failed: " + TOSTR(status)) +#else + THROW("GaussianFilterNode: vxExtRppGaussianFilter requires amd_rpp version >= 3.2.0"); +#endif } void GaussianFilterNode::update_node() { diff --git a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp index 1b6fc001d..f5afc86e5 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp @@ -17,6 +17,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +#include #include "augmentations/filter_augmentations/node_median_filter.h" #include "pipeline/exception.h" @@ -27,6 +28,7 @@ void MedianFilterNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); @@ -50,6 +52,9 @@ void MedianFilterNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the median filter (vxExtRppMedianFilter) node failed: " + TOSTR(status)) +#else + THROW("MedianFilterNode: vxExtRppMedianFilter requires amd_rpp version >= 3.2.0"); +#endif } void MedianFilterNode::init(int kernel_size, int border_type) { From 266a85645d02b68faa0680f3aa446a9dd82c064b Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 23 Dec 2025 05:36:01 -0600 Subject: [PATCH 57/77] Add version check for new augmentations --- .../augmentations/filter_augmentations/node_dilate.cpp | 5 +++++ .../source/augmentations/filter_augmentations/node_erode.cpp | 5 +++++ .../augmentations/filter_augmentations/node_magnitude.cpp | 5 +++++ .../source/augmentations/filter_augmentations/node_phase.cpp | 5 +++++ .../augmentations/filter_augmentations/node_threshold.cpp | 5 +++++ .../geometry_augmentations/node_warp_perspective.cpp | 5 +++++ 6 files changed, 30 insertions(+) diff --git a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp index 7ae6f946e..b35bd19b0 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp @@ -18,6 +18,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/filter_augmentations/node_dilate.h" #include "pipeline/exception.h" @@ -28,6 +29,7 @@ void DilateNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 3) int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); @@ -49,6 +51,9 @@ void DilateNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the dilate (vxExtRppDilate) node failed: " + TOSTR(status)) +#else + THROW("DilateNode: vxExtRppDilate requires amd_rpp version >= 3.1.3"); +#endif } void DilateNode::init(unsigned kernel_size) { diff --git a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp index 9b9c097d2..75f0a30e9 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp @@ -19,6 +19,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/filter_augmentations/node_erode.h" #include "pipeline/exception.h" @@ -29,6 +30,7 @@ void ErodeNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 3) int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); @@ -50,6 +52,9 @@ void ErodeNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the erode (vxExtRppErode) node failed: " + TOSTR(status)) +#else + THROW("ErodeNode: vxExtRppErode requires amd_rpp version >= 3.1.3"); +#endif } void ErodeNode::init(unsigned kernel_size) { diff --git a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp index fdc401d5f..daf5c801e 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp @@ -19,6 +19,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/filter_augmentations/node_magnitude.h" #include "pipeline/exception.h" @@ -29,6 +30,7 @@ void MagnitudeNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 3) if (_inputs.size() < 2) THROW("Magnitude node needs two input tensors") @@ -52,6 +54,9 @@ void MagnitudeNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the magnitude (vxExtRppMagnitude) node failed: " + TOSTR(status)) +#else + THROW("MagnitudeNode: vxExtRppMagnitude requires amd_rpp version >= 3.1.3"); +#endif } void MagnitudeNode::update_node() {} diff --git a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp index 006bf8c20..ceba6ec1e 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp @@ -18,6 +18,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/filter_augmentations/node_phase.h" #include "pipeline/exception.h" @@ -28,6 +29,7 @@ void PhaseNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 3) if (_inputs.size() < 2) THROW("Phase node needs two input tensors") @@ -51,6 +53,9 @@ void PhaseNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the phase (vxExtRppPhase) node failed: " + TOSTR(status)) +#else + THROW("PhaseNode: vxExtRppPhase requires amd_rpp version >= 3.1.3"); +#endif } void PhaseNode::update_node() {} diff --git a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp index 539f8a6ce..9747147ef 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/filter_augmentations/node_threshold.h" #include "pipeline/exception.h" @@ -50,6 +51,7 @@ void ThresholdNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 3) // Create per-sample arrays for min and max threshold values auto no_of_channels = _inputs[0]->info().get_channels(); auto array_size = _batch_size * no_of_channels; @@ -95,6 +97,9 @@ void ThresholdNode::create_node() { if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the threshold (vxExtRppThreshold) node failed: " + TOSTR(status)) +#else + THROW("ThresholdNode: vxExtRppThreshold requires amd_rpp version >= 3.1.3"); +#endif } void ThresholdNode::init(std::vector& min_val, std::vector& max_val) { diff --git a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp index ecf381cfe..87692cb28 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp @@ -23,6 +23,7 @@ THE SOFTWARE. #include "augmentations/geometry_augmentations/node_warp_perspective.h" #include +#include #include "pipeline/exception.h" @@ -34,6 +35,7 @@ void WarpPerspectiveNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 3) // Build and allocate perspective array const size_t expected_len = static_cast(_batch_size) * 9; @@ -89,6 +91,9 @@ void WarpPerspectiveNode::create_node() { if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { THROW("Adding the warp perspective (vxExtRppWarpPerspective) node failed: " + TOSTR(status)); } +#else + THROW("WarpPerspectiveNode: vxExtRppWarpPerspective requires amd_rpp version >= 3.1.3"); +#endif } void WarpPerspectiveNode::init(const std::vector& perspective_matrix, ResizeInterpolationType interpolation_type) { From ca8670e5bffaccaa21c3c92976388509252a187b Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 23 Dec 2025 05:37:41 -0600 Subject: [PATCH 58/77] Fix version check in THROW statements --- .../augmentations/color_augmentations/node_color_cast.cpp | 2 +- .../augmentations/color_augmentations/node_non_linear_blend.cpp | 2 +- .../augmentations/effects_augmentations/node_grid_mask.cpp | 2 +- .../augmentations/filter_augmentations/node_gaussian_filter.cpp | 2 +- .../augmentations/filter_augmentations/node_median_filter.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp index 08ce51e75..a5f0af7a8 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp @@ -106,7 +106,7 @@ void ColorCastNode::create_node() { if ((nstatus = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the ColorCast (vxExtRppColorCast) node failed: " + TOSTR(nstatus)) #else - THROW("ColorCastNode: vxExtRppColorCast requires amd_rpp version >= 3.2.0"); + THROW("ColorCastNode: vxExtRppColorCast requires amd_rpp version >= 3.1.2"); #endif } diff --git a/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp index c61912aef..bc5502b7b 100644 --- a/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp @@ -58,7 +58,7 @@ void NonLinearBlendNode::create_node() { if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the NonLinearBlend (vxExtRppNonLinearBlend) node failed: " + TOSTR(status)) #else - THROW("NonLinearBlendNode: vxExtRppNonLinearBlend requires amd_rpp version >= 3.2.0"); + THROW("NonLinearBlendNode: vxExtRppNonLinearBlend requires amd_rpp version >= 3.1.2"); #endif } diff --git a/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp index 87cc91339..b6ca7f0e7 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp @@ -68,7 +68,7 @@ void GridMaskNode::create_node() { if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the grid mask (vxExtRppGridMask) node failed: " + TOSTR(status)) #else - THROW("GridMaskNode: vxExtRppGridMask requires amd_rpp version >= 3.2.0"); + THROW("GridMaskNode: vxExtRppGridMask requires amd_rpp version >= 3.1.2"); #endif } diff --git a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp index e4cfc7d64..b66951f3d 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp @@ -67,7 +67,7 @@ void GaussianFilterNode::create_node() { if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the gaussian filter (vxExtRppGaussianFilter) node failed: " + TOSTR(status)) #else - THROW("GaussianFilterNode: vxExtRppGaussianFilter requires amd_rpp version >= 3.2.0"); + THROW("GaussianFilterNode: vxExtRppGaussianFilter requires amd_rpp version >= 3.1.2"); #endif } diff --git a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp index f5afc86e5..02041d0b5 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp @@ -53,7 +53,7 @@ void MedianFilterNode::create_node() { if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the median filter (vxExtRppMedianFilter) node failed: " + TOSTR(status)) #else - THROW("MedianFilterNode: vxExtRppMedianFilter requires amd_rpp version >= 3.2.0"); + THROW("MedianFilterNode: vxExtRppMedianFilter requires amd_rpp version >= 3.1.2"); #endif } From c1946ef649e0707baac62905d770e479bdb9aefe Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 23 Dec 2025 05:47:28 -0600 Subject: [PATCH 59/77] Add version check for new augmentations --- .../augmentations/filter_augmentations/node_bitwise_ops.cpp | 5 +++++ .../augmentations/filter_augmentations/node_erase.cpp | 5 +++++ .../geometry_augmentations/node_crop_and_patch.cpp | 5 +++++ .../augmentations/geometry_augmentations/node_remap.cpp | 5 +++++ .../augmentations/geometry_augmentations/node_ricap.cpp | 6 +++++- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp index 294de0cc8..b985c40b0 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp @@ -3,12 +3,14 @@ Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. */ #include +#include #include "augmentations/filter_augmentations/node_bitwise_ops.h" #include "pipeline/exception.h" void BitwiseOpsNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 4) // For AND/OR/XOR require two inputs; for NOT allow a single input if ( (_operator != BitwiseOp::NOT && _inputs.size() < 2) || (_operator == BitwiseOp::NOT && _inputs.size() < 1) ) @@ -39,6 +41,9 @@ void BitwiseOpsNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the bitwise ops (vxExtRppBitwiseOps) node failed: " + TOSTR(status)) +#else + THROW("BitwiseOpsNode: vxExtRppBitwiseOps requires amd_rpp version >= 3.1.4"); +#endif } void BitwiseOpsNode::update_node() { } diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index bbca3b0aa..6034461d0 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include +#include #include #include "augmentations/filter_augmentations/node_erase.h" #include "pipeline/exception.h" @@ -53,6 +54,7 @@ void EraseNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 4) // Tensor layout and ROI type int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); @@ -170,6 +172,9 @@ void EraseNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the erase (vxExtRppErase) node failed: " + TOSTR(status)) +#else + THROW("EraseNode: vxExtRppErase requires amd_rpp version >= 3.1.4"); +#endif } // New: raw vector-based init (replicates across batch if needed) diff --git a/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp b/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp index da73d8b43..1cbcfa143 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp @@ -6,6 +6,7 @@ All rights reserved. #include "augmentations/geometry_augmentations/node_crop_and_patch.h" #include +#include #include #include "pipeline/exception.h" @@ -16,6 +17,7 @@ void CropAndPatchNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 4) // Validate inputs if (_crop_roi_vec.empty() || _patch_roi_vec.empty()) THROW("CropAndPatch node requires non-empty ROI vectors for dst, crop and patch") @@ -102,6 +104,9 @@ void CropAndPatchNode::create_node() { if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { THROW("Adding the crop_and_patch (vxExtRppCropAndPatch) node failed: " + TOSTR(status)); } +#else + THROW("CropAndPatchNode: vxExtRppCropAndPatch requires amd_rpp version >= 3.1.4"); +#endif } void CropAndPatchNode::update_node() {} diff --git a/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp index 7959de2c0..2633ce886 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp @@ -6,6 +6,7 @@ All rights reserved. #include "augmentations/geometry_augmentations/node_remap.h" #include +#include #include #include "pipeline/exception.h" @@ -16,6 +17,7 @@ void RemapNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 4) // Validate vectors if (_row_remap_vec.empty() || _col_remap_vec.empty()) THROW("Remap node requires non-empty row and col remap vectors") @@ -103,6 +105,9 @@ void RemapNode::create_node() { if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { THROW("Adding the remap (vxExtRppRemap) node failed: " + TOSTR(status)); } +#else + THROW("RemapNode: vxExtRppRemap requires amd_rpp version >= 3.1.4"); +#endif } void RemapNode::update_node() {} diff --git a/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp b/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp index 8e29a1970..5dbd6bcb0 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp @@ -6,6 +6,7 @@ All rights reserved. #include "augmentations/geometry_augmentations/node_ricap.h" #include +#include #include #include "pipeline/exception.h" @@ -74,7 +75,7 @@ void RicapNode::create_node() { if (_node) return; - +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 4) vx_size N = static_cast(_inputs[0]->info().dims()[0]); auto layout = _inputs[0]->info().layout(); @@ -124,6 +125,9 @@ void RicapNode::create_node() { if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) { THROW("Adding the ricap (vxExtRppRicap) node failed: " + TOSTR(status)); } +#else + THROW("RicapNode: vxExtRppRicap requires amd_rpp version >= 3.1.4"); +#endif } void RicapNode::init(const std::vector& permutation, From 4e49d8fcf258f21dbb688ac1995e398210b6c6ca Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 6 Jan 2026 04:44:06 -0600 Subject: [PATCH 60/77] Minor changes - resolve review comments --- .../filter_augmentations/node_dilate.cpp | 2 +- .../filter_augmentations/node_erode.cpp | 2 +- .../filter_augmentations/node_magnitude.cpp | 2 +- .../filter_augmentations/node_phase.cpp | 2 +- .../filter_augmentations/node_threshold.cpp | 30 +++++++++++-------- .../node_warp_perspective.cpp | 12 ++++---- 6 files changed, 28 insertions(+), 22 deletions(-) diff --git a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp index b35bd19b0..b8f35eeb4 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_dilate.cpp @@ -50,7 +50,7 @@ void DilateNode::create_node() { roi_type_vx); vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the dilate (vxExtRppDilate) node failed: " + TOSTR(status)) + THROW("Adding the dilate (vxExtRppDilate) node failed: " + TOSTR(status)); #else THROW("DilateNode: vxExtRppDilate requires amd_rpp version >= 3.1.3"); #endif diff --git a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp index 75f0a30e9..8f8ac455a 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erode.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erode.cpp @@ -51,7 +51,7 @@ void ErodeNode::create_node() { roi_type_vx); vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the erode (vxExtRppErode) node failed: " + TOSTR(status)) + THROW("Adding the erode (vxExtRppErode) node failed: " + TOSTR(status)); #else THROW("ErodeNode: vxExtRppErode requires amd_rpp version >= 3.1.3"); #endif diff --git a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp index daf5c801e..f15b443eb 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp @@ -53,7 +53,7 @@ void MagnitudeNode::create_node() { roi_type_vx); vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the magnitude (vxExtRppMagnitude) node failed: " + TOSTR(status)) + THROW("Adding the magnitude (vxExtRppMagnitude) node failed: " + TOSTR(status)); #else THROW("MagnitudeNode: vxExtRppMagnitude requires amd_rpp version >= 3.1.3"); #endif diff --git a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp index ceba6ec1e..efc61c09d 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp @@ -52,7 +52,7 @@ void PhaseNode::create_node() { roi_type_vx); vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the phase (vxExtRppPhase) node failed: " + TOSTR(status)) + THROW("Adding the phase (vxExtRppPhase) node failed: " + TOSTR(status)); #else THROW("PhaseNode: vxExtRppPhase requires amd_rpp version >= 3.1.3"); #endif diff --git a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp index 9747147ef..12e1d051a 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_threshold.cpp @@ -28,15 +28,15 @@ THE SOFTWARE. ThresholdNode::ThresholdNode(const std::vector &inputs, const std::vector &outputs) : Node(inputs, outputs) {} -void fill_vector_with_threshold_values(std::vector& threshold_batch, - std::vector& threshold_values, - size_t no_of_channels) { +void fill_vector_with_threshold_values(std::vector& threshold_batch, + std::vector& threshold_values, + size_t no_of_channels) { size_t threshold_vec_size = threshold_batch.size(); - + if (threshold_values.size() == no_of_channels) { - for (int batch_channel_idx = 0; batch_channel_idx < threshold_vec_size; batch_channel_idx += no_of_channels) { - for (int channel_idx = 0; channel_idx < no_of_channels; channel_idx++) { + for (size_t batch_channel_idx = 0; batch_channel_idx < threshold_vec_size; batch_channel_idx += no_of_channels) { + for (size_t channel_idx = 0; channel_idx < no_of_channels; channel_idx++) { threshold_batch[batch_channel_idx + channel_idx] = threshold_values[channel_idx]; } } @@ -60,18 +60,22 @@ void ThresholdNode::create_node() { max_array.resize(array_size, 0.0f); fill_vector_with_threshold_values(min_array, _min, no_of_channels); fill_vector_with_threshold_values(max_array, _max, no_of_channels); - + // Create vx_array and populate it vx_status status; - vx_array min_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, array_size); + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_array min_array_vx = vxCreateArray(ctx, VX_TYPE_FLOAT32, array_size); status = vxAddArrayItems(min_array_vx, array_size, min_array.data(), sizeof(vx_float32)); if (status != VX_SUCCESS) { + vxReleaseArray(&min_array_vx); THROW("Threshold: vxAddArrayItems failed while creating min array: " + TOSTR(status)); } - vx_array max_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, array_size); + vx_array max_array_vx = vxCreateArray(ctx, VX_TYPE_FLOAT32, array_size); status = vxAddArrayItems(max_array_vx, array_size, max_array.data(), sizeof(vx_float32)); if (status != VX_SUCCESS) { + vxReleaseArray(&min_array_vx); + vxReleaseArray(&max_array_vx); THROW("Threshold: vxAddArrayItems failed while creating max array: " + TOSTR(status)); } @@ -80,9 +84,9 @@ void ThresholdNode::create_node() { int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); - vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); - vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); - vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); // Create Threshold node via MIVisionX RPP extension _node = vxExtRppThreshold(_graph->get(), @@ -96,7 +100,7 @@ void ThresholdNode::create_node() { roi_type_vx); if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the threshold (vxExtRppThreshold) node failed: " + TOSTR(status)) + THROW("Adding the threshold (vxExtRppThreshold) node failed: " + TOSTR(status)); #else THROW("ThresholdNode: vxExtRppThreshold requires amd_rpp version >= 3.1.3"); #endif diff --git a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp index 87692cb28..eded3d9ce 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_warp_perspective.cpp @@ -59,23 +59,25 @@ void WarpPerspectiveNode::create_node() { // Create vx_array and populate it vx_status status; - vx_array perspective_array_vx = vxCreateArray(vxGetContext((vx_reference)_graph->get()), VX_TYPE_FLOAT32, expected_len); + vx_context ctx = vxGetContext((vx_reference)_graph->get()); + vx_array perspective_array_vx = vxCreateArray(ctx, VX_TYPE_FLOAT32, expected_len); status = vxAddArrayItems(perspective_array_vx, expected_len, data.data(), sizeof(vx_float32)); if (status != VX_SUCCESS) { + vxReleaseArray(&perspective_array_vx); THROW("WarpPerspective: vxAddArrayItems failed while creating perspective array: " + TOSTR(status)); } // Interpolation scalar - vx_scalar interpolation_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &_interpolation_type); + vx_scalar interpolation_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &_interpolation_type); // Layout and ROI type scalars int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); - vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); - vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); - vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + vx_scalar input_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); // Construct the RPP WarpPerspective node _node = vxExtRppWarpPerspective(_graph->get(), From 5567e360aeff0fe53997f0d419605ac194b00d89 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 6 Jan 2026 04:44:24 -0600 Subject: [PATCH 61/77] Update python description --- rocAL_pybind/amd/rocal/fn.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 35038322d..7f39be235 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1293,7 +1293,7 @@ def color_cast(*inputs, alpha=1.0, rgb=[0.0, 0.0, 0.0], device=None, output_layo @return Image with color cast applied """ alpha = b.createFloatParameter(alpha) if isinstance(alpha, float) else alpha - kwargs_pybind = {"input_image": inputs[0], "is_output": False, "p_alpha": alpha, "rgb": rgb, + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "alpha": alpha, "rgb": rgb, "output_layout": output_layout, "output_dtype": output_dtype} color_cast_image = b.colorCast(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (color_cast_image) @@ -1356,7 +1356,7 @@ def gaussian_filter(*inputs, stddev=None, kernel_size=3, device=None, output_lay """!Applies gaussian filter to images with per-sample stddev parameter. @param inputs the input image passed to the augmentation - @param stddev (float or FloatParam, optional, default = None) per-sample standard deviation parameter; if float, wrapped into a FloatParam + @param stddev (float or FloatParam, optional, default = None) per-sample standard deviation parameter; if float, wrapped into a FloatParam. @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 @param device (string, optional, default = None) Parameter unused for augmentation @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output @@ -1397,8 +1397,8 @@ def threshold(*inputs, min=None, max=None, device=None, output_layout=types.NHWC """!Applies thresholding to images with per-sample min/max parameters. @param inputs the input image passed to the augmentation - @param min (float or FloatParam, optional, default = None) per-sample minimum threshold; if float, wrapped into a FloatParam - @param max (float or FloatParam, optional, default = None) per-sample maximum threshold; if float, wrapped into a FloatParam + @param min (list of floats, optional, default = None) minimum thresholds per channel or per sample (length = channels or batch*channels) + @param max (list of floats, optional, default = None) maximum thresholds per channel or per sample (length = channels or batch*channels) @param device (string, optional, default = None) Parameter unused for augmentation @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output From 54c78c1c95f72803ab21fd09274c2767b00148c9 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 7 Jan 2026 06:18:18 -0600 Subject: [PATCH 62/77] Add border type for gaussian filter --- rocAL/include/api/rocal_api_augmentation.h | 4 ++++ .../filter_augmentations/node_gaussian_filter.h | 5 +++-- rocAL/source/api/rocal_api_augmentation.cpp | 6 ++++-- .../filter_augmentations/node_gaussian_filter.cpp | 8 ++++++-- rocAL_pybind/amd/rocal/fn.py | 4 +++- tests/cpp_api/unit_tests/unit_tests.cpp | 4 ++-- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index ec6c26294..7c4b01660 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1457,6 +1457,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalMedianFilter(RocalContext context, Ro * \param [in] is_output Is the output tensor part of the graph output * \param [in] stddev Per-sample standard deviation parameter * \param [in] kernel_size Gaussian filter kernel size (pixels) + * \param [in] border_type Border handling policy * \param [in] output_layout the layout of the output tensor * \param [in] output_datatype the data type of the output tensor * \return RocalTensor @@ -1465,6 +1466,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilter(RocalContext context, bool is_output, RocalFloatParam stddev = NULL, unsigned kernel_size = 3, + int border_type = 0, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); @@ -1474,6 +1476,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilter(RocalContext context, * \param [in] input Input Rocal tensor * \param [in] stddev Fixed standard deviation value * \param [in] kernel_size Gaussian filter kernel size (pixels) + * \param [in] border_type Border handling policy * \param [in] is_output Is the output tensor part of the graph output * \param [in] output_layout the layout of the output tensor * \param [in] output_datatype the data type of the output tensor @@ -1482,6 +1485,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilter(RocalContext context, extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext context, RocalTensor input, float stddev, unsigned kernel_size, + int border_type, bool is_output, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); diff --git a/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h b/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h index ffb16c48d..cf75a1e32 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h +++ b/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h @@ -26,9 +26,9 @@ class GaussianFilterNode : public Node { GaussianFilterNode() = delete; // Dynamic per-sample stddev with fixed kernel size - void init(FloatParam* stddev_param, int kernel_size); + void init(FloatParam* stddev_param, int kernel_size, int border_type); // Fixed stddev with fixed kernel size - void init(float stddev, int kernel_size); + void init(float stddev, int kernel_size, int border_type); protected: void create_node() override; @@ -38,6 +38,7 @@ class GaussianFilterNode : public Node { // Per-sample stddev (size batch_size) ParameterVX _stddev; unsigned _kernel_size = 3; + int _border_type = 0; // Reasonable range for stddev > 0 constexpr static float STDDEV_RANGE[2] = {0.01f, 64.0f}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 494f6b6f3..da55fb160 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2531,6 +2531,7 @@ rocalGaussianFilter( bool is_output, RocalFloatParam p_stddev, unsigned kernel_size, + int border_type, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { Tensor* output = nullptr; @@ -2548,7 +2549,7 @@ rocalGaussianFilter( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph ->add_node({input}, {output}) - ->init(stddev, kernel_size); + ->init(stddev, kernel_size, border_type); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2561,6 +2562,7 @@ rocalGaussianFilterFixed( RocalTensor p_input, float stddev, unsigned kernel_size, + int border_type, bool is_output, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { @@ -2578,7 +2580,7 @@ rocalGaussianFilterFixed( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph ->add_node({input}, {output}) - ->init(stddev, kernel_size); + ->init(stddev, kernel_size, border_type); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } diff --git a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp index b66951f3d..e6126a3ed 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp @@ -25,14 +25,16 @@ GaussianFilterNode::GaussianFilterNode(const std::vector& inputs, const : Node(inputs, outputs), _stddev(STDDEV_RANGE[0], STDDEV_RANGE[1]) {} -void GaussianFilterNode::init(float stddev, int kernel_size) { +void GaussianFilterNode::init(float stddev, int kernel_size, int border_type) { _stddev.set_param(stddev); _kernel_size = kernel_size; + _border_type = border_type; } -void GaussianFilterNode::init(FloatParam* stddev_param, int kernel_size) { +void GaussianFilterNode::init(FloatParam* stddev_param, int kernel_size, int border_type) { _stddev.set_param(core(stddev_param)); _kernel_size = kernel_size; + _border_type = border_type; } void GaussianFilterNode::create_node() { @@ -52,6 +54,7 @@ void GaussianFilterNode::create_node() { vx_scalar output_layout_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &output_layout); vx_scalar roi_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &roi_type); vx_scalar kernel_size_vx = vxCreateScalar(ctx, VX_TYPE_UINT32, &_kernel_size); + vx_scalar border_type_vx = vxCreateScalar(ctx, VX_TYPE_INT32, &_border_type); _node = vxExtRppGaussianFilter(_graph->get(), _inputs[0]->handle(), @@ -59,6 +62,7 @@ void GaussianFilterNode::create_node() { _outputs[0]->handle(), _stddev.default_array(), kernel_size_vx, + border_type_vx, input_layout_vx, output_layout_vx, roi_type_vx); diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 3b8a26b6e..931f5b35e 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1385,12 +1385,13 @@ def median_filter(*inputs, kernel_size=3, border_type=0, device=None, output_lay return (output_image) -def gaussian_filter(*inputs, stddev=None, kernel_size=3, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): +def gaussian_filter(*inputs, stddev=None, kernel_size=3, border_type=0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies gaussian filter to images with per-sample stddev parameter. @param inputs the input image passed to the augmentation @param stddev (float or FloatParam, optional, default = None) per-sample standard deviation parameter; if float, wrapped into a FloatParam @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 + @param border_type (int, default = 0) border handling policy (implementation specific) @param device (string, optional, default = None) Parameter unused for augmentation @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output @@ -1403,6 +1404,7 @@ def gaussian_filter(*inputs, stddev=None, kernel_size=3, device=None, output_lay "is_output": False, "stddev": stddev, "kernel_size": kernel_size, + "border_type": border_type, "output_layout": output_layout, "output_dtype": output_dtype } diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index be7f95932..08c3c421e 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -925,11 +925,11 @@ int test(int test_case, int reader_type, const char *path, const char *outName, case 70: { std::cout << "Running rocalGaussianFilter" << std::endl; // Use existing float_param defined earlier as per-sample stddev - output = rocalGaussianFilter(handle, input, true, nullptr, 3, output_tensor_layout, output_tensor_dtype); + output = rocalGaussianFilter(handle, input, true, nullptr, 3, 0, output_tensor_layout, output_tensor_dtype); } break; case 71: { std::cout << "Running rocalGaussianFilterFixed" << std::endl; - output = rocalGaussianFilterFixed(handle, input, 5.0f, 3, true, output_tensor_layout, output_tensor_dtype); + output = rocalGaussianFilterFixed(handle, input, 5.0f, 3, 0, true, output_tensor_layout, output_tensor_dtype); } break; default: std::cout << "Not a valid option! Exiting!\n"; From c4cd2a54c1691c3b68a54b64dc03b88b877a0344 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Wed, 7 Jan 2026 06:34:57 -0600 Subject: [PATCH 63/77] Introduce ImageBorderType enum --- rocAL/include/api/rocal_api_augmentation.h | 6 +++--- rocAL/include/api/rocal_api_types.h | 16 ++++++++++++++++ .../filter_augmentations/node_gaussian_filter.h | 4 ++-- .../filter_augmentations/node_median_filter.h | 2 +- rocAL/include/pipeline/commons.h | 10 ++++++++++ rocAL/source/api/rocal_api_augmentation.cpp | 12 ++++++------ .../node_gaussian_filter.cpp | 8 ++++---- .../filter_augmentations/node_median_filter.cpp | 2 +- rocAL_pybind/amd/rocal/fn.py | 8 ++++---- rocAL_pybind/amd/rocal/types.py | 9 +++++++++ rocAL_pybind/rocal_pybind.cpp | 5 +++++ tests/cpp_api/unit_tests/unit_tests.cpp | 6 +++--- tests/python_api/unit_test.py | 3 ++- 13 files changed, 66 insertions(+), 25 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 7c4b01660..ad1d443e9 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -1446,7 +1446,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGridMask(RocalContext context, RocalT extern "C" RocalTensor ROCAL_API_CALL rocalMedianFilter(RocalContext context, RocalTensor input, bool is_output, unsigned kernel_size = 3, - int border_type = 0, + RocalImageBorderType border_type = RocalImageBorderType::ROCAL_REPLICATE, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); @@ -1466,7 +1466,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilter(RocalContext context, bool is_output, RocalFloatParam stddev = NULL, unsigned kernel_size = 3, - int border_type = 0, + RocalImageBorderType border_type = RocalImageBorderType::ROCAL_REPLICATE, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); @@ -1485,7 +1485,7 @@ extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilter(RocalContext context, extern "C" RocalTensor ROCAL_API_CALL rocalGaussianFilterFixed(RocalContext context, RocalTensor input, float stddev, unsigned kernel_size, - int border_type, + RocalImageBorderType border_type, bool is_output, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); diff --git a/rocAL/include/api/rocal_api_types.h b/rocAL/include/api/rocal_api_types.h index 9a74a942b..dbf1213a9 100644 --- a/rocAL/include/api/rocal_api_types.h +++ b/rocAL/include/api/rocal_api_types.h @@ -464,6 +464,22 @@ enum RocalLastBatchPolicy { ROCAL_LAST_BATCH_PARTIAL = 2 }; + +/*! \brief rocAL Image Border Type enum + * \ingroup group_rocal_types + */ +enum RocalImageBorderType { + /*! \brief AMD ROCAL_REPLICATE + */ + ROCAL_REPLICATE = 0, + /*! \brief AMD ROCAL_CONSTANT + */ + ROCAL_CONSTANT = 1, + /*! \brief AMD ROCAL_REFLECT_NO_EDGE + */ + ROCAL_REFLECT_NO_EDGE = 2 +}; + /*! \brief rocAL RocalShardingInfo enum * \ingroup group_rocal_types */ diff --git a/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h b/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h index cf75a1e32..8ae8c601d 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h +++ b/rocAL/include/augmentations/filter_augmentations/node_gaussian_filter.h @@ -26,9 +26,9 @@ class GaussianFilterNode : public Node { GaussianFilterNode() = delete; // Dynamic per-sample stddev with fixed kernel size - void init(FloatParam* stddev_param, int kernel_size, int border_type); + void init(FloatParam* stddev_param, int kernel_size, ImageBorderType border_type); // Fixed stddev with fixed kernel size - void init(float stddev, int kernel_size, int border_type); + void init(float stddev, int kernel_size, ImageBorderType border_type); protected: void create_node() override; diff --git a/rocAL/include/augmentations/filter_augmentations/node_median_filter.h b/rocAL/include/augmentations/filter_augmentations/node_median_filter.h index 2d3524989..566b525ad 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_median_filter.h +++ b/rocAL/include/augmentations/filter_augmentations/node_median_filter.h @@ -25,7 +25,7 @@ class MedianFilterNode : public Node { MedianFilterNode() = delete; // Fixed parameters - void init(int kernel_size, int border_type); + void init(int kernel_size, ImageBorderType border_type); protected: void create_node() override; diff --git a/rocAL/include/pipeline/commons.h b/rocAL/include/pipeline/commons.h index 1cab15a87..b5ac6d56e 100644 --- a/rocAL/include/pipeline/commons.h +++ b/rocAL/include/pipeline/commons.h @@ -280,3 +280,13 @@ enum class OutOfBoundsPolicy { ERROR }; REGISTER_ENUM(OutOfBoundsPolicy) + +/*! \brief Internal Image Border Type enum + * Internal version of RocalImageBorderType for use within rocAL implementation + */ +enum class ImageBorderType { + REPLICATE = 0, + CONSTANT, + REFLECT_NO_EDGE +}; +REGISTER_ENUM(ImageBorderType) diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index da55fb160..6ac889881 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2500,7 +2500,7 @@ rocalMedianFilter( RocalTensor p_input, bool is_output, unsigned kernel_size, - int border_type, + RocalImageBorderType border_type, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { Tensor* output = nullptr; @@ -2517,7 +2517,7 @@ rocalMedianFilter( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph ->add_node({input}, {output}) - ->init(kernel_size, border_type); + ->init(kernel_size, static_cast(border_type)); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2531,7 +2531,7 @@ rocalGaussianFilter( bool is_output, RocalFloatParam p_stddev, unsigned kernel_size, - int border_type, + RocalImageBorderType border_type, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { Tensor* output = nullptr; @@ -2549,7 +2549,7 @@ rocalGaussianFilter( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph ->add_node({input}, {output}) - ->init(stddev, kernel_size, border_type); + ->init(stddev, kernel_size, static_cast(border_type)); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2562,7 +2562,7 @@ rocalGaussianFilterFixed( RocalTensor p_input, float stddev, unsigned kernel_size, - int border_type, + RocalImageBorderType border_type, bool is_output, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { @@ -2580,7 +2580,7 @@ rocalGaussianFilterFixed( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph ->add_node({input}, {output}) - ->init(stddev, kernel_size, border_type); + ->init(stddev, kernel_size, static_cast(border_type)); } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } diff --git a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp index e6126a3ed..e716bb8de 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp @@ -25,16 +25,16 @@ GaussianFilterNode::GaussianFilterNode(const std::vector& inputs, const : Node(inputs, outputs), _stddev(STDDEV_RANGE[0], STDDEV_RANGE[1]) {} -void GaussianFilterNode::init(float stddev, int kernel_size, int border_type) { +void GaussianFilterNode::init(float stddev, int kernel_size, ImageBorderType border_type) { _stddev.set_param(stddev); _kernel_size = kernel_size; - _border_type = border_type; + _border_type = static_cast(border_type); } -void GaussianFilterNode::init(FloatParam* stddev_param, int kernel_size, int border_type) { +void GaussianFilterNode::init(FloatParam* stddev_param, int kernel_size, ImageBorderType border_type) { _stddev.set_param(core(stddev_param)); _kernel_size = kernel_size; - _border_type = border_type; + _border_type = static_cast(border_type); } void GaussianFilterNode::create_node() { diff --git a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp index 02041d0b5..8212d10a5 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp @@ -57,7 +57,7 @@ void MedianFilterNode::create_node() { #endif } -void MedianFilterNode::init(int kernel_size, int border_type) { +void MedianFilterNode::init(int kernel_size, ImageBorderType border_type) { _kernel_size = kernel_size; _border_type = static_cast(border_type); } diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 931f5b35e..d865428f7 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1361,12 +1361,12 @@ def grid_mask(*inputs, tile_width=16, grid_ratio=0.5, grid_angle=0.0, translate_ grid_mask_image = b.gridMask(Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) return (grid_mask_image) -def median_filter(*inputs, kernel_size=3, border_type=0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): +def median_filter(*inputs, kernel_size=3, border_type=types.REPLICATE, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies median filter to images. @param inputs the input image passed to the augmentation @param kernel_size (int, default = 3) median filter kernel size (pixels), typically odd: 3,5,7 - @param border_type (int, default = 0) border handling policy (implementation specific) + @param border_type (int, default = types.REPLICATE) border handling policy (implementation specific) @param device (string, optional, default = None) Parameter unused for augmentation @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output @@ -1385,13 +1385,13 @@ def median_filter(*inputs, kernel_size=3, border_type=0, device=None, output_lay return (output_image) -def gaussian_filter(*inputs, stddev=None, kernel_size=3, border_type=0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): +def gaussian_filter(*inputs, stddev=None, kernel_size=3, border_type=types.REPLICATE, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): """!Applies gaussian filter to images with per-sample stddev parameter. @param inputs the input image passed to the augmentation @param stddev (float or FloatParam, optional, default = None) per-sample standard deviation parameter; if float, wrapped into a FloatParam @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 - @param border_type (int, default = 0) border handling policy (implementation specific) + @param border_type (int, default = types.REPLICATE) border handling policy (implementation specific) @param device (string, optional, default = None) Parameter unused for augmentation @param output_layout (int, optional, default = types.NHWC) tensor layout for the augmentation output @param output_dtype (int, optional, default = types.UINT8) tensor dtype for the augmentation output diff --git a/rocAL_pybind/amd/rocal/types.py b/rocAL_pybind/amd/rocal/types.py index c676ed058..e84dbc21d 100644 --- a/rocAL_pybind/amd/rocal/types.py +++ b/rocAL_pybind/amd/rocal/types.py @@ -126,6 +126,11 @@ from rocal_pybind.types import MISSING_COMPONENT_SKIP from rocal_pybind.types import MISSING_COMPONENT_EMPTY +# RocalImageBorderType +from rocal_pybind.types import REPLICATE +from rocal_pybind.types import CONSTANT +from rocal_pybind.types import REFLECT_NO_EDGE + _known_types = { OK: ("OK", OK), @@ -211,6 +216,10 @@ MISSING_COMPONENT_ERROR : ("MISSING_COMPONENT_ERROR", MISSING_COMPONENT_ERROR), MISSING_COMPONENT_SKIP : ("MISSING_COMPONENT_SKIP", MISSING_COMPONENT_SKIP), MISSING_COMPONENT_EMPTY : ("MISSING_COMPONENT_EMPTY", MISSING_COMPONENT_EMPTY), + + REPLICATE : ("REPLICATE", REPLICATE), + CONSTANT : ("CONSTANT", CONSTANT), + REFLECT_NO_EDGE : ("REFLECT_NO_EDGE", REFLECT_NO_EDGE), } def data_type_function(dtype): diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index 033bca449..c14832555 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -758,6 +758,11 @@ py::class_(m, "rocalListOfTensorList") .value("MISSING_COMPONENT_SKIP", ROCAL_MISSING_COMPONENT_SKIP) .value("MISSING_COMPONENT_EMPTY", ROCAL_MISSING_COMPONENT_EMPTY) .export_values(); + py::enum_(types_m,"RocalImageBorderType", "Rocal Image Border Type") + .value("REPLICATE", ROCAL_REPLICATE) + .value("CONSTANT", ROCAL_CONSTANT) + .value("REFLECT_NO_EDGE", ROCAL_REFLECT_NO_EDGE) + .export_values(); py::class_(m, "ROIxywh") .def(py::init<>()) .def_readwrite("x", &ROIxywh::x) diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 08c3c421e..54d530dd8 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -919,17 +919,17 @@ int test(int test_case, int reader_type, const char *path, const char *outName, case 69: { std::cout << "Running rocalMedianFilter" << std::endl; int kernel = 3; - int border_type = 0; + auto border_type = RocalImageBorderType::ROCAL_REPLICATE; output = rocalMedianFilter(handle, input, true, kernel, border_type, output_tensor_layout, output_tensor_dtype); } break; case 70: { std::cout << "Running rocalGaussianFilter" << std::endl; // Use existing float_param defined earlier as per-sample stddev - output = rocalGaussianFilter(handle, input, true, nullptr, 3, 0, output_tensor_layout, output_tensor_dtype); + output = rocalGaussianFilter(handle, input, true, nullptr, 3, RocalImageBorderType::ROCAL_REPLICATE, output_tensor_layout, output_tensor_dtype); } break; case 71: { std::cout << "Running rocalGaussianFilterFixed" << std::endl; - output = rocalGaussianFilterFixed(handle, input, 5.0f, 3, 0, true, output_tensor_layout, output_tensor_dtype); + output = rocalGaussianFilterFixed(handle, input, 5.0f, 3, RocalImageBorderType::ROCAL_REPLICATE, true, output_tensor_layout, output_tensor_dtype); } break; default: std::cout << "Not a valid option! Exiting!\n"; diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index f7a61b94a..d59e4e1b7 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -524,13 +524,14 @@ def main(): elif augmentation_name == "median_filter": output = fn.median_filter(images, kernel_size=3, - border_type=0, + border_type=types.REPLICATE, output_layout=tensor_layout, output_dtype=tensor_dtype) elif augmentation_name == "gaussian_filter": output = fn.gaussian_filter(images, stddev=5.0, kernel_size=3, + border_type=types.REPLICATE, output_layout=tensor_layout, output_dtype=tensor_dtype) From c8b21c5eeb236c164bc3fccdba796838e6d8644e Mon Sep 17 00:00:00 2001 From: SundarRajan28 Date: Thu, 8 Jan 2026 12:34:15 -0600 Subject: [PATCH 64/77] Add rocAL support for Set 1 augmentations: GaussianNoise, ShotNoise, Spatter, Log, ColorJitter, Water - Add node headers and implementations for GaussianNoise, ShotNoise, Spatter, Log, ColorJitter, Water - Add C API declarations and implementations in rocal_api_augmentation.h/cpp - Add Python bindings in rocal_pybind.cpp and fn.py --- rocAL/include/api/rocal_api_augmentation.h | 192 +++++++++++ .../arithmetic_augmentations/node_log.h | 35 ++ .../augmentations/augmentations_nodes.h | 6 + .../color_augmentations/node_color_jitter.h | 50 +++ .../node_gaussian_noise.h | 46 +++ .../effects_augmentations/node_shot_noise.h | 45 +++ .../effects_augmentations/node_spatter.h | 43 +++ .../effects_augmentations/node_water.h | 52 +++ rocAL/source/api/rocal_api_augmentation.cpp | 310 ++++++++++++++++++ .../arithmetic_augmentations/node_log.cpp | 40 +++ .../color_augmentations/node_color_jitter.cpp | 79 +++++ .../node_gaussian_noise.cpp | 67 ++++ .../effects_augmentations/node_shot_noise.cpp | 62 ++++ .../effects_augmentations/node_spatter.cpp | 55 ++++ .../effects_augmentations/node_water.cpp | 90 +++++ rocAL_pybind/amd/rocal/fn.py | 135 ++++++++ rocAL_pybind/rocal_pybind.cpp | 14 +- 17 files changed, 1320 insertions(+), 1 deletion(-) create mode 100644 rocAL/include/augmentations/arithmetic_augmentations/node_log.h create mode 100644 rocAL/include/augmentations/color_augmentations/node_color_jitter.h create mode 100644 rocAL/include/augmentations/effects_augmentations/node_gaussian_noise.h create mode 100644 rocAL/include/augmentations/effects_augmentations/node_shot_noise.h create mode 100644 rocAL/include/augmentations/effects_augmentations/node_spatter.h create mode 100644 rocAL/include/augmentations/effects_augmentations/node_water.h create mode 100644 rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp create mode 100644 rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp create mode 100644 rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp create mode 100644 rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp create mode 100644 rocAL/source/augmentations/effects_augmentations/node_spatter.cpp create mode 100644 rocAL/source/augmentations/effects_augmentations/node_water.cpp diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 10a4e001d..4d5e63e1f 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -599,6 +599,78 @@ extern "C" RocalTensor ROCAL_API_CALL rocalSnPNoiseFixed(RocalContext context, R RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies gaussian noise effect on images. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] mean specifies the mean value for the Gaussian noise distribution + * \param [in] stddev specifies the standard deviation for the Gaussian noise distribution + * \param [in] seed seed value for the random number generator + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalGaussianNoise(RocalContext context, RocalTensor input, + bool is_output, + RocalFloatParam mean = NULL, RocalFloatParam stddev = NULL, + int seed = 0, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies gaussian noise on images with fixed parameters. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] mean specifies the mean value for the Gaussian noise distribution + * \param [in] stddev specifies the standard deviation for the Gaussian noise distribution + * \param [in] is_output is the output tensor part of the graph output + * \param [in] seed seed value for the random number generator + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalGaussianNoiseFixed(RocalContext context, RocalTensor input, + bool is_output, + float mean = 0.0, float stddev = 1.0, int seed = 0, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies shot noise effect on images. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] noise_factor specifies the noise intensity factor for the shot (Poisson) noise + * \param [in] seed seed value for the random number generator + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalShotNoise(RocalContext context, RocalTensor input, + bool is_output, + RocalFloatParam noise_factor = NULL, + int seed = 0, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies shot noise on images with fixed parameters. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] noise_factor specifies the noise intensity factor for the shot (Poisson) noise + * \param [in] is_output is the output tensor part of the graph output + * \param [in] seed seed value for the random number generator + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalShotNoiseFixed(RocalContext context, RocalTensor input, + float noise_factor, + bool is_output, int seed = 0, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Applies snow effect on images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context @@ -678,6 +750,24 @@ extern "C" RocalTensor ROCAL_API_CALL rocalRainFixed(RocalContext context, Rocal RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies spatter effect on images. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] red red channel value of the spatter color + * \param [in] green green channel value of the spatter color + * \param [in] blue blue channel value of the spatter color + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalSpatter(RocalContext context, RocalTensor input, + bool is_output, + uint8_t red = 65, uint8_t green = 50, uint8_t blue = 23, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Adjusts the color temperature in images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context @@ -709,6 +799,47 @@ extern "C" RocalTensor ROCAL_API_CALL rocalColorTempFixed(RocalContext context, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies color jitter augmentation on images. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] brightness brightness adjustment factor + * \param [in] contrast contrast adjustment factor + * \param [in] hue hue adjustment value in degrees + * \param [in] saturation saturation adjustment factor + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalColorJitter(RocalContext context, RocalTensor input, + bool is_output, + RocalFloatParam brightness = NULL, + RocalFloatParam contrast = NULL, + RocalFloatParam hue = NULL, + RocalFloatParam saturation = NULL, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies color jitter augmentation on images with fixed parameters. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] brightness brightness adjustment factor + * \param [in] contrast contrast adjustment factor + * \param [in] hue hue adjustment value in degrees + * \param [in] saturation saturation adjustment factor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalColorJitterFixed(RocalContext context, RocalTensor input, + float brightness, float contrast, float hue, float saturation, + bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Applies fog effect on images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context @@ -1372,4 +1503,65 @@ extern "C" RocalTensor ROCAL_API_CALL rocalLog1p(RocalContext p_context, RocalTensor p_input, bool is_output); +/*! \brief Computes the natural logarithm of input element-wise and returns the output + * \param [in] p_context Rocal context + * \param [in] p_input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalLog(RocalContext p_context, + RocalTensor p_input, + bool is_output); + +/*! \brief Applies water effect on images. + * \ingroup group_rocal_augmentations + * \note Accepts U8 and RGB24 input. + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] is_output is the output tensor part of the graph output + * \param [in] amplitude_x amplitude of the water effect in the x direction + * \param [in] amplitude_y amplitude of the water effect in the y direction + * \param [in] frequency_x frequency of the water effect in the x direction + * \param [in] frequency_y frequency of the water effect in the y direction + * \param [in] phase_x phase of the water effect in the x direction + * \param [in] phase_y phase of the water effect in the y direction + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalWater(RocalContext context, RocalTensor input, + bool is_output, + RocalFloatParam amplitude_x = NULL, + RocalFloatParam amplitude_y = NULL, + RocalFloatParam frequency_x = NULL, + RocalFloatParam frequency_y = NULL, + RocalFloatParam phase_x = NULL, + RocalFloatParam phase_y = NULL, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + +/*! \brief Applies water effect on images with fixed parameters. + * \ingroup group_rocal_augmentations + * \note Accepts U8 and RGB24 input. + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] amplitude_x amplitude of the water effect in the x direction + * \param [in] amplitude_y amplitude of the water effect in the y direction + * \param [in] frequency_x frequency of the water effect in the x direction + * \param [in] frequency_y frequency of the water effect in the y direction + * \param [in] phase_x phase of the water effect in the x direction + * \param [in] phase_y phase of the water effect in the y direction + * \param [in] is_output is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalWaterFixed(RocalContext context, RocalTensor input, + float amplitude_x, float amplitude_y, + float frequency_x, float frequency_y, + float phase_x, float phase_y, + bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + #endif // MIVISIONX_ROCAL_API_AUGMENTATION_H diff --git a/rocAL/include/augmentations/arithmetic_augmentations/node_log.h b/rocAL/include/augmentations/arithmetic_augmentations/node_log.h new file mode 100644 index 000000000..999e5e89b --- /dev/null +++ b/rocAL/include/augmentations/arithmetic_augmentations/node_log.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once + +#include "pipeline/node.h" + +class LogNode : public Node { + public: + LogNode(const std::vector &inputs, const std::vector &outputs); + LogNode() = delete; + + protected: + void create_node() override; + void update_node() override {}; +}; diff --git a/rocAL/include/augmentations/augmentations_nodes.h b/rocAL/include/augmentations/augmentations_nodes.h index 0d93109f7..ca0fc45d7 100644 --- a/rocAL/include/augmentations/augmentations_nodes.h +++ b/rocAL/include/augmentations/augmentations_nodes.h @@ -27,8 +27,12 @@ THE SOFTWARE. #include "augmentations/color_augmentations/node_vignette.h" #include "augmentations/effects_augmentations/node_jitter.h" #include "augmentations/effects_augmentations/node_snp_noise.h" +#include "augmentations/effects_augmentations/node_gaussian_noise.h" +#include "augmentations/effects_augmentations/node_shot_noise.h" #include "augmentations/effects_augmentations/node_snow.h" #include "augmentations/effects_augmentations/node_rain.h" +#include "augmentations/effects_augmentations/node_spatter.h" +#include "augmentations/effects_augmentations/node_water.h" #include "augmentations/color_augmentations/node_color_temperature.h" #include "augmentations/effects_augmentations/node_fog.h" #include "augmentations/effects_augmentations/node_pixelate.h" @@ -44,6 +48,7 @@ THE SOFTWARE. #include "augmentations/geometry_augmentations/node_resize.h" #include "augmentations/geometry_augmentations/node_rotate.h" #include "augmentations/color_augmentations/node_color_twist.h" +#include "augmentations/color_augmentations/node_color_jitter.h" #include "augmentations/color_augmentations/node_hue.h" #include "augmentations/color_augmentations/node_saturation.h" #include "augmentations/geometry_augmentations/node_crop_mirror_normalize.h" @@ -69,3 +74,4 @@ THE SOFTWARE. #include "augmentations/audio_augmentations/node_mel_filter_bank.h" #include "augmentations/geometry_augmentations/node_transpose.h" #include "augmentations/arithmetic_augmentations/node_log1p.h" +#include "augmentations/arithmetic_augmentations/node_log.h" diff --git a/rocAL/include/augmentations/color_augmentations/node_color_jitter.h b/rocAL/include/augmentations/color_augmentations/node_color_jitter.h new file mode 100644 index 000000000..f155729bb --- /dev/null +++ b/rocAL/include/augmentations/color_augmentations/node_color_jitter.h @@ -0,0 +1,50 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once + +#include "pipeline/graph.h" +#include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" + +class ColorJitterNode : public Node { + public: + ColorJitterNode(const std::vector &inputs, const std::vector &outputs); + ColorJitterNode() = delete; + void init(float brightness, float contrast, float hue, float saturation); + void init(FloatParam *brightness_param, FloatParam *contrast_param, FloatParam *hue_param, FloatParam *saturation_param); + + protected: + void create_node() override; + void update_node() override; + + private: + ParameterVX _brightness; + ParameterVX _contrast; + ParameterVX _hue; + ParameterVX _saturation; + constexpr static float BRIGHTNESS_RANGE[2] = {0.0f, 20.0f}; + constexpr static float CONTRAST_RANGE[2] = {0.0f, 255.0f}; + constexpr static float HUE_RANGE[2] = {0.0f, 359.0f}; + constexpr static float SATURATION_RANGE[2] = {0.0f, 10.0f}; +}; diff --git a/rocAL/include/augmentations/effects_augmentations/node_gaussian_noise.h b/rocAL/include/augmentations/effects_augmentations/node_gaussian_noise.h new file mode 100644 index 000000000..44d1dc823 --- /dev/null +++ b/rocAL/include/augmentations/effects_augmentations/node_gaussian_noise.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once + +#include "pipeline/graph.h" +#include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" + +class GaussianNoiseNode : public Node { + public: + GaussianNoiseNode(const std::vector &inputs, const std::vector &outputs); + GaussianNoiseNode() = delete; + void init(float mean, float stddev, int seed); + void init(FloatParam *mean_param, FloatParam *stddev_param, int seed); + + protected: + void create_node() override; + void update_node() override; + + private: + ParameterVX _mean, _stddev; + constexpr static float MEAN_RANGE[2] = {0.0, 1.0}; + constexpr static float STDDEV_RANGE[2] = {0.0, 1.0}; + int _seed; +}; diff --git a/rocAL/include/augmentations/effects_augmentations/node_shot_noise.h b/rocAL/include/augmentations/effects_augmentations/node_shot_noise.h new file mode 100644 index 000000000..99c70e75f --- /dev/null +++ b/rocAL/include/augmentations/effects_augmentations/node_shot_noise.h @@ -0,0 +1,45 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once + +#include "pipeline/graph.h" +#include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" + +class ShotNoiseNode : public Node { + public: + ShotNoiseNode(const std::vector &inputs, const std::vector &outputs); + ShotNoiseNode() = delete; + void init(float noise_factor, int seed); + void init(FloatParam *noise_factor_param, int seed); + + protected: + void create_node() override; + void update_node() override; + + private: + ParameterVX _noise_factor; + constexpr static float NOISE_FACTOR_RANGE[2] = {0.0, 1.0}; + int _seed; +}; diff --git a/rocAL/include/augmentations/effects_augmentations/node_spatter.h b/rocAL/include/augmentations/effects_augmentations/node_spatter.h new file mode 100644 index 000000000..3c4e499bb --- /dev/null +++ b/rocAL/include/augmentations/effects_augmentations/node_spatter.h @@ -0,0 +1,43 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once + +#include + +#include "pipeline/graph.h" +#include "pipeline/node.h" + +class SpatterNode : public Node { + public: + SpatterNode(const std::vector &inputs, const std::vector &outputs); + SpatterNode() = delete; + void init(uint8_t red, uint8_t green, uint8_t blue); + + protected: + void create_node() override; + void update_node() override {} + + private: + std::array _color; + vx_array _color_array; +}; diff --git a/rocAL/include/augmentations/effects_augmentations/node_water.h b/rocAL/include/augmentations/effects_augmentations/node_water.h new file mode 100644 index 000000000..c06fddf8d --- /dev/null +++ b/rocAL/include/augmentations/effects_augmentations/node_water.h @@ -0,0 +1,52 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once + +#include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" + +class WaterNode : public Node { + public: + WaterNode(const std::vector &inputs, const std::vector &outputs); + WaterNode() = delete; + void init(float amplitude_x, float amplitude_y, float frequency_x, float frequency_y, float phase_x, float phase_y); + void init(FloatParam *amplitude_x_param, FloatParam *amplitude_y_param, + FloatParam *frequency_x_param, FloatParam *frequency_y_param, + FloatParam *phase_x_param, FloatParam *phase_y_param); + + protected: + void create_node() override; + void update_node() override; + + private: + ParameterVX _amplitude_x; + ParameterVX _amplitude_y; + ParameterVX _frequency_x; + ParameterVX _frequency_y; + ParameterVX _phase_x; + ParameterVX _phase_y; + constexpr static float AMPLITUDE_RANGE[2] = {0.0, 10.0}; + constexpr static float FREQUENCY_RANGE[2] = {0.0, 1.0}; + constexpr static float PHASE_RANGE[2] = {0.0, 6.28318}; // 0 to 2*PI +}; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 4789bb2bd..cb5fe7fc4 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -1110,6 +1110,123 @@ rocalSnPNoiseFixed( return output; } +RocalTensor ROCAL_API_CALL +rocalGaussianNoise( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_mean, + RocalFloatParam p_stddev, + int seed, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto mean = static_cast(p_mean); + auto stddev = static_cast(p_stddev); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(mean, stddev, seed); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalGaussianNoiseFixed( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + float mean, + float stddev, + int seed, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(mean, stddev, seed); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalShotNoise( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_noise_factor, + int seed, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto noise_factor = static_cast(p_noise_factor); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(noise_factor, seed); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalShotNoiseFixed( + RocalContext p_context, + RocalTensor p_input, + float noise_factor, + bool is_output, + int seed, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(noise_factor, seed); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalFlip( RocalContext p_context, @@ -1350,6 +1467,37 @@ rocalRainFixed( return output; } +RocalTensor ROCAL_API_CALL +rocalSpatter( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + uint8_t red, + uint8_t green, + uint8_t blue, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + if (op_tensor_layout == RocalTensorlayout::NONE) + op_tensor_layout = input->info().layout(); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(red, green, blue); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalColorTemp( RocalContext p_context, @@ -1405,6 +1553,74 @@ rocalColorTempFixed( return output; } +RocalTensor ROCAL_API_CALL +rocalColorJitter( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_brightness, + RocalFloatParam p_contrast, + RocalFloatParam p_hue, + RocalFloatParam p_saturation, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto brightness = static_cast(p_brightness); + auto contrast = static_cast(p_contrast); + auto hue = static_cast(p_hue); + auto saturation = static_cast(p_saturation); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + if (op_tensor_layout == RocalTensorlayout::NONE) + op_tensor_layout = input->info().layout(); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(brightness, contrast, hue, saturation); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalColorJitterFixed( + RocalContext p_context, + RocalTensor p_input, + float brightness, + float contrast, + float hue, + float saturation, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + if (op_tensor_layout == RocalTensorlayout::NONE) + op_tensor_layout = input->info().layout(); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(brightness, contrast, hue, saturation); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + RocalTensor ROCAL_API_CALL rocalFog( RocalContext p_context, @@ -2436,3 +2652,97 @@ RocalTensor rocalLog1p(RocalContext p_context, } return output; } + +RocalTensor rocalLog(RocalContext p_context, + RocalTensor p_input, + bool is_output) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorDataType op_tensor_data_type = RocalTensorDataType::FP32; + TensorInfo output_info = input->info(); + output_info.set_data_type(op_tensor_data_type); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output}); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalWater( + RocalContext p_context, + RocalTensor p_input, + bool is_output, + RocalFloatParam p_amplitude_x, + RocalFloatParam p_amplitude_y, + RocalFloatParam p_frequency_x, + RocalFloatParam p_frequency_y, + RocalFloatParam p_phase_x, + RocalFloatParam p_phase_y, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto amplitude_x = static_cast(p_amplitude_x); + auto amplitude_y = static_cast(p_amplitude_y); + auto frequency_x = static_cast(p_frequency_x); + auto frequency_y = static_cast(p_frequency_y); + auto phase_x = static_cast(p_phase_x); + auto phase_y = static_cast(p_phase_y); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + if (op_tensor_layout == RocalTensorlayout::NONE) + op_tensor_layout = input->info().layout(); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(amplitude_x, amplitude_y, frequency_x, frequency_y, phase_x, phase_y); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalWaterFixed( + RocalContext p_context, + RocalTensor p_input, + float amplitude_x, + float amplitude_y, + float frequency_x, + float frequency_y, + float phase_x, + float phase_y, + bool is_output, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + try { + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + if (op_tensor_layout == RocalTensorlayout::NONE) + op_tensor_layout = input->info().layout(); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(amplitude_x, amplitude_y, frequency_x, frequency_y, phase_x, phase_y); + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} diff --git a/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp b/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp new file mode 100644 index 000000000..dc2e07fa0 --- /dev/null +++ b/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp @@ -0,0 +1,40 @@ +/* +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "augmentations/arithmetic_augmentations/node_log.h" + +#include + +#include "pipeline/exception.h" + +LogNode::LogNode(const std::vector &inputs, const std::vector &outputs) : Node(inputs, outputs) {} + +void LogNode::create_node() { + if (_node) + return; + int input_layout = static_cast(_inputs[0]->info().layout()); + vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + _node = vxExtRppLog(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), input_layout_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the (vxExtRppLog) node failed: " + TOSTR(status)) +} diff --git a/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp b/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp new file mode 100644 index 000000000..3b9b159b5 --- /dev/null +++ b/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp @@ -0,0 +1,79 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include + +#include "augmentations/color_augmentations/node_color_jitter.h" +#include "pipeline/exception.h" + +ColorJitterNode::ColorJitterNode(const std::vector &inputs, const std::vector &outputs) + : Node(inputs, outputs), + _brightness(BRIGHTNESS_RANGE[0], BRIGHTNESS_RANGE[1]), + _contrast(CONTRAST_RANGE[0], CONTRAST_RANGE[1]), + _hue(HUE_RANGE[0], HUE_RANGE[1]), + _saturation(SATURATION_RANGE[0], SATURATION_RANGE[1]) {} + +void ColorJitterNode::create_node() { + if (_node) + return; + + _brightness.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _contrast.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _hue.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _saturation.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + + _node = vxExtRppColorJitter(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), + _brightness.default_array(), _contrast.default_array(), + _hue.default_array(), _saturation.default_array(), + input_layout_vx, output_layout_vx, roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the ColorJitter (vxExtRppColorJitter) node failed: " + TOSTR(status)); +} + +void ColorJitterNode::init(float brightness, float contrast, float hue, float saturation) { + _brightness.set_param(brightness); + _contrast.set_param(contrast); + _hue.set_param(hue); + _saturation.set_param(saturation); +} + +void ColorJitterNode::init(FloatParam *brightness_param, FloatParam *contrast_param, FloatParam *hue_param, FloatParam *saturation_param) { + _brightness.set_param(core(brightness_param)); + _contrast.set_param(core(contrast_param)); + _hue.set_param(core(hue_param)); + _saturation.set_param(core(saturation_param)); +} + +void ColorJitterNode::update_node() { + _brightness.update_array(); + _contrast.update_array(); + _hue.update_array(); + _saturation.update_array(); +} diff --git a/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp b/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp new file mode 100644 index 000000000..f3bab537f --- /dev/null +++ b/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp @@ -0,0 +1,67 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/effects_augmentations/node_gaussian_noise.h" +#include "pipeline/exception.h" + +GaussianNoiseNode::GaussianNoiseNode(const std::vector& inputs, const std::vector& outputs) : Node(inputs, outputs), + _mean(MEAN_RANGE[0], MEAN_RANGE[1]), + _stddev(STDDEV_RANGE[0], STDDEV_RANGE[1]) {} + +void GaussianNoiseNode::create_node() { + if (_node) + return; + + _mean.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _stddev.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + vx_scalar seed = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_UINT32, &_seed); + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + + _node = vxExtRppGaussianNoise(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), _mean.default_array(), _stddev.default_array(), + seed, input_layout_vx, output_layout_vx, roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the GaussianNoise (vxExtRppGaussianNoise) node failed: " + TOSTR(status)) +} + +void GaussianNoiseNode::init(float mean, float stddev, int seed) { + _mean.set_param(mean); + _stddev.set_param(stddev); + _seed = seed; +} + +void GaussianNoiseNode::init(FloatParam* mean_param, FloatParam* stddev_param, int seed) { + _mean.set_param(core(mean_param)); + _stddev.set_param(core(stddev_param)); + _seed = seed; +} + +void GaussianNoiseNode::update_node() { + _mean.update_array(); + _stddev.update_array(); +} diff --git a/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp b/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp new file mode 100644 index 000000000..091e38ffa --- /dev/null +++ b/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp @@ -0,0 +1,62 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/effects_augmentations/node_shot_noise.h" +#include "pipeline/exception.h" + +ShotNoiseNode::ShotNoiseNode(const std::vector& inputs, const std::vector& outputs) : Node(inputs, outputs), + _noise_factor(NOISE_FACTOR_RANGE[0], NOISE_FACTOR_RANGE[1]) {} + +void ShotNoiseNode::create_node() { + if (_node) + return; + + _noise_factor.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + vx_scalar seed = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_UINT32, &_seed); + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + + _node = vxExtRppShotNoise(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), _noise_factor.default_array(), + seed, input_layout_vx, output_layout_vx, roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the ShotNoise (vxExtRppShotNoise) node failed: " + TOSTR(status)) +} + +void ShotNoiseNode::init(float noise_factor, int seed) { + _noise_factor.set_param(noise_factor); + _seed = seed; +} + +void ShotNoiseNode::init(FloatParam* noise_factor_param, int seed) { + _noise_factor.set_param(core(noise_factor_param)); + _seed = seed; +} + +void ShotNoiseNode::update_node() { + _noise_factor.update_array(); +} diff --git a/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp b/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp new file mode 100644 index 000000000..30e525532 --- /dev/null +++ b/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp @@ -0,0 +1,55 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include + +#include "augmentations/effects_augmentations/node_spatter.h" +#include "pipeline/exception.h" + +SpatterNode::SpatterNode(const std::vector &inputs, const std::vector &outputs) + : Node(inputs, outputs), _color{0, 0, 0}, _color_array(nullptr) {} + +void SpatterNode::create_node() { + if (_node) + return; + + vx_context context = vxGetContext((vx_reference)_graph->get()); + _color_array = vxCreateArray(context, VX_TYPE_UINT8, 3); + vxAddArrayItems(_color_array, 3, _color.data(), sizeof(uint8_t)); + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + vx_scalar input_layout_vx = vxCreateScalar(context, VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(context, VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(context, VX_TYPE_INT32, &roi_type); + + _node = vxExtRppSpatter(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), + _color_array, input_layout_vx, output_layout_vx, roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the Spatter (vxExtRppSpatter) node failed: " + TOSTR(status)); +} + +void SpatterNode::init(uint8_t red, uint8_t green, uint8_t blue) { + _color = {red, green, blue}; +} diff --git a/rocAL/source/augmentations/effects_augmentations/node_water.cpp b/rocAL/source/augmentations/effects_augmentations/node_water.cpp new file mode 100644 index 000000000..96411c374 --- /dev/null +++ b/rocAL/source/augmentations/effects_augmentations/node_water.cpp @@ -0,0 +1,90 @@ +/* +Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "augmentations/effects_augmentations/node_water.h" +#include "pipeline/exception.h" + +WaterNode::WaterNode(const std::vector &inputs, const std::vector &outputs) : Node(inputs, outputs), + _amplitude_x(AMPLITUDE_RANGE[0], AMPLITUDE_RANGE[1]), + _amplitude_y(AMPLITUDE_RANGE[0], AMPLITUDE_RANGE[1]), + _frequency_x(FREQUENCY_RANGE[0], FREQUENCY_RANGE[1]), + _frequency_y(FREQUENCY_RANGE[0], FREQUENCY_RANGE[1]), + _phase_x(PHASE_RANGE[0], PHASE_RANGE[1]), + _phase_y(PHASE_RANGE[0], PHASE_RANGE[1]) {} + +void WaterNode::create_node() { + if (_node) + return; + + _amplitude_x.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _amplitude_y.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _frequency_x.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _frequency_y.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _phase_x.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + _phase_y.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); + + int input_layout = static_cast(_inputs[0]->info().layout()); + int output_layout = static_cast(_outputs[0]->info().layout()); + int roi_type = static_cast(_inputs[0]->info().roi_type()); + vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); + vx_scalar output_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &output_layout); + vx_scalar roi_type_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &roi_type); + + _node = vxExtRppWater(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), + _amplitude_x.default_array(), _amplitude_y.default_array(), + _frequency_x.default_array(), _frequency_y.default_array(), + _phase_x.default_array(), _phase_y.default_array(), + input_layout_vx, output_layout_vx, roi_type_vx); + vx_status status; + if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) + THROW("Adding the water (vxExtRppWater) node failed: " + TOSTR(status)) +} + +void WaterNode::init(float amplitude_x, float amplitude_y, float frequency_x, float frequency_y, float phase_x, float phase_y) { + _amplitude_x.set_param(amplitude_x); + _amplitude_y.set_param(amplitude_y); + _frequency_x.set_param(frequency_x); + _frequency_y.set_param(frequency_y); + _phase_x.set_param(phase_x); + _phase_y.set_param(phase_y); +} + +void WaterNode::init(FloatParam *amplitude_x_param, FloatParam *amplitude_y_param, + FloatParam *frequency_x_param, FloatParam *frequency_y_param, + FloatParam *phase_x_param, FloatParam *phase_y_param) { + _amplitude_x.set_param(core(amplitude_x_param)); + _amplitude_y.set_param(core(amplitude_y_param)); + _frequency_x.set_param(core(frequency_x_param)); + _frequency_y.set_param(core(frequency_y_param)); + _phase_x.set_param(core(phase_x_param)); + _phase_y.set_param(core(phase_y_param)); +} + +void WaterNode::update_node() { + _amplitude_x.update_array(); + _amplitude_y.update_array(); + _frequency_x.update_array(); + _frequency_y.update_array(); + _phase_x.update_array(); + _phase_y.update_array(); +} diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index f9b2d1e7d..48e136cce 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1123,6 +1123,72 @@ def snp_noise(*inputs, p_noise=0.0, p_salt=0.0, noise_val=0.0, salt_val=0.0, return (snp_noise_added_image) +def gaussian_noise(*inputs, mean=0.0, stddev=0.1, seed=0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies Gaussian noise to the input image. + + @param inputs (list) The input image to which Gaussian noise is applied. + @param mean (float, optional, default = 0.0) Mean value for the Gaussian noise distribution. Default is 0.0. + @param stddev (float, optional, default = 0.1) Standard deviation for the Gaussian noise distribution. Default is 0.1. + @param seed (int, optional, default = 0) Random seed. Default is 0. + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) Tensor layout for the augmentation output. Default is types.NHWC. + @param output_dtype (int, optional, default = types.UINT8) Tensor dtype for the augmentation output. Default is types.UINT8. + + @return images with Gaussian noise added. + """ + mean = b.createFloatParameter(mean) if isinstance(mean, float) else mean + stddev = b.createFloatParameter(stddev) if isinstance(stddev, float) else stddev + + # pybind call arguments + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "mean": mean, "stddev": stddev, + "seed": seed, "output_layout": output_layout, "output_dtype": output_dtype} + gaussian_noise_added_image = b.gaussianNoise( + Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (gaussian_noise_added_image) + + +def shot_noise(*inputs, noise_factor=0.1, seed=0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies shot (Poisson) noise to the input image. + + @param inputs (list) The input image to which shot noise is applied. + @param noise_factor (float, optional, default = 0.1) Noise intensity factor for shot (Poisson) noise. Default is 0.1. + @param seed (int, optional, default = 0) Random seed. Default is 0. + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) Tensor layout for the augmentation output. Default is types.NHWC. + @param output_dtype (int, optional, default = types.UINT8) Tensor dtype for the augmentation output. Default is types.UINT8. + + @return images with shot noise added. + """ + noise_factor = b.createFloatParameter(noise_factor) if isinstance(noise_factor, float) else noise_factor + + # pybind call arguments + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "noise_factor": noise_factor, + "seed": seed, "output_layout": output_layout, "output_dtype": output_dtype} + shot_noise_added_image = b.shotNoise( + Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (shot_noise_added_image) + + +def spatter(*inputs, red=65, green=50, blue=23, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies spatter effect to the input image with a specified color. + + @param inputs (list) The input image to which the spatter effect is applied. + @param red (int, optional, default = 65) Red channel value for the spatter color. + @param green (int, optional, default = 50) Green channel value for the spatter color. + @param blue (int, optional, default = 23) Blue channel value for the spatter color. + @param device (string, optional, default = None) Parameter unused for augmentation. + @param output_layout (int, optional, default = types.NHWC) Tensor layout for the augmentation output. + @param output_dtype (int, optional, default = types.UINT8) Tensor dtype for the augmentation output. + + @return Image with spatter effect applied. + """ + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "red": red, "green": green, "blue": blue, + "output_layout": output_layout, "output_dtype": output_dtype} + spatter_image = b.spatter( + Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (spatter_image) + + def box_iou_matcher(*inputs, anchors, high_threshold=0.5, low_threshold=0.4, allow_low_quality_matches=True, device=None): """!Applies box IoU matching to the input image. @@ -1312,3 +1378,72 @@ def log1p(*inputs, output_datatype = types.FLOAT): kwargs_pybind = {"input_tensor": inputs[0], "is_output": False} log_output = b.log1p(Pipeline._current_pipeline._handle ,*(kwargs_pybind.values())) return log_output + + +def log(*inputs, output_datatype = types.FLOAT): + """ + Computes the natural logarithm of input element-wise. + """ + kwargs_pybind = {"input_tensor": inputs[0], "is_output": False} + log_output = b.log(Pipeline._current_pipeline._handle ,*(kwargs_pybind.values())) + return log_output + + +def color_jitter(*inputs, brightness=1.0, contrast=1.0, hue=0.0, saturation=1.0, + device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies color jitter to the input image. + + @param inputs (list) The input image to which color jitter is applied. + @param brightness (float, optional, default = 1.0) Brightness adjustment factor. + @param contrast (float, optional, default = 1.0) Contrast adjustment factor. + @param hue (float, optional, default = 0.0) Hue adjustment value in degrees. + @param saturation (float, optional, default = 1.0) Saturation adjustment factor. + @param device (string, optional, default = None) Parameter unused for augmentation. + @param output_layout (int, optional, default = types.NHWC) Tensor layout for the augmentation output. + @param output_dtype (int, optional, default = types.UINT8) Tensor dtype for the augmentation output. + + @return Image with color jitter applied. + """ + brightness = b.createFloatParameter(brightness) if isinstance(brightness, float) else brightness + contrast = b.createFloatParameter(contrast) if isinstance(contrast, float) else contrast + hue = b.createFloatParameter(hue) if isinstance(hue, float) else hue + saturation = b.createFloatParameter(saturation) if isinstance(saturation, float) else saturation + + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "brightness": brightness, "contrast": contrast, + "hue": hue, "saturation": saturation, "output_layout": output_layout, "output_dtype": output_dtype} + jittered_image = b.colorJitter( + Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (jittered_image) + + +def water(*inputs, amplitude_x=5.0, amplitude_y=5.0, frequency_x=0.5, frequency_y=0.5, + phase_x=0.0, phase_y=0.0, device=None, output_layout=types.NHWC, output_dtype=types.UINT8): + """!Applies water effect to the input image. + + @param inputs (list) The input image to which water effect is applied. + @param amplitude_x (float, optional, default = 5.0) Amplitude of the water effect in the x direction. Default is 5.0. + @param amplitude_y (float, optional, default = 5.0) Amplitude of the water effect in the y direction. Default is 5.0. + @param frequency_x (float, optional, default = 0.5) Frequency of the water effect in the x direction. Default is 0.5. + @param frequency_y (float, optional, default = 0.5) Frequency of the water effect in the y direction. Default is 0.5. + @param phase_x (float, optional, default = 0.0) Phase of the water effect in the x direction. Default is 0.0. + @param phase_y (float, optional, default = 0.0) Phase of the water effect in the y direction. Default is 0.0. + @param device (string, optional, default = None) Parameter unused for augmentation + @param output_layout (int, optional, default = types.NHWC) Tensor layout for the augmentation output. Default is types.NHWC. + @param output_dtype (int, optional, default = types.UINT8) Tensor dtype for the augmentation output. Default is types.UINT8. + + @return images with water effect applied. + """ + amplitude_x = b.createFloatParameter(amplitude_x) if isinstance(amplitude_x, float) else amplitude_x + amplitude_y = b.createFloatParameter(amplitude_y) if isinstance(amplitude_y, float) else amplitude_y + frequency_x = b.createFloatParameter(frequency_x) if isinstance(frequency_x, float) else frequency_x + frequency_y = b.createFloatParameter(frequency_y) if isinstance(frequency_y, float) else frequency_y + phase_x = b.createFloatParameter(phase_x) if isinstance(phase_x, float) else phase_x + phase_y = b.createFloatParameter(phase_y) if isinstance(phase_y, float) else phase_y + + # pybind call arguments + kwargs_pybind = {"input_image": inputs[0], "is_output": False, "amplitude_x": amplitude_x, "amplitude_y": amplitude_y, + "frequency_x": frequency_x, "frequency_y": frequency_y, "phase_x": phase_x, "phase_y": phase_y, + "output_layout": output_layout, "output_dtype": output_dtype} + water_image = b.water( + Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (water_image) diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index 10a7a6c1f..a36631a1e 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -1125,6 +1125,12 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("snpNoise", &rocalSnPNoise, py::return_value_policy::reference); + m.def("gaussianNoise", &rocalGaussianNoise, + py::return_value_policy::reference); + m.def("shotNoise", &rocalShotNoise, + py::return_value_policy::reference); + m.def("water", &rocalWater, + py::return_value_policy::reference); m.def("exposure", &rocalExposure, py::return_value_policy::reference); m.def("pixelate", &rocalPixelate, @@ -1135,6 +1141,10 @@ py::class_(m, "rocalListOfTensorList") py::return_value_policy::reference); m.def("colorTemp", &rocalColorTemp, py::return_value_policy::reference); + m.def("colorJitter", &rocalColorJitter, + py::return_value_policy::reference); + m.def("spatter", &rocalSpatter, + py::return_value_policy::reference); m.def("lensCorrection", &rocalLensCorrection, py::return_value_policy::reference); m.def("preEmphasisFilter", &rocalPreEmphasisFilter, @@ -1164,6 +1174,8 @@ py::class_(m, "rocalListOfTensorList") m.def("transpose", &rocalTranspose, py::return_value_policy::reference); m.def("log1p", &rocalLog1p, - py::return_value_policy::reference); + py::return_value_policy::reference); + m.def("log", &rocalLog, + py::return_value_policy::reference); } } // namespace rocal From 60d5be852996813819f183748a23add935de1d1a Mon Sep 17 00:00:00 2001 From: SundarRajan28 Date: Thu, 8 Jan 2026 12:55:19 -0600 Subject: [PATCH 65/77] Add VX_EXT_RPP version check for Set 1 augmentation APIs --- rocAL/source/api/rocal_api_augmentation.cpp | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index cb5fe7fc4..7df8b4ab5 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -20,6 +20,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include "meta_data/augmentations_meta_nodes.h" #include "augmentations/augmentations_nodes.h" #include "pipeline/commons.h" @@ -1128,6 +1129,7 @@ rocalGaussianNoise( auto mean = static_cast(p_mean); auto stddev = static_cast(p_stddev); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1135,6 +1137,9 @@ rocalGaussianNoise( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(mean, stddev, seed); +#else + THROW("rocalGaussianNoise requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1157,6 +1162,7 @@ rocalGaussianNoiseFixed( auto context = static_cast(p_context); auto input = static_cast(p_input); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1164,6 +1170,9 @@ rocalGaussianNoiseFixed( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(mean, stddev, seed); +#else + THROW("rocalGaussianNoiseFixed requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1186,6 +1195,7 @@ rocalShotNoise( auto input = static_cast(p_input); auto noise_factor = static_cast(p_noise_factor); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1193,6 +1203,9 @@ rocalShotNoise( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(noise_factor, seed); +#else + THROW("rocalShotNoise requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1214,6 +1227,7 @@ rocalShotNoiseFixed( auto context = static_cast(p_context); auto input = static_cast(p_input); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1221,6 +1235,9 @@ rocalShotNoiseFixed( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(noise_factor, seed); +#else + THROW("rocalShotNoiseFixed requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1483,6 +1500,7 @@ rocalSpatter( auto context = static_cast(p_context); auto input = static_cast(p_input); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1492,6 +1510,9 @@ rocalSpatter( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(red, green, blue); +#else + THROW("rocalSpatter requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1574,6 +1595,7 @@ rocalColorJitter( auto hue = static_cast(p_hue); auto saturation = static_cast(p_saturation); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1583,6 +1605,9 @@ rocalColorJitter( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(brightness, contrast, hue, saturation); +#else + THROW("rocalColorJitter requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1606,6 +1631,7 @@ rocalColorJitterFixed( auto context = static_cast(p_context); auto input = static_cast(p_input); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1615,6 +1641,9 @@ rocalColorJitterFixed( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(brightness, contrast, hue, saturation); +#else + THROW("rocalColorJitterFixed requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2662,11 +2691,15 @@ RocalTensor rocalLog(RocalContext p_context, auto context = static_cast(p_context); auto input = static_cast(p_input); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorDataType op_tensor_data_type = RocalTensorDataType::FP32; TensorInfo output_info = input->info(); output_info.set_data_type(op_tensor_data_type); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output}); +#else + THROW("rocalLog requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2698,6 +2731,7 @@ rocalWater( auto phase_x = static_cast(p_phase_x); auto phase_y = static_cast(p_phase_y); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -2707,6 +2741,9 @@ rocalWater( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(amplitude_x, amplitude_y, frequency_x, frequency_y, phase_x, phase_y); +#else + THROW("rocalWater requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2732,6 +2769,7 @@ rocalWaterFixed( auto context = static_cast(p_context); auto input = static_cast(p_input); try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -2741,6 +2779,9 @@ rocalWaterFixed( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(amplitude_x, amplitude_y, frequency_x, frequency_y, phase_x, phase_y); +#else + THROW("rocalWaterFixed requires amd_rpp version >= 3.2.0"); +#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } From 39f8043e037ddbddf1086108d27fd4d58962dfc4 Mon Sep 17 00:00:00 2001 From: SundarRajan28 Date: Thu, 8 Jan 2026 13:08:56 -0600 Subject: [PATCH 66/77] Update vx_rpp version checks to 3.1.5 for Set 1 augmentations - Update VX_EXT_RPP_CHECK_VERSION to (3, 1, 5) in API file - Update THROW messages to indicate vx_rpp >= 3.1.5 - Add version checks in node files: node_gaussian_noise.cpp, node_shot_noise.cpp, node_spatter.cpp, node_water.cpp, node_color_jitter.cpp, node_log.cpp --- rocAL/source/api/rocal_api_augmentation.cpp | 40 +++++++++---------- .../arithmetic_augmentations/node_log.cpp | 6 +++ .../color_augmentations/node_color_jitter.cpp | 5 +++ .../node_gaussian_noise.cpp | 5 +++ .../effects_augmentations/node_shot_noise.cpp | 5 +++ .../effects_augmentations/node_spatter.cpp | 5 +++ .../effects_augmentations/node_water.cpp | 7 +++- 7 files changed, 52 insertions(+), 21 deletions(-) diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 7df8b4ab5..09fd648ba 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -1129,7 +1129,7 @@ rocalGaussianNoise( auto mean = static_cast(p_mean); auto stddev = static_cast(p_stddev); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1138,7 +1138,7 @@ rocalGaussianNoise( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(mean, stddev, seed); #else - THROW("rocalGaussianNoise requires amd_rpp version >= 3.2.0"); + THROW("rocalGaussianNoise requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -1162,7 +1162,7 @@ rocalGaussianNoiseFixed( auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1171,7 +1171,7 @@ rocalGaussianNoiseFixed( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(mean, stddev, seed); #else - THROW("rocalGaussianNoiseFixed requires amd_rpp version >= 3.2.0"); + THROW("rocalGaussianNoiseFixed requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -1195,7 +1195,7 @@ rocalShotNoise( auto input = static_cast(p_input); auto noise_factor = static_cast(p_noise_factor); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1204,7 +1204,7 @@ rocalShotNoise( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(noise_factor, seed); #else - THROW("rocalShotNoise requires amd_rpp version >= 3.2.0"); + THROW("rocalShotNoise requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -1227,7 +1227,7 @@ rocalShotNoiseFixed( auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1236,7 +1236,7 @@ rocalShotNoiseFixed( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(noise_factor, seed); #else - THROW("rocalShotNoiseFixed requires amd_rpp version >= 3.2.0"); + THROW("rocalShotNoiseFixed requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -1500,7 +1500,7 @@ rocalSpatter( auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1511,7 +1511,7 @@ rocalSpatter( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(red, green, blue); #else - THROW("rocalSpatter requires amd_rpp version >= 3.2.0"); + THROW("rocalSpatter requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -1595,7 +1595,7 @@ rocalColorJitter( auto hue = static_cast(p_hue); auto saturation = static_cast(p_saturation); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1606,7 +1606,7 @@ rocalColorJitter( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(brightness, contrast, hue, saturation); #else - THROW("rocalColorJitter requires amd_rpp version >= 3.2.0"); + THROW("rocalColorJitter requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -1631,7 +1631,7 @@ rocalColorJitterFixed( auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1642,7 +1642,7 @@ rocalColorJitterFixed( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(brightness, contrast, hue, saturation); #else - THROW("rocalColorJitterFixed requires amd_rpp version >= 3.2.0"); + THROW("rocalColorJitterFixed requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -2691,14 +2691,14 @@ RocalTensor rocalLog(RocalContext p_context, auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorDataType op_tensor_data_type = RocalTensorDataType::FP32; TensorInfo output_info = input->info(); output_info.set_data_type(op_tensor_data_type); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output}); #else - THROW("rocalLog requires amd_rpp version >= 3.2.0"); + THROW("rocalLog requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -2731,7 +2731,7 @@ rocalWater( auto phase_x = static_cast(p_phase_x); auto phase_y = static_cast(p_phase_y); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -2742,7 +2742,7 @@ rocalWater( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(amplitude_x, amplitude_y, frequency_x, frequency_y, phase_x, phase_y); #else - THROW("rocalWater requires amd_rpp version >= 3.2.0"); + THROW("rocalWater requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); @@ -2769,7 +2769,7 @@ rocalWaterFixed( auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -2780,7 +2780,7 @@ rocalWaterFixed( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(amplitude_x, amplitude_y, frequency_x, frequency_y, phase_x, phase_y); #else - THROW("rocalWaterFixed requires amd_rpp version >= 3.2.0"); + THROW("rocalWaterFixed requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); diff --git a/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp b/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp index dc2e07fa0..9caaff0a5 100644 --- a/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp +++ b/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp @@ -23,6 +23,7 @@ THE SOFTWARE. #include "augmentations/arithmetic_augmentations/node_log.h" #include +#include #include "pipeline/exception.h" @@ -31,10 +32,15 @@ LogNode::LogNode(const std::vector &inputs, const std::vector(_inputs[0]->info().layout()); vx_scalar input_layout_vx = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_INT32, &input_layout); _node = vxExtRppLog(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), input_layout_vx); vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the (vxExtRppLog) node failed: " + TOSTR(status)) +#else + THROW("LogNode: vxExtRppLog requires vx_rpp version >= 3.1.5"); +#endif } diff --git a/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp b/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp index 3b9b159b5..ea5128b1a 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/color_augmentations/node_color_jitter.h" #include "pipeline/exception.h" @@ -36,6 +37,7 @@ void ColorJitterNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) _brightness.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); _contrast.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); _hue.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); @@ -55,6 +57,9 @@ void ColorJitterNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the ColorJitter (vxExtRppColorJitter) node failed: " + TOSTR(status)); +#else + THROW("ColorJitterNode: vxExtRppColorJitter requires vx_rpp version >= 3.1.5"); +#endif } void ColorJitterNode::init(float brightness, float contrast, float hue, float saturation) { diff --git a/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp b/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp index f3bab537f..b32f42aed 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/effects_augmentations/node_gaussian_noise.h" #include "pipeline/exception.h" @@ -32,6 +33,7 @@ void GaussianNoiseNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) _mean.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); _stddev.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); vx_scalar seed = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_UINT32, &_seed); @@ -47,6 +49,9 @@ void GaussianNoiseNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the GaussianNoise (vxExtRppGaussianNoise) node failed: " + TOSTR(status)) +#else + THROW("GaussianNoiseNode: vxExtRppGaussianNoise requires vx_rpp version >= 3.1.5"); +#endif } void GaussianNoiseNode::init(float mean, float stddev, int seed) { diff --git a/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp b/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp index 091e38ffa..9308b0ef5 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/effects_augmentations/node_shot_noise.h" #include "pipeline/exception.h" @@ -31,6 +32,7 @@ void ShotNoiseNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) _noise_factor.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); vx_scalar seed = vxCreateScalar(vxGetContext((vx_reference)_graph->get()), VX_TYPE_UINT32, &_seed); int input_layout = static_cast(_inputs[0]->info().layout()); @@ -45,6 +47,9 @@ void ShotNoiseNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the ShotNoise (vxExtRppShotNoise) node failed: " + TOSTR(status)) +#else + THROW("ShotNoiseNode: vxExtRppShotNoise requires vx_rpp version >= 3.1.5"); +#endif } void ShotNoiseNode::init(float noise_factor, int seed) { diff --git a/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp b/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp index 30e525532..5fe8560bd 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/effects_augmentations/node_spatter.h" #include "pipeline/exception.h" @@ -32,6 +33,7 @@ void SpatterNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) vx_context context = vxGetContext((vx_reference)_graph->get()); _color_array = vxCreateArray(context, VX_TYPE_UINT8, 3); vxAddArrayItems(_color_array, 3, _color.data(), sizeof(uint8_t)); @@ -48,6 +50,9 @@ void SpatterNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the Spatter (vxExtRppSpatter) node failed: " + TOSTR(status)); +#else + THROW("SpatterNode: vxExtRppSpatter requires vx_rpp version >= 3.1.5"); +#endif } void SpatterNode::init(uint8_t red, uint8_t green, uint8_t blue) { diff --git a/rocAL/source/augmentations/effects_augmentations/node_water.cpp b/rocAL/source/augmentations/effects_augmentations/node_water.cpp index 96411c374..29e9aeb33 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_water.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_water.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include +#include #include "augmentations/effects_augmentations/node_water.h" #include "pipeline/exception.h" @@ -36,13 +37,14 @@ void WaterNode::create_node() { if (_node) return; +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) _amplitude_x.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); _amplitude_y.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); _frequency_x.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); _frequency_y.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); _phase_x.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); _phase_y.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); - + int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); int roi_type = static_cast(_inputs[0]->info().roi_type()); @@ -58,6 +60,9 @@ void WaterNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the water (vxExtRppWater) node failed: " + TOSTR(status)) +#else + THROW("WaterNode: vxExtRppWater requires vx_rpp version >= 3.1.5"); +#endif } void WaterNode::init(float amplitude_x, float amplitude_y, float frequency_x, float frequency_y, float phase_x, float phase_y) { From c35b3a64b6bb1b9183b6dec7790ee173346e7e24 Mon Sep 17 00:00:00 2001 From: SundarRajan28 Date: Fri, 9 Jan 2026 01:20:41 -0600 Subject: [PATCH 67/77] Add C++ and Python tests for Set 1 augmentations C++ tests (unit_tests.cpp): - Case 64: rocalGaussianNoise (random) - Case 65: rocalGaussianNoiseFixed - Case 66: rocalShotNoise (random) - Case 67: rocalShotNoiseFixed - Case 68: rocalSpatter - Case 69: rocalLog - Case 70: rocalColorJitter (random) - Case 71: rocalColorJitterFixed - Case 72: rocalWater (random) - Case 73: rocalWaterFixed Python tests (unit_test.py): - gaussian_noise, shot_noise, spatter, water, color_jitter Shell scripts updated: - testAllScripts.sh: Added C++ test entries - unit_tests.sh: Added Python test entries --- tests/cpp_api/unit_tests/testAllScripts.sh | 14 +++++++ tests/cpp_api/unit_tests/unit_tests.cpp | 47 +++++++++++++++++++++- tests/python_api/unit_test.py | 38 +++++++++++++++++ tests/python_api/unit_tests.sh | 9 +++++ 4 files changed, 107 insertions(+), 1 deletion(-) diff --git a/tests/cpp_api/unit_tests/testAllScripts.sh b/tests/cpp_api/unit_tests/testAllScripts.sh index c7a15116c..293a5f218 100755 --- a/tests/cpp_api/unit_tests/testAllScripts.sh +++ b/tests/cpp_api/unit_tests/testAllScripts.sh @@ -223,6 +223,20 @@ do ./unit_tests 2 "$coco_detection_path" "${output_path}Nop_${rgb_name[$rgb]}_${device_name}" $width $height 61 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}ResizeMirrorNormalize_${rgb_name[$rgb]}_${device_name}" $width $height 56 $device $rgb 1 $display + # Set 1 augmentation tests - random variants + ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianNoiseRandom_${rgb_name[$rgb]}_${device_name}" $width $height 64 $device $rgb 1 $display + ./unit_tests 4 "$tf_classification_path" "${output_path}ShotNoiseRandom_${rgb_name[$rgb]}_${device_name}" $width $height 66 $device $rgb 1 $display + ./unit_tests 0 "$image_path" "${output_path}SpatterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 68 $device $rgb 0 $display + ./unit_tests 8 "$caffe2_classification_path" "${output_path}Log_${rgb_name[$rgb]}_${device_name}" $width $height 69 $device $rgb 1 $display + ./unit_tests 0 "$image_path" "${output_path}ColorJitterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 70 $device $rgb 0 $display + ./unit_tests 0 "$image_path" "${output_path}WaterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 72 $device $rgb 1 $display + + # Set 1 augmentation tests - fixed variants + ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianNoise_${rgb_name[$rgb]}_${device_name}" $width $height 65 $device $rgb 0 $display + ./unit_tests 4 "$tf_classification_path" "${output_path}ShotNoise_${rgb_name[$rgb]}_${device_name}" $width $height 67 $device $rgb 0 $display + ./unit_tests 0 "$image_path" "${output_path}ColorJitter_${rgb_name[$rgb]}_${device_name}" $width $height 71 $device $rgb 0 $display + ./unit_tests 0 "$image_path" "${output_path}Water_${rgb_name[$rgb]}_${device_name}" $width $height 73 $device $rgb 0 $display + # to_tensor coverage tests for ((memcpy_backend=0;memcpy_backend<=1;memcpy_backend++)) do diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 57097983b..ad4e55a21 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -597,7 +597,12 @@ int test(int test_case, int reader_type, const char *path, const char *outName, // RocalTensor input = rocalResize(handle, decoded_output, resize_w, resize_h, false); // uncomment when processing images of different size RocalTensor output; - if ((test_case == 48 || test_case == 49 || test_case == 50 || test_case == 21 || test_case == 22 || test_case == 24 || test_case == 16 || test_case == 43 || reader_type == 13 || reader_type == 21 || reader_type == 27 || reader_type == 28) && rgb == 0) { + if ((test_case == 48 || test_case == 49 || test_case == 50 || test_case == 21 || test_case == 22 || test_case == 24 || test_case == 16 || test_case == 43 || test_case == 70 || test_case == 71 || reader_type == 13 || reader_type == 21 || reader_type == 27 || reader_type == 28) && rgb == 0) { + std::cout << "Not a valid option! Exiting!\n"; + rocalRelease(handle); + return -1; + } + if ((test_case == 70 || test_case == 71) && gpu == 1) { std::cout << "Not a valid option! Exiting!\n"; rocalRelease(handle); return -1; @@ -884,6 +889,46 @@ int test(int test_case, int reader_type, const char *path, const char *outName, std::vector aspect_ratio = {3.0f / 4, 4.0f / 3}; output = rocalRandomResizedCrop(handle, input, resize_w, resize_h, true, area_factor, aspect_ratio); } break; + case 64: { + std::cout << "Running rocalGaussianNoise" << std::endl; + output = rocalGaussianNoise(handle, input, true); + } break; + case 65: { + std::cout << "Running rocalGaussianNoiseFixed" << std::endl; + output = rocalGaussianNoiseFixed(handle, input, 0.0f, 0.2f, true, 1255459); + } break; + case 66: { + std::cout << "Running rocalShotNoise" << std::endl; + output = rocalShotNoise(handle, input, true); + } break; + case 67: { + std::cout << "Running rocalShotNoiseFixed" << std::endl; + output = rocalShotNoiseFixed(handle, input, 80.0f, true, 1255459); + } break; + case 68: { + std::cout << "Running rocalSpatter" << std::endl; + output = rocalSpatter(handle, input, true, 65, 50, 23); + } break; + case 69: { + std::cout << "Running rocalLog" << std::endl; + output = rocalLog(handle, input, true); + } break; + case 70: { + std::cout << "Running rocalColorJitter" << std::endl; + output = rocalColorJitter(handle, input, true); + } break; + case 71: { + std::cout << "Running rocalColorJitterFixed" << std::endl; + output = rocalColorJitterFixed(handle, input, 1.02f, 1.1f, 0.02f, 1.3f, true); + } break; + case 72: { + std::cout << "Running rocalWater" << std::endl; + output = rocalWater(handle, input, true); + } break; + case 73: { + std::cout << "Running rocalWaterFixed" << std::endl; + output = rocalWaterFixed(handle, input, 2.0f, 5.0f, 5.8f, 1.2f, 10.0f, 15.0f, true); + } break; default: std::cout << "Not a valid option! Exiting!\n"; return -1; diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index bf37a84cb..9bcd41936 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -342,6 +342,19 @@ def main(): kernel_size=3, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "gaussian_noise": + output = fn.gaussian_noise(images, + mean=0.0, + stddev=0.2, + seed=1255459, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "shot_noise": + output = fn.shot_noise(images, + noise_factor=80.0, + seed=1255459, + output_layout=tensor_layout, + output_dtype=tensor_dtype) elif augmentation_name == "snp_noise": output = fn.snp_noise(images, p_noise=0.2, @@ -395,6 +408,31 @@ def main(): saturation=0.25, output_layout=tensor_layout, output_dtype=tensor_dtype) + elif augmentation_name == "spatter": + output = fn.spatter(images, + red=65, + green=50, + blue=23, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "water": + output = fn.water(images, + amplitude_x=2.0, + amplitude_y=5.0, + frequency_x=5.8, + frequency_y=1.2, + phase_x=10.0, + phase_y=15.0, + output_layout=tensor_layout, + output_dtype=tensor_dtype) + elif augmentation_name == "color_jitter": + output = fn.color_jitter(images, + brightness=1.02, + contrast=1.1, + hue=0.02, + saturation=1.3, + output_layout=tensor_layout, + output_dtype=tensor_dtype) elif augmentation_name == "crop": output = fn.crop(images, crop=(3, 224, 224), diff --git a/tests/python_api/unit_tests.sh b/tests/python_api/unit_tests.sh index db8e97f25..de951d750 100755 --- a/tests/python_api/unit_tests.sh +++ b/tests/python_api/unit_tests.sh @@ -165,6 +165,15 @@ do python"$ver" unit_test.py --image-dataset-path "$caffe2_detection_path" --reader-type "caffe2_detection" --augmentation-name resize --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --interpolation-type 5 --scaling-mode 0 --$backend_arg -f "${output_path}Resize_${rgb_name[$rgb]}_${device_name}_triangular_default_caffe2Detection" python"$ver" unit_test.py --image-dataset-path "$mxnet_path" --reader-type "mxnet" --augmentation-name resize --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --interpolation-type 4 --scaling-mode 0 --$backend_arg -f "${output_path}Resize_${rgb_name[$rgb]}_${device_name}_gaussian_default_mxnet" + # Set 1 augmentation tests + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name gaussian_noise --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}GaussianNoise_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name shot_noise --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}ShotNoise_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name spatter --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Spatter_${rgb_name[$rgb]}_${device_name}" + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name water --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Water_${rgb_name[$rgb]}_${device_name}" + if [ $rgb -eq 1 ]; then + python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name color_jitter --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}ColorJitter_${rgb_name[$rgb]}_${device_name}" + fi + # Special Case - One Hot Encoded Labels python"$ver" unit_test.py --image-dataset-path "$one_hot_data_path" --augmentation-name one_hot --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}OneHot_${rgb_name[$rgb]}_${device_name}" From 2a613023fc2be85332887564e7f88c456d5a9e19 Mon Sep 17 00:00:00 2001 From: SundarRajan28 Date: Fri, 9 Jan 2026 03:16:40 -0600 Subject: [PATCH 68/77] Fix issue with Log --- rocAL/source/api/rocal_api_augmentation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 09fd648ba..fa389b932 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -2692,7 +2692,11 @@ RocalTensor rocalLog(RocalContext p_context, auto input = static_cast(p_input); try { #if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) - RocalTensorDataType op_tensor_data_type = RocalTensorDataType::FP32; + // Preserve FP16 inputs, promote everything else to FP32 to avoid precision loss. + RocalTensorDataType input_dtype = static_cast(input->data_type()); + RocalTensorDataType op_tensor_data_type = (input_dtype == RocalTensorDataType::FP16) + ? RocalTensorDataType::FP16 + : RocalTensorDataType::FP32; TensorInfo output_info = input->info(); output_info.set_data_type(op_tensor_data_type); output = context->master_graph->create_tensor(output_info, is_output); From 4effbc0cc0b1b5373690b5cc18fffde22b0f75b6 Mon Sep 17 00:00:00 2001 From: SundarRajan28 Date: Fri, 9 Jan 2026 08:57:48 -0600 Subject: [PATCH 69/77] Unit tests fix --- tests/cpp_api/unit_tests/pixel_comparison/image_comparison.py | 4 ++-- tests/cpp_api/unit_tests/unit_tests.cpp | 2 +- tests/python_api/image_comparison.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/cpp_api/unit_tests/pixel_comparison/image_comparison.py b/tests/cpp_api/unit_tests/pixel_comparison/image_comparison.py index 074e6124d..6bd814217 100644 --- a/tests/cpp_api/unit_tests/pixel_comparison/image_comparison.py +++ b/tests/cpp_api/unit_tests/pixel_comparison/image_comparison.py @@ -82,7 +82,7 @@ def main(): failed_case_list = [] golden_output_dir_list = os.listdir(ref_output_path) rocal_output_dir_list = os.listdir(rocal_output_path) - randomized_augmentation = ["Snow", "Rain", "Jitter", "SNPNoise", "Fog"] + randomized_augmentation = ["Snow", "Rain", "Jitter", "SNPNoise", "Fog", "GaussianNoise", "ShotNoise", "Spatter"] golden_file_path = "" for aug_name in rocal_output_dir_list: temp = aug_name.split(".") @@ -94,7 +94,7 @@ def main(): golden_file_path = aug_name # For randomized augmentation - if file_name_split[0] in randomized_augmentation or "Random" in file_name_split[0]: + if file_name_split[0] in randomized_augmentation or "Random" in file_name_split[0] or "Log" in file_name_split[0]: total_case_count = total_case_count + 1 augmentation_name = aug_name.split(".")[0] logging.info("Running %s", augmentation_name) diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index ad4e55a21..28681328a 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -895,7 +895,7 @@ int test(int test_case, int reader_type, const char *path, const char *outName, } break; case 65: { std::cout << "Running rocalGaussianNoiseFixed" << std::endl; - output = rocalGaussianNoiseFixed(handle, input, 0.0f, 0.2f, true, 1255459); + output = rocalGaussianNoiseFixed(handle, input, true, 0.0f, 0.2f, 1255459); } break; case 66: { std::cout << "Running rocalShotNoise" << std::endl; diff --git a/tests/python_api/image_comparison.py b/tests/python_api/image_comparison.py index b17645aec..335a75c1c 100644 --- a/tests/python_api/image_comparison.py +++ b/tests/python_api/image_comparison.py @@ -93,7 +93,7 @@ def main(): failed_case_list = [] golden_output_dir_list = os.listdir(ref_output_path) rocal_output_dir_list = os.listdir(rocal_output_path) - randomized_augmentation = ["Snow", "Rain", "Jitter", "SNPNoise", "Fog"] + randomized_augmentation = ["Snow", "Rain", "Jitter", "SNPNoise", "Fog", "GaussianNoise", "ShotNoise", "Spatter"] spl_case_meta_data = ["OneHot"] golden_file_path = "" for aug_name in rocal_output_dir_list: From e705cf7bc7a6c9a809f3baae38ab01684f0aafab Mon Sep 17 00:00:00 2001 From: SundarRajan28 Date: Fri, 9 Jan 2026 09:40:12 -0600 Subject: [PATCH 70/77] Spatter API changes --- rocAL/include/api/rocal_api_augmentation.h | 20 ++++++++- .../effects_augmentations/node_spatter.h | 11 ++++- rocAL/source/api/rocal_api_augmentation.cpp | 40 +++++++++++++++++- .../effects_augmentations/node_spatter.cpp | 42 +++++++++++++++++-- rocAL_pybind/amd/rocal/fn.py | 3 ++ tests/cpp_api/unit_tests/testAllScripts.sh | 13 +++--- tests/cpp_api/unit_tests/unit_tests.cpp | 18 ++++---- tests/python_api/unit_tests.sh | 1 - 8 files changed, 125 insertions(+), 23 deletions(-) diff --git a/rocAL/include/api/rocal_api_augmentation.h b/rocAL/include/api/rocal_api_augmentation.h index 4d5e63e1f..5339575af 100644 --- a/rocAL/include/api/rocal_api_augmentation.h +++ b/rocAL/include/api/rocal_api_augmentation.h @@ -764,10 +764,28 @@ extern "C" RocalTensor ROCAL_API_CALL rocalRainFixed(RocalContext context, Rocal */ extern "C" RocalTensor ROCAL_API_CALL rocalSpatter(RocalContext context, RocalTensor input, bool is_output, - uint8_t red = 65, uint8_t green = 50, uint8_t blue = 23, + RocalIntParam red = NULL, RocalIntParam green = NULL, RocalIntParam blue = NULL, RocalTensorLayout output_layout = ROCAL_NONE, RocalTensorOutputType output_datatype = ROCAL_UINT8); +/*! \brief Applies spatter effect on images with fixed parameters. + * \ingroup group_rocal_augmentations + * \param [in] context Rocal context + * \param [in] input Input Rocal tensor + * \param [in] red red channel value of the spatter color + * \param [in] green green channel value of the spatter color + * \param [in] blue blue channel value of the spatter color + * \param [in] is_output is the output tensor part of the graph output + * \param [in] output_layout the layout of the output tensor + * \param [in] output_datatype the data type of the output tensor + * \return RocalTensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalSpatterFixed(RocalContext context, RocalTensor input, + uint8_t red, uint8_t green, uint8_t blue, + bool is_output, + RocalTensorLayout output_layout = ROCAL_NONE, + RocalTensorOutputType output_datatype = ROCAL_UINT8); + /*! \brief Adjusts the color temperature in images. * \ingroup group_rocal_augmentations * \param [in] context Rocal context diff --git a/rocAL/include/augmentations/effects_augmentations/node_spatter.h b/rocAL/include/augmentations/effects_augmentations/node_spatter.h index 3c4e499bb..a8a97d006 100644 --- a/rocAL/include/augmentations/effects_augmentations/node_spatter.h +++ b/rocAL/include/augmentations/effects_augmentations/node_spatter.h @@ -26,18 +26,25 @@ THE SOFTWARE. #include "pipeline/graph.h" #include "pipeline/node.h" +#include "parameters/parameter_factory.h" +#include "parameters/parameter_vx.h" class SpatterNode : public Node { public: SpatterNode(const std::vector &inputs, const std::vector &outputs); SpatterNode() = delete; void init(uint8_t red, uint8_t green, uint8_t blue); + void init(IntParam *red, IntParam *green, IntParam *blue); protected: void create_node() override; - void update_node() override {} + void update_node() override; private: - std::array _color; + ParameterVX _red_param; + ParameterVX _green_param; + ParameterVX _blue_param; + constexpr static int COLOR_RANGE[2] = {0, 255}; vx_array _color_array; + std::array _color; }; diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index fa389b932..57f053bd5 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -1489,9 +1489,47 @@ rocalSpatter( RocalContext p_context, RocalTensor p_input, bool is_output, + RocalIntParam p_red, + RocalIntParam p_green, + RocalIntParam p_blue, + RocalTensorLayout output_layout, + RocalTensorOutputType output_datatype) { + Tensor* output = nullptr; + ROCAL_INVALID_CONTEXT_ERR(p_context, output); + ROCAL_INVALID_INPUT_ERR(p_input, output); + auto context = static_cast(p_context); + auto input = static_cast(p_input); + auto red = static_cast(p_red); + auto green = static_cast(p_green); + auto blue = static_cast(p_blue); + try { +#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + RocalTensorlayout op_tensor_layout = static_cast(output_layout); + if (op_tensor_layout == RocalTensorlayout::NONE) + op_tensor_layout = input->info().layout(); + RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); + TensorInfo output_info = input->info(); + output_info.set_tensor_layout(op_tensor_layout); + output_info.set_data_type(op_tensor_datatype); + output = context->master_graph->create_tensor(output_info, is_output); + context->master_graph->add_node({input}, {output})->init(red, green, blue); +#else + THROW("rocalSpatter requires vx_rpp version >= 3.1.5"); +#endif + } catch (const std::exception& e) { + ROCAL_PRINT_EXCEPTION(context, e); + } + return output; +} + +RocalTensor ROCAL_API_CALL +rocalSpatterFixed( + RocalContext p_context, + RocalTensor p_input, uint8_t red, uint8_t green, uint8_t blue, + bool is_output, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { Tensor* output = nullptr; @@ -1511,7 +1549,7 @@ rocalSpatter( output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(red, green, blue); #else - THROW("rocalSpatter requires vx_rpp version >= 3.1.5"); + THROW("rocalSpatterFixed requires vx_rpp version >= 3.1.5"); #endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); diff --git a/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp b/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp index 5fe8560bd..79e1f0556 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp @@ -27,7 +27,12 @@ THE SOFTWARE. #include "pipeline/exception.h" SpatterNode::SpatterNode(const std::vector &inputs, const std::vector &outputs) - : Node(inputs, outputs), _color{0, 0, 0}, _color_array(nullptr) {} + : Node(inputs, outputs), + _red_param(COLOR_RANGE[0], COLOR_RANGE[1]), + _green_param(COLOR_RANGE[0], COLOR_RANGE[1]), + _blue_param(COLOR_RANGE[0], COLOR_RANGE[1]), + _color_array(nullptr), + _color({0, 0, 0}) {} void SpatterNode::create_node() { if (_node) @@ -35,8 +40,15 @@ void SpatterNode::create_node() { #if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) vx_context context = vxGetContext((vx_reference)_graph->get()); + + // Create parameter arrays for random value generation + _red_param.create_array(_graph, VX_TYPE_INT32, _batch_size); + _green_param.create_array(_graph, VX_TYPE_INT32, _batch_size); + _blue_param.create_array(_graph, VX_TYPE_INT32, _batch_size); + + // Create a single color array with 3 elements (R, G, B) _color_array = vxCreateArray(context, VX_TYPE_UINT8, 3); - vxAddArrayItems(_color_array, 3, _color.data(), sizeof(uint8_t)); + vxAddArrayItems(_color_array, 3, _color.data(), sizeof(vx_uint8)); int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); @@ -46,7 +58,7 @@ void SpatterNode::create_node() { vx_scalar roi_type_vx = vxCreateScalar(context, VX_TYPE_INT32, &roi_type); _node = vxExtRppSpatter(_graph->get(), _inputs[0]->handle(), _inputs[0]->get_roi_tensor(), _outputs[0]->handle(), - _color_array, input_layout_vx, output_layout_vx, roi_type_vx); + _color_array, input_layout_vx, output_layout_vx, roi_type_vx); vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) THROW("Adding the Spatter (vxExtRppSpatter) node failed: " + TOSTR(status)); @@ -56,5 +68,27 @@ void SpatterNode::create_node() { } void SpatterNode::init(uint8_t red, uint8_t green, uint8_t blue) { - _color = {red, green, blue}; + _red_param.set_param(static_cast(red)); + _green_param.set_param(static_cast(green)); + _blue_param.set_param(static_cast(blue)); +} + +void SpatterNode::init(IntParam *red, IntParam *green, IntParam *blue) { + _red_param.set_param(core(red)); + _green_param.set_param(core(green)); + _blue_param.set_param(core(blue)); +} + +void SpatterNode::update_node() { + // Update the parameter arrays to generate new random values if using IntParam + _red_param.update_array(); + _green_param.update_array(); + _blue_param.update_array(); + + // Get the generated values from ParameterVX and update the color array + _color[0] = static_cast(_red_param.default_value()); + _color[1] = static_cast(_green_param.default_value()); + _color[2] = static_cast(_blue_param.default_value()); + + vxCopyArrayRange(_color_array, 0, 3, sizeof(vx_uint8), _color.data(), VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); } diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 48e136cce..efe7a8a20 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1182,6 +1182,9 @@ def spatter(*inputs, red=65, green=50, blue=23, device=None, output_layout=types @return Image with spatter effect applied. """ + red = b.createIntParameter(red) if isinstance(red, int) else red + green = b.createIntParameter(green) if isinstance(green, int) else green + blue = b.createIntParameter(blue) if isinstance(blue, int) else blue kwargs_pybind = {"input_image": inputs[0], "is_output": False, "red": red, "green": green, "blue": blue, "output_layout": output_layout, "output_dtype": output_dtype} spatter_image = b.spatter( diff --git a/tests/cpp_api/unit_tests/testAllScripts.sh b/tests/cpp_api/unit_tests/testAllScripts.sh index 293a5f218..121fd527a 100755 --- a/tests/cpp_api/unit_tests/testAllScripts.sh +++ b/tests/cpp_api/unit_tests/testAllScripts.sh @@ -223,19 +223,18 @@ do ./unit_tests 2 "$coco_detection_path" "${output_path}Nop_${rgb_name[$rgb]}_${device_name}" $width $height 61 $device $rgb 1 $display ./unit_tests 2 "$coco_detection_path" "${output_path}ResizeMirrorNormalize_${rgb_name[$rgb]}_${device_name}" $width $height 56 $device $rgb 1 $display - # Set 1 augmentation tests - random variants ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianNoiseRandom_${rgb_name[$rgb]}_${device_name}" $width $height 64 $device $rgb 1 $display ./unit_tests 4 "$tf_classification_path" "${output_path}ShotNoiseRandom_${rgb_name[$rgb]}_${device_name}" $width $height 66 $device $rgb 1 $display ./unit_tests 0 "$image_path" "${output_path}SpatterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 68 $device $rgb 0 $display - ./unit_tests 8 "$caffe2_classification_path" "${output_path}Log_${rgb_name[$rgb]}_${device_name}" $width $height 69 $device $rgb 1 $display - ./unit_tests 0 "$image_path" "${output_path}ColorJitterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 70 $device $rgb 0 $display - ./unit_tests 0 "$image_path" "${output_path}WaterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 72 $device $rgb 1 $display + ./unit_tests 8 "$caffe2_classification_path" "${output_path}Log_${rgb_name[$rgb]}_${device_name}" $width $height 70 $device $rgb 1 $display + ./unit_tests 0 "$image_path" "${output_path}ColorJitterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 71 $device $rgb 0 $display + ./unit_tests 0 "$image_path" "${output_path}WaterRandom_${rgb_name[$rgb]}_${device_name}" $width $height 73 $device $rgb 1 $display - # Set 1 augmentation tests - fixed variants ./unit_tests 2 "$coco_detection_path" "${output_path}GaussianNoise_${rgb_name[$rgb]}_${device_name}" $width $height 65 $device $rgb 0 $display ./unit_tests 4 "$tf_classification_path" "${output_path}ShotNoise_${rgb_name[$rgb]}_${device_name}" $width $height 67 $device $rgb 0 $display - ./unit_tests 0 "$image_path" "${output_path}ColorJitter_${rgb_name[$rgb]}_${device_name}" $width $height 71 $device $rgb 0 $display - ./unit_tests 0 "$image_path" "${output_path}Water_${rgb_name[$rgb]}_${device_name}" $width $height 73 $device $rgb 0 $display + ./unit_tests 0 "$image_path" "${output_path}Spatter_${rgb_name[$rgb]}_${device_name}" $width $height 69 $device $rgb 0 $display + ./unit_tests 0 "$image_path" "${output_path}ColorJitter_${rgb_name[$rgb]}_${device_name}" $width $height 72 $device $rgb 0 $display + ./unit_tests 0 "$image_path" "${output_path}Water_${rgb_name[$rgb]}_${device_name}" $width $height 74 $device $rgb 0 $display # to_tensor coverage tests for ((memcpy_backend=0;memcpy_backend<=1;memcpy_backend++)) diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index 28681328a..011bc6fbf 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -597,12 +597,12 @@ int test(int test_case, int reader_type, const char *path, const char *outName, // RocalTensor input = rocalResize(handle, decoded_output, resize_w, resize_h, false); // uncomment when processing images of different size RocalTensor output; - if ((test_case == 48 || test_case == 49 || test_case == 50 || test_case == 21 || test_case == 22 || test_case == 24 || test_case == 16 || test_case == 43 || test_case == 70 || test_case == 71 || reader_type == 13 || reader_type == 21 || reader_type == 27 || reader_type == 28) && rgb == 0) { + if ((test_case == 48 || test_case == 49 || test_case == 50 || test_case == 21 || test_case == 22 || test_case == 24 || test_case == 16 || test_case == 43 || test_case == 71 || test_case == 72 || reader_type == 13 || reader_type == 21 || reader_type == 27 || reader_type == 28) && rgb == 0) { std::cout << "Not a valid option! Exiting!\n"; rocalRelease(handle); return -1; } - if ((test_case == 70 || test_case == 71) && gpu == 1) { + if ((test_case == 71 || test_case == 72) && gpu == 1) { std::cout << "Not a valid option! Exiting!\n"; rocalRelease(handle); return -1; @@ -907,25 +907,29 @@ int test(int test_case, int reader_type, const char *path, const char *outName, } break; case 68: { std::cout << "Running rocalSpatter" << std::endl; - output = rocalSpatter(handle, input, true, 65, 50, 23); + output = rocalSpatter(handle, input, true); } break; case 69: { + std::cout << "Running rocalSpatterFixed" << std::endl; + output = rocalSpatterFixed(handle, input, 65, 50, 23, true); + } break; + case 70: { std::cout << "Running rocalLog" << std::endl; output = rocalLog(handle, input, true); } break; - case 70: { + case 71: { std::cout << "Running rocalColorJitter" << std::endl; output = rocalColorJitter(handle, input, true); } break; - case 71: { + case 72: { std::cout << "Running rocalColorJitterFixed" << std::endl; output = rocalColorJitterFixed(handle, input, 1.02f, 1.1f, 0.02f, 1.3f, true); } break; - case 72: { + case 73: { std::cout << "Running rocalWater" << std::endl; output = rocalWater(handle, input, true); } break; - case 73: { + case 74: { std::cout << "Running rocalWaterFixed" << std::endl; output = rocalWaterFixed(handle, input, 2.0f, 5.0f, 5.8f, 1.2f, 10.0f, 15.0f, true); } break; diff --git a/tests/python_api/unit_tests.sh b/tests/python_api/unit_tests.sh index de951d750..66611a5eb 100755 --- a/tests/python_api/unit_tests.sh +++ b/tests/python_api/unit_tests.sh @@ -165,7 +165,6 @@ do python"$ver" unit_test.py --image-dataset-path "$caffe2_detection_path" --reader-type "caffe2_detection" --augmentation-name resize --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --interpolation-type 5 --scaling-mode 0 --$backend_arg -f "${output_path}Resize_${rgb_name[$rgb]}_${device_name}_triangular_default_caffe2Detection" python"$ver" unit_test.py --image-dataset-path "$mxnet_path" --reader-type "mxnet" --augmentation-name resize --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --interpolation-type 4 --scaling-mode 0 --$backend_arg -f "${output_path}Resize_${rgb_name[$rgb]}_${device_name}_gaussian_default_mxnet" - # Set 1 augmentation tests python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name gaussian_noise --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}GaussianNoise_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name shot_noise --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}ShotNoise_${rgb_name[$rgb]}_${device_name}" python"$ver" unit_test.py --image-dataset-path "$image_path" --augmentation-name spatter --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Spatter_${rgb_name[$rgb]}_${device_name}" From cef421f17ee604c03d3a95d545e859e738cd1d70 Mon Sep 17 00:00:00 2001 From: SundarRajan28 Date: Sat, 10 Jan 2026 01:40:47 -0600 Subject: [PATCH 71/77] Update copyright year to 2026 --- rocAL/include/augmentations/arithmetic_augmentations/node_log.h | 2 +- .../augmentations/color_augmentations/node_color_jitter.h | 2 +- .../augmentations/effects_augmentations/node_gaussian_noise.h | 2 +- .../augmentations/effects_augmentations/node_shot_noise.h | 2 +- .../include/augmentations/effects_augmentations/node_spatter.h | 2 +- rocAL/include/augmentations/effects_augmentations/node_water.h | 2 +- .../source/augmentations/arithmetic_augmentations/node_log.cpp | 2 +- .../augmentations/color_augmentations/node_color_jitter.cpp | 2 +- .../augmentations/effects_augmentations/node_gaussian_noise.cpp | 2 +- .../augmentations/effects_augmentations/node_shot_noise.cpp | 2 +- .../source/augmentations/effects_augmentations/node_spatter.cpp | 2 +- rocAL/source/augmentations/effects_augmentations/node_water.cpp | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rocAL/include/augmentations/arithmetic_augmentations/node_log.h b/rocAL/include/augmentations/arithmetic_augmentations/node_log.h index 999e5e89b..c8f1a00d8 100644 --- a/rocAL/include/augmentations/arithmetic_augmentations/node_log.h +++ b/rocAL/include/augmentations/arithmetic_augmentations/node_log.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/include/augmentations/color_augmentations/node_color_jitter.h b/rocAL/include/augmentations/color_augmentations/node_color_jitter.h index f155729bb..0db9b6d59 100644 --- a/rocAL/include/augmentations/color_augmentations/node_color_jitter.h +++ b/rocAL/include/augmentations/color_augmentations/node_color_jitter.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/include/augmentations/effects_augmentations/node_gaussian_noise.h b/rocAL/include/augmentations/effects_augmentations/node_gaussian_noise.h index 44d1dc823..fdd042de4 100644 --- a/rocAL/include/augmentations/effects_augmentations/node_gaussian_noise.h +++ b/rocAL/include/augmentations/effects_augmentations/node_gaussian_noise.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/include/augmentations/effects_augmentations/node_shot_noise.h b/rocAL/include/augmentations/effects_augmentations/node_shot_noise.h index 99c70e75f..73af136d3 100644 --- a/rocAL/include/augmentations/effects_augmentations/node_shot_noise.h +++ b/rocAL/include/augmentations/effects_augmentations/node_shot_noise.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/include/augmentations/effects_augmentations/node_spatter.h b/rocAL/include/augmentations/effects_augmentations/node_spatter.h index a8a97d006..1ee737763 100644 --- a/rocAL/include/augmentations/effects_augmentations/node_spatter.h +++ b/rocAL/include/augmentations/effects_augmentations/node_spatter.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/include/augmentations/effects_augmentations/node_water.h b/rocAL/include/augmentations/effects_augmentations/node_water.h index c06fddf8d..8d7c9d5be 100644 --- a/rocAL/include/augmentations/effects_augmentations/node_water.h +++ b/rocAL/include/augmentations/effects_augmentations/node_water.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp b/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp index 9caaff0a5..0eff27f73 100644 --- a/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp +++ b/rocAL/source/augmentations/arithmetic_augmentations/node_log.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp b/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp index ea5128b1a..95f67a9b6 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_jitter.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp b/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp index b32f42aed..f6eb59cd2 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_gaussian_noise.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp b/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp index 9308b0ef5..5cfabf255 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_shot_noise.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp b/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp index 79e1f0556..b4e813c82 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_spatter.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/rocAL/source/augmentations/effects_augmentations/node_water.cpp b/rocAL/source/augmentations/effects_augmentations/node_water.cpp index 29e9aeb33..1e09b4cbc 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_water.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_water.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From e7743168f6ba7d9d2709d47a65e8a7c13157e4db Mon Sep 17 00:00:00 2001 From: SundarRajan28 Date: Sat, 10 Jan 2026 02:15:04 -0600 Subject: [PATCH 72/77] Move VX_EXT_RPP_CHECK_VERSION to beginning of API functions Move version check to the very beginning of each function, before any variable assignments or context validation, for all Set 1 augmentation APIs. --- rocAL/source/api/rocal_api_augmentation.cpp | 88 ++++++++++----------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/rocAL/source/api/rocal_api_augmentation.cpp b/rocAL/source/api/rocal_api_augmentation.cpp index 57f053bd5..5ca244ec6 100644 --- a/rocAL/source/api/rocal_api_augmentation.cpp +++ b/rocAL/source/api/rocal_api_augmentation.cpp @@ -1121,6 +1121,10 @@ rocalGaussianNoise( int seed, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalGaussianNoise requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); @@ -1129,7 +1133,6 @@ rocalGaussianNoise( auto mean = static_cast(p_mean); auto stddev = static_cast(p_stddev); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1137,9 +1140,6 @@ rocalGaussianNoise( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(mean, stddev, seed); -#else - THROW("rocalGaussianNoise requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1156,13 +1156,16 @@ rocalGaussianNoiseFixed( int seed, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalGaussianNoiseFixed requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1170,9 +1173,6 @@ rocalGaussianNoiseFixed( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(mean, stddev, seed); -#else - THROW("rocalGaussianNoiseFixed requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1188,6 +1188,10 @@ rocalShotNoise( int seed, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalShotNoise requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); @@ -1195,7 +1199,6 @@ rocalShotNoise( auto input = static_cast(p_input); auto noise_factor = static_cast(p_noise_factor); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1203,9 +1206,6 @@ rocalShotNoise( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(noise_factor, seed); -#else - THROW("rocalShotNoise requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1221,13 +1221,16 @@ rocalShotNoiseFixed( int seed, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalShotNoiseFixed requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); RocalTensorDataType op_tensor_datatype = static_cast(output_datatype); TensorInfo output_info = input->info(); @@ -1235,9 +1238,6 @@ rocalShotNoiseFixed( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(noise_factor, seed); -#else - THROW("rocalShotNoiseFixed requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1494,6 +1494,10 @@ rocalSpatter( RocalIntParam p_blue, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalSpatter requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); @@ -1503,7 +1507,6 @@ rocalSpatter( auto green = static_cast(p_green); auto blue = static_cast(p_blue); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1513,9 +1516,6 @@ rocalSpatter( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(red, green, blue); -#else - THROW("rocalSpatter requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1532,13 +1532,16 @@ rocalSpatterFixed( bool is_output, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalSpatterFixed requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1548,9 +1551,6 @@ rocalSpatterFixed( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(red, green, blue); -#else - THROW("rocalSpatterFixed requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1623,6 +1623,10 @@ rocalColorJitter( RocalFloatParam p_saturation, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalColorJitter requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); @@ -1633,7 +1637,6 @@ rocalColorJitter( auto hue = static_cast(p_hue); auto saturation = static_cast(p_saturation); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1643,9 +1646,6 @@ rocalColorJitter( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(brightness, contrast, hue, saturation); -#else - THROW("rocalColorJitter requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -1663,13 +1663,16 @@ rocalColorJitterFixed( bool is_output, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalColorJitterFixed requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -1679,9 +1682,6 @@ rocalColorJitterFixed( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(brightness, contrast, hue, saturation); -#else - THROW("rocalColorJitterFixed requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2723,13 +2723,16 @@ RocalTensor rocalLog1p(RocalContext p_context, RocalTensor rocalLog(RocalContext p_context, RocalTensor p_input, bool is_output) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalLog requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) // Preserve FP16 inputs, promote everything else to FP32 to avoid precision loss. RocalTensorDataType input_dtype = static_cast(input->data_type()); RocalTensorDataType op_tensor_data_type = (input_dtype == RocalTensorDataType::FP16) @@ -2739,9 +2742,6 @@ RocalTensor rocalLog(RocalContext p_context, output_info.set_data_type(op_tensor_data_type); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output}); -#else - THROW("rocalLog requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2761,6 +2761,10 @@ rocalWater( RocalFloatParam p_phase_y, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalWater requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); @@ -2773,7 +2777,6 @@ rocalWater( auto phase_x = static_cast(p_phase_x); auto phase_y = static_cast(p_phase_y); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -2783,9 +2786,6 @@ rocalWater( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(amplitude_x, amplitude_y, frequency_x, frequency_y, phase_x, phase_y); -#else - THROW("rocalWater requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } @@ -2805,13 +2805,16 @@ rocalWaterFixed( bool is_output, RocalTensorLayout output_layout, RocalTensorOutputType output_datatype) { +#if !VX_EXT_RPP_CHECK_VERSION(3, 1, 5) + THROW("rocalWaterFixed requires vx_rpp version >= 3.1.5"); + return nullptr; +#endif Tensor* output = nullptr; ROCAL_INVALID_CONTEXT_ERR(p_context, output); ROCAL_INVALID_INPUT_ERR(p_input, output); auto context = static_cast(p_context); auto input = static_cast(p_input); try { -#if VX_EXT_RPP_CHECK_VERSION(3, 1, 5) RocalTensorlayout op_tensor_layout = static_cast(output_layout); if (op_tensor_layout == RocalTensorlayout::NONE) op_tensor_layout = input->info().layout(); @@ -2821,9 +2824,6 @@ rocalWaterFixed( output_info.set_data_type(op_tensor_datatype); output = context->master_graph->create_tensor(output_info, is_output); context->master_graph->add_node({input}, {output})->init(amplitude_x, amplitude_y, frequency_x, frequency_y, phase_x, phase_y); -#else - THROW("rocalWaterFixed requires vx_rpp version >= 3.1.5"); -#endif } catch (const std::exception& e) { ROCAL_PRINT_EXCEPTION(context, e); } From 53c8e93473694dfb045ca41ea52e8676aac155a9 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Mon, 19 Jan 2026 01:09:16 -0600 Subject: [PATCH 73/77] Resolve PR comments --- .../color_augmentations/node_color_cast.cpp | 6 +++--- .../color_augmentations/node_non_linear_blend.cpp | 4 ++-- .../effects_augmentations/node_grid_mask.cpp | 2 +- .../filter_augmentations/node_gaussian_filter.cpp | 2 +- .../filter_augmentations/node_median_filter.cpp | 2 +- tests/python_api/unit_test.py | 12 ------------ 6 files changed, 8 insertions(+), 20 deletions(-) diff --git a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp index a5f0af7a8..8c3320507 100644 --- a/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_color_cast.cpp @@ -90,7 +90,7 @@ void ColorCastNode::create_node() { stride, _rgb_memory, mem_type); vx_status status; if ((status = vxGetStatus((vx_reference)_rgb_tensor)) != VX_SUCCESS) - THROW("Error: vxCreateTensorFromHandle(_rgb_tensor) failed: " + TOSTR(status)) + THROW("Error: vxCreateTensorFromHandle(_rgb_tensor) failed: " + TOSTR(status)); // Layouts & ROI type int input_layout = static_cast(_inputs[0]->info().layout()); @@ -104,7 +104,7 @@ void ColorCastNode::create_node() { _rgb_tensor, _alpha.default_array(), input_layout_vx, output_layout_vx, roi_type_vx); vx_status nstatus; if ((nstatus = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the ColorCast (vxExtRppColorCast) node failed: " + TOSTR(nstatus)) + THROW("Adding the ColorCast (vxExtRppColorCast) node failed: " + TOSTR(nstatus)); #else THROW("ColorCastNode: vxExtRppColorCast requires amd_rpp version >= 3.1.2"); #endif @@ -135,4 +135,4 @@ ColorCastNode::~ColorCastNode() { if (_rgb_memory) free(_rgb_memory); } if (_rgb_tensor) vxReleaseTensor(&_rgb_tensor); -} \ No newline at end of file +} diff --git a/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp index bc5502b7b..3f2d33d28 100644 --- a/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp +++ b/rocAL/source/augmentations/color_augmentations/node_non_linear_blend.cpp @@ -36,7 +36,7 @@ void NonLinearBlendNode::create_node() { #if VX_EXT_RPP_CHECK_VERSION(3, 1, 2) if (_inputs.size() < 2) - THROW("NonLinearBlend node needs two input images") + THROW("NonLinearBlend node needs two input images"); _stddev.create_array(_graph, VX_TYPE_FLOAT32, _batch_size); @@ -56,7 +56,7 @@ void NonLinearBlendNode::create_node() { input_layout_vx, output_layout_vx, roi_type_vx); vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the NonLinearBlend (vxExtRppNonLinearBlend) node failed: " + TOSTR(status)) + THROW("Adding the NonLinearBlend (vxExtRppNonLinearBlend) node failed: " + TOSTR(status)); #else THROW("NonLinearBlendNode: vxExtRppNonLinearBlend requires amd_rpp version >= 3.1.2"); #endif diff --git a/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp index b6ca7f0e7..56c771023 100644 --- a/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp +++ b/rocAL/source/augmentations/effects_augmentations/node_grid_mask.cpp @@ -66,7 +66,7 @@ void GridMaskNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the grid mask (vxExtRppGridMask) node failed: " + TOSTR(status)) + THROW("Adding the grid mask (vxExtRppGridMask) node failed: " + TOSTR(status)); #else THROW("GridMaskNode: vxExtRppGridMask requires amd_rpp version >= 3.1.2"); #endif diff --git a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp index e716bb8de..893e27ed6 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_gaussian_filter.cpp @@ -69,7 +69,7 @@ void GaussianFilterNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the gaussian filter (vxExtRppGaussianFilter) node failed: " + TOSTR(status)) + THROW("Adding the gaussian filter (vxExtRppGaussianFilter) node failed: " + TOSTR(status)); #else THROW("GaussianFilterNode: vxExtRppGaussianFilter requires amd_rpp version >= 3.1.2"); #endif diff --git a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp index 8212d10a5..a69814ea7 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_median_filter.cpp @@ -51,7 +51,7 @@ void MedianFilterNode::create_node() { roi_type_vx); vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the median filter (vxExtRppMedianFilter) node failed: " + TOSTR(status)) + THROW("Adding the median filter (vxExtRppMedianFilter) node failed: " + TOSTR(status)); #else THROW("MedianFilterNode: vxExtRppMedianFilter requires amd_rpp version >= 3.1.2"); #endif diff --git a/tests/python_api/unit_test.py b/tests/python_api/unit_test.py index 0a09caf56..fd45734a5 100644 --- a/tests/python_api/unit_test.py +++ b/tests/python_api/unit_test.py @@ -325,18 +325,6 @@ def main(): window_size=5, output_layout=tensor_layout, output_dtype=tensor_dtype) - elif augmentation_name == "gaussian_filter": - output = fn.gaussian_filter(images, - stddev=1.0, - kernel_size=3, - output_layout=tensor_layout, - output_dtype=tensor_dtype) - elif augmentation_name == "gaussian_filter_fixed": - output = fn.gaussian_filter_fixed(images, - stddev=1.0, - kernel_size=3, - output_layout=tensor_layout, - output_dtype=tensor_dtype) elif augmentation_name == "warp_affine": output = fn.warp_affine(images, dest_height=416, dest_width=416, matrix=[1.0, 1.0, 0.5, 0.5, 7.0, 7.0], output_layout=tensor_layout, output_dtype=tensor_dtype, interpolation_type=types.LINEAR_INTERPOLATION) From 04de48b98ff92b8d9ce8883eaaf1ea16e9f1a5f2 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Mon, 19 Jan 2026 01:25:51 -0600 Subject: [PATCH 74/77] Address review comments --- .../augmentations/filter_augmentations/node_magnitude.cpp | 2 +- rocAL/source/augmentations/filter_augmentations/node_phase.cpp | 2 +- rocAL_pybind/amd/rocal/fn.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp index f15b443eb..a9249ff67 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_magnitude.cpp @@ -32,7 +32,7 @@ void MagnitudeNode::create_node() { #if VX_EXT_RPP_CHECK_VERSION(3, 1, 3) if (_inputs.size() < 2) - THROW("Magnitude node needs two input tensors") + THROW("Magnitude node needs two input tensors"); int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); diff --git a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp index efc61c09d..114ff0b08 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_phase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_phase.cpp @@ -31,7 +31,7 @@ void PhaseNode::create_node() { #if VX_EXT_RPP_CHECK_VERSION(3, 1, 3) if (_inputs.size() < 2) - THROW("Phase node needs two input tensors") + THROW("Phase node needs two input tensors"); int input_layout = static_cast(_inputs[0]->info().layout()); int output_layout = static_cast(_outputs[0]->info().layout()); diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index 4bde4578d..550f4c97d 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1489,7 +1489,7 @@ def gaussian_filter(*inputs, stddev=None, kernel_size=3, border_type=types.REPLI """!Applies gaussian filter to images with per-sample stddev parameter. @param inputs the input image passed to the augmentation - @param stddev (float or FloatParam, optional, default = None) per-sample standard deviation parameter; if float, wrapped into a FloatParam. + @param stddev (float or FloatParam, optional, default = None) per-sample standard deviation parameter; if float, wrapped into a FloatParam. When None, the backend uses its default random parameterization. @param kernel_size (int, default = 3) gaussian filter kernel size (pixels), typically odd: 3,5,7 @param border_type (int, default = types.REPLICATE) border handling policy (implementation specific) @param device (string, optional, default = None) Parameter unused for augmentation From 2604c5da096978e6e1667ea73c1b8c41f8a5326d Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Tue, 20 Jan 2026 12:42:14 -0600 Subject: [PATCH 75/77] Address review comments --- .../augmentations/filter_augmentations/node_bitwise_ops.cpp | 2 +- .../source/augmentations/filter_augmentations/node_erase.cpp | 4 ++-- rocAL_pybind/amd/rocal/types.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp index b985c40b0..3e795a79c 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp @@ -40,7 +40,7 @@ void BitwiseOpsNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the bitwise ops (vxExtRppBitwiseOps) node failed: " + TOSTR(status)) + THROW("Adding the bitwise ops (vxExtRppBitwiseOps) node failed: " + TOSTR(status)); #else THROW("BitwiseOpsNode: vxExtRppBitwiseOps requires amd_rpp version >= 3.1.4"); #endif diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index 6034461d0..51bda344c 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -43,7 +43,7 @@ inline vx_enum interpret_tensor_data_type(RocalTensorDataType data_type) { case RocalTensorDataType::INT16: return VX_TYPE_INT16; default: - THROW("Unsupported Tensor type " + TOSTR(data_type)) + THROW("Unsupported Tensor type " + TOSTR(data_type)); } } @@ -171,7 +171,7 @@ void EraseNode::create_node() { vx_status status; if ((status = vxGetStatus((vx_reference)_node)) != VX_SUCCESS) - THROW("Adding the erase (vxExtRppErase) node failed: " + TOSTR(status)) + THROW("Adding the erase (vxExtRppErase) node failed: " + TOSTR(status)); #else THROW("EraseNode: vxExtRppErase requires amd_rpp version >= 3.1.4"); #endif diff --git a/rocAL_pybind/amd/rocal/types.py b/rocAL_pybind/amd/rocal/types.py index 17af1c769..174cbec85 100644 --- a/rocAL_pybind/amd/rocal/types.py +++ b/rocAL_pybind/amd/rocal/types.py @@ -236,7 +236,7 @@ BITWISE_AND : ("BITWISE_AND", BITWISE_AND), BITWISE_OR : ("BITWISE_OR", BITWISE_OR), - BITWISE_XOR : ("BITWISE_OR", BITWISE_XOR), + BITWISE_XOR : ("BITWISE_XOR", BITWISE_XOR), BITWISE_NOT : ("BITWISE_NOT", BITWISE_NOT), } From b04d807860f06d7b219bb8f44164bcbca59a356e Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Thu, 22 Jan 2026 03:08:55 -0600 Subject: [PATCH 76/77] Address review comments --- rocAL/include/pipeline/tensor.h | 7 +++++ .../filter_augmentations/node_erase.cpp | 28 +++---------------- tests/cpp_api/unit_tests/unit_tests.cpp | 2 -- 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/rocAL/include/pipeline/tensor.h b/rocAL/include/pipeline/tensor.h index 1c51d78ab..2c2a9eb8c 100644 --- a/rocAL/include/pipeline/tensor.h +++ b/rocAL/include/pipeline/tensor.h @@ -53,6 +53,13 @@ vx_enum vx_mem_type(RocalMemType mem); */ vx_uint64 tensor_data_size(RocalTensorDataType data_type); +/*! \brief Converts the Rocal data_type to OpenVX + * + * @param RocalTensorDataType input data type + * @return the OpenVX data type associated with input argument + */ +vx_enum interpret_tensor_data_type(RocalTensorDataType data_type); + /*! \brief Allocated memory for given size * * @param void * The ptr for which memory is allocated diff --git a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp index 51bda344c..0a4b1cc11 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_erase.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_erase.cpp @@ -28,25 +28,6 @@ THE SOFTWARE. #include "pipeline/tensor.h" #include -inline vx_enum interpret_tensor_data_type(RocalTensorDataType data_type) { - switch (data_type) { - case RocalTensorDataType::FP32: - return VX_TYPE_FLOAT32; - case RocalTensorDataType::FP16: - return VX_TYPE_FLOAT16; - case RocalTensorDataType::UINT8: - return VX_TYPE_UINT8; - case RocalTensorDataType::UINT32: - return VX_TYPE_UINT32; - case RocalTensorDataType::INT32: - return VX_TYPE_INT32; - case RocalTensorDataType::INT16: - return VX_TYPE_INT16; - default: - THROW("Unsupported Tensor type " + TOSTR(data_type)); - } -} - EraseNode::EraseNode(const std::vector &inputs, const std::vector &outputs) : Node(inputs, outputs) {} @@ -70,16 +51,15 @@ void EraseNode::create_node() { vx_enum vx_mem = (mem_type == RocalMemType::HIP) ? VX_MEMORY_TYPE_HIP : VX_MEMORY_TYPE_HOST; // NumBox tensor handle - vx_size num_box_dims[1] = {_batch_size}; - vx_size num_box_stride[1] = {0}; - num_box_stride[0] = sizeof(vx_uint32); + vx_size num_box_dims = _batch_size; + vx_size num_box_stride = sizeof(vx_uint32); - size_t bytes_a = num_box_stride[0] * num_box_dims[0]; + size_t bytes_a = num_box_stride * num_box_dims; allocate_host_or_pinned_mem(&_num_box_ptr, bytes_a, mem_type); std::memcpy(_num_box_ptr, _num_boxes_vec.data(), bytes_a); vx_tensor _num_boxes_vx = vxCreateTensorFromHandle(vxGetContext((vx_reference)_graph->get()), - 1, num_box_dims, VX_TYPE_UINT32, 0, num_box_stride, _num_box_ptr, vx_mem); + 1, &num_box_dims, VX_TYPE_UINT32, 0, &num_box_stride, _num_box_ptr, vx_mem); if (!_num_boxes_vx) THROW("vxCreateTensorFromHandle for num_box tensor failed"); { vx_status s = vxGetStatus((vx_reference)_num_boxes_vx); diff --git a/tests/cpp_api/unit_tests/unit_tests.cpp b/tests/cpp_api/unit_tests/unit_tests.cpp index cd9ef98a9..b6d4da2dd 100644 --- a/tests/cpp_api/unit_tests/unit_tests.cpp +++ b/tests/cpp_api/unit_tests/unit_tests.cpp @@ -1142,7 +1142,6 @@ int test(int test_case, int reader_type, const char *path, const char *outName, return -1; } int image_name_length[input_batch_size]; - /* switch (pipeline_type) { case 1: { // classification pipeline RocalTensorList labels = rocalGetImageLabels(handle); @@ -1323,7 +1322,6 @@ int test(int test_case, int reader_type, const char *path, const char *outName, return -1; } } - */ auto last_colot_temp = rocalGetIntValue(color_temp_adj); rocalUpdateIntParameter(last_colot_temp + 1, color_temp_adj); From eacce682842f44432da0261cf9b1b1dbfcf6dde9 Mon Sep 17 00:00:00 2001 From: fiona-gladwin Date: Thu, 22 Jan 2026 03:19:39 -0600 Subject: [PATCH 77/77] Update copyright --- .../filter_augmentations/node_bitwise_ops.h | 26 +++++++++++-------- .../node_crop_and_patch.h | 21 +++++++++++++-- .../geometry_augmentations/node_remap.h | 21 +++++++++++++-- .../geometry_augmentations/node_ricap.h | 21 +++++++++++++-- .../filter_augmentations/node_bitwise_ops.cpp | 22 ++++++++++++++-- .../node_crop_and_patch.cpp | 21 +++++++++++++-- .../geometry_augmentations/node_remap.cpp | 21 +++++++++++++-- .../geometry_augmentations/node_ricap.cpp | 21 +++++++++++++-- 8 files changed, 149 insertions(+), 25 deletions(-) diff --git a/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h b/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h index 521bb7ba5..68fa3bce6 100644 --- a/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h +++ b/rocAL/include/augmentations/filter_augmentations/node_bitwise_ops.h @@ -1,21 +1,25 @@ /* -Copyright (c) 2025 Advanced Micro Devices, -Inc. All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in the -Software without restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies of the -Software, and to permit persons to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + #pragma once #include "pipeline/node.h" #include "pipeline/commons.h" diff --git a/rocAL/include/augmentations/geometry_augmentations/node_crop_and_patch.h b/rocAL/include/augmentations/geometry_augmentations/node_crop_and_patch.h index 4f1992136..063b62031 100644 --- a/rocAL/include/augmentations/geometry_augmentations/node_crop_and_patch.h +++ b/rocAL/include/augmentations/geometry_augmentations/node_crop_and_patch.h @@ -1,6 +1,23 @@ /* -Copyright (c) 2025 Advanced Micro Devices, Inc. -All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ #pragma once diff --git a/rocAL/include/augmentations/geometry_augmentations/node_remap.h b/rocAL/include/augmentations/geometry_augmentations/node_remap.h index 862915945..9561527ea 100644 --- a/rocAL/include/augmentations/geometry_augmentations/node_remap.h +++ b/rocAL/include/augmentations/geometry_augmentations/node_remap.h @@ -1,6 +1,23 @@ /* -Copyright (c) 2025 Advanced Micro Devices, Inc. -All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ #pragma once diff --git a/rocAL/include/augmentations/geometry_augmentations/node_ricap.h b/rocAL/include/augmentations/geometry_augmentations/node_ricap.h index f7016bc8c..4db2add68 100644 --- a/rocAL/include/augmentations/geometry_augmentations/node_ricap.h +++ b/rocAL/include/augmentations/geometry_augmentations/node_ricap.h @@ -1,6 +1,23 @@ /* -Copyright (c) 2025 Advanced Micro Devices, Inc. -All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ #pragma once diff --git a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp index 3e795a79c..fcd222510 100644 --- a/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp +++ b/rocAL/source/augmentations/filter_augmentations/node_bitwise_ops.cpp @@ -1,7 +1,25 @@ /* -Copyright (c) 2025 -Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + #include #include #include "augmentations/filter_augmentations/node_bitwise_ops.h" diff --git a/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp b/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp index 1cbcfa143..8176dfb47 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_crop_and_patch.cpp @@ -1,6 +1,23 @@ /* -Copyright (c) 2025 Advanced Micro Devices, Inc. -All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ #include "augmentations/geometry_augmentations/node_crop_and_patch.h" diff --git a/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp index 2633ce886..7a505214e 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_remap.cpp @@ -1,6 +1,23 @@ /* -Copyright (c) 2025 Advanced Micro Devices, Inc. -All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ #include "augmentations/geometry_augmentations/node_remap.h" diff --git a/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp b/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp index 5dbd6bcb0..d4f9fdbff 100644 --- a/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp +++ b/rocAL/source/augmentations/geometry_augmentations/node_ricap.cpp @@ -1,6 +1,23 @@ /* -Copyright (c) 2025 Advanced Micro Devices, Inc. -All rights reserved. +Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ #include "augmentations/geometry_augmentations/node_ricap.h"