From c5f5c0f66d81b09f4aa235cc82243aa1b8c8272d Mon Sep 17 00:00:00 2001 From: Maksims Svecovs Date: Thu, 25 Jan 2024 20:19:32 +0000 Subject: [PATCH 1/2] [doc] Adds documentation for resize_to_quarter Doxygen documentation for resize_to_quarter function. Breaks are used at the end of formating-crucial blocks to enforce table structure in a resulting HTML file. Signed-off-by: Maksims Svecovs --- intrinsiccv/include/intrinsiccv.h | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/intrinsiccv/include/intrinsiccv.h b/intrinsiccv/include/intrinsiccv.h index 441489451..2711470ec 100644 --- a/intrinsiccv/include/intrinsiccv.h +++ b/intrinsiccv/include/intrinsiccv.h @@ -598,6 +598,46 @@ intrinsiccv_error_t intrinsiccv_count_nonzeros_u8(const uint8_t *src, size_t width, size_t height, size_t *count); +/// Resizes source data by averaging 4 elements to one. +/// +/// For even source dimensions `(2*N, 2*M)` destination dimensions should be +/// `(N, M)`. +/// In case of odd source dimensions `(2*N+1, 2*M+1)` destination +/// dimensions could be either `(N+1, M+1)` or `(N, M)` or combination of both. +/// For later cases last respective row or column of source data will not be +/// processed. Currently only supports single-channel data. +/// +/// Even dimension example of 2x2 to 1x1 conversion: +/// ``` +/// | a | b | --> | (a+b+c+d)/4 | +/// | c | d | +/// ``` +/// Odd dimension example of 3x3 to 2x2 conversion: +/// ``` +/// | a | b | c | | (a+b+c+d)/4 | (c+f)/2 | +/// | d | e | f | --> | (g+h)/2 | i | +/// | g | h | i | +/// ``` +/// +/// @param src Pointer to the source data. Must be non-null. +/// @param src_stride Distance in bytes from the start of one row to the +/// start of the next row for the source data. +/// Must not be less than width * sizeof(type). +/// @param src_width Number of elements in the source row. +/// @param src_height Number of rows in the source data. +/// @param dst Pointer to the destination data. Must be non-null. +/// @param dst_stride Distance in bytes from the start of one row to the +/// start of the next row for the destination data. +/// Must not be less than width * sizeof(type). +/// @param dst_width Number of elements in the destination row. +/// Should be src_width / 2 for even src_width. +/// For odd src_width could be either src_width / 2 +/// or (src_width / 2) + 1 +/// @param dst_height Number of rows in the destination data. +/// Should be src_height / 2 for even src_height. +/// For odd src_height could be either src_height / 2 +/// or (src_height / 2) + 1 +/// intrinsiccv_error_t intrinsiccv_resize_to_quarter_u8( const uint8_t *src, size_t src_stride, size_t src_width, size_t src_height, uint8_t *dst, size_t dst_stride, size_t dst_width, size_t dst_height); -- GitLab From 98e449fc11d567d48712a4e1a40ed1adea0f4b86 Mon Sep 17 00:00:00 2001 From: Maksims Svecovs Date: Fri, 26 Jan 2024 16:38:13 +0000 Subject: [PATCH 2/2] [test] Add resize to quarter test Signed-off-by: Maksims Svecovs --- test/api/test_resize_to_quarter.cpp | 213 ++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 test/api/test_resize_to_quarter.cpp diff --git a/test/api/test_resize_to_quarter.cpp b/test/api/test_resize_to_quarter.cpp new file mode 100644 index 000000000..b4cf33f53 --- /dev/null +++ b/test/api/test_resize_to_quarter.cpp @@ -0,0 +1,213 @@ +// SPDX-FileCopyrightText: 2024 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include "framework/array.h" +#include "framework/utils.h" + +class ResizeToQuarterTest final { + public: + explicit ResizeToQuarterTest(size_t channels, size_t padding) + : channels_(channels), padding_(padding) {} + + void execute_test(size_t src_width, size_t src_height, size_t dst_width, + size_t dst_height) const { + size_t src_logical_width = channels_ * src_width; + size_t out_logical_width = channels_ * dst_width; + + test::Array2D source{src_logical_width, src_height, padding_, + channels_}; + test::Array2D actual{out_logical_width, dst_height, padding_, + channels_}; + test::Array2D expected{out_logical_width, dst_height, padding_, + channels_}; + + // Set bottom-row and right-column to 0xFF, the rest to element position in + // buffer + for (size_t h = 0; h < src_height; ++h) { + for (size_t w = 0; w < src_logical_width; ++w) { + if (h >= src_height - 1 || w >= src_logical_width - channels_) { + *source.at(h, w) = 0xFF; + } else { + *source.at(h, w) = (h * src_logical_width + w) % 0xFF; + } + } + } + + calculate_expected(source, expected); + + ASSERT_EQ( + INTRINSICCV_OK, + intrinsiccv_resize_to_quarter_u8( + source.data(), source.stride(), source.width(), source.height(), + actual.data(), actual.stride(), actual.width(), actual.height())); + + EXPECT_EQ_ARRAY2D(actual, expected); + } + + private: + // Calculates average value of 2x2 window with respect to array boundaries. + void fill_from_window(test::Array2D &src, + test::Array2D &dst, size_t src_row, + size_t src_col, size_t dst_row, size_t dst_col) const { + for (size_t channel = 0; channel < channels_; ++channel) { + uint16_t value = 0; + uint8_t divider = 1; + + // Top-left corner, always present + value = *src.at(src_row, src_col + channel); + // Top-right corner + if (src_col + channels_ < src.width()) { + value += *src.at(src_row, src_col + channels_ + channel); + divider++; + } + // Bottom-left corner + if (src_row + 1 < src.height()) { + value += *src.at(src_row + 1, src_col + channel); + divider++; + } + // Bottom-right corner + if (src_row + 1 < src.height() && src_col + channels_ < src.width()) { + value += *src.at(src_row + 1, src_col + channels_ + channel); + divider++; + } + + // Rounding division + *dst.at(dst_row, dst_col + channel) = + static_cast((value + (divider / 2)) / divider); + } + } + + void calculate_expected(test::Array2D &src, + test::Array2D &expected) const { + size_t src_vindex = 0; + size_t src_hindex = 0; + + for (size_t exp_vindex = 0; exp_vindex < expected.height(); exp_vindex++) { + for (size_t exp_hindex = 0; exp_hindex < expected.width(); + exp_hindex += channels_) { + fill_from_window(src, expected, src_vindex, src_hindex, exp_vindex, + exp_hindex); + src_hindex += 2 * channels_; + } + src_vindex += 2; + src_hindex = 0; + } + } + + size_t channels_; + size_t padding_; +}; + +// Test basic dimension cases without padding +TEST(ResizeToQuarter, EvenDimsNoPadding) { + // For now resize only reasonably supports single-channel data + ResizeToQuarterTest resize_test(1, 0); + + size_t src_width = 2 * test::Options::vector_lanes(); + // Set height to at least double 2x2 window height + size_t src_height = 4; + size_t dst_width = src_width / 2; + size_t dst_height = src_height / 2; + resize_test.execute_test(src_width, src_height, dst_width, dst_height); +} + +TEST(ResizeToQuarter, OddDimsFullNoPadding) { + // For now resize only reasonably supports single-channel data + ResizeToQuarterTest resize_test(1, 0); + + size_t src_width = 2 * test::Options::vector_lanes() - 1; + // Set height to at least double 2x2 window height + size_t src_height = 5; + size_t dst_width = src_width / 2 + 1; + size_t dst_height = src_height / 2 + 1; + resize_test.execute_test(src_width, src_height, dst_width, dst_height); +} + +// The rest of tests are done with padding since this is a more elaborate case +TEST(ResizeToQuarter, EvenDims) { + // For now resize only reasonably supports single-channel data + ResizeToQuarterTest resize_test(1, 1); + + size_t src_width = 2 * test::Options::vector_lanes(); + // Set height to at least double 2x2 window height + size_t src_height = 4; + size_t dst_width = src_width / 2; + size_t dst_height = src_height / 2; + resize_test.execute_test(src_width, src_height, dst_width, dst_height); +} + +TEST(ResizeToQuarter, OddDimsFull) { + // For now resize only reasonably supports single-channel data + ResizeToQuarterTest resize_test(1, 1); + + size_t src_width = 2 * test::Options::vector_lanes() - 1; + // Set height to at least double 2x2 window height + size_t src_height = 5; + size_t dst_width = src_width / 2 + 1; + size_t dst_height = src_height / 2 + 1; + resize_test.execute_test(src_width, src_height, dst_width, dst_height); +} + +TEST(ResizeToQuarter, EvenHeightOddWidthFull) { + // For now resize only reasonably supports single-channel data + ResizeToQuarterTest resize_test(1, 1); + + size_t src_width = 2 * test::Options::vector_lanes() - 1; + // Set height to at least double 2x2 window height + size_t src_height = 4; + size_t dst_width = src_width / 2 + 1; + size_t dst_height = src_height / 2; + resize_test.execute_test(src_width, src_height, dst_width, dst_height); +} + +TEST(ResizeToQuarter, OddHeightEvenWidthFull) { + // For now resize only reasonably supports single-channel data + ResizeToQuarterTest resize_test(1, 1); + + size_t src_width = 2 * test::Options::vector_lanes(); + // Set height to at least double 2x2 window height + size_t src_height = 5; + size_t dst_width = src_width / 2; + size_t dst_height = src_height / 2 + 1; + resize_test.execute_test(src_width, src_height, dst_width, dst_height); +} + +TEST(ResizeToQuarter, OddDimsFullHeight) { + // For now resize only reasonably supports single-channel data + ResizeToQuarterTest resize_test(1, 1); + + size_t src_width = 2 * test::Options::vector_lanes() - 1; + // Set height to at least double 2x2 window height + size_t src_height = 5; + size_t dst_width = src_width / 2; + size_t dst_height = src_height / 2 + 1; + resize_test.execute_test(src_width, src_height, dst_width, dst_height); +} + +TEST(ResizeToQuarter, OddDimsFullWidth) { + // For now resize only reasonably supports single-channel data + ResizeToQuarterTest resize_test(1, 1); + + size_t src_width = 2 * test::Options::vector_lanes() - 1; + // Set height to at least double 2x2 window height + size_t src_height = 5; + size_t dst_width = src_width / 2 + 1; + size_t dst_height = src_height / 2; + resize_test.execute_test(src_width, src_height, dst_width, dst_height); +} + +TEST(ResizeToQuarter, OddDimsTruncated) { + // For now resize only reasonably supports single-channel data + ResizeToQuarterTest resize_test(1, 1); + + size_t src_width = 2 * test::Options::vector_lanes() - 1; + // Set height to at least double 2x2 window height + size_t src_height = 5; + size_t dst_width = src_width / 2; + size_t dst_height = src_height / 2; + resize_test.execute_test(src_width, src_height, dst_width, dst_height); +} -- GitLab