| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-FileCopyrightText: 2023 - 2025 Arm Limited and/or its affiliates <open-source-office@arm.com> | ||
| 2 | // | ||
| 3 | // SPDX-License-Identifier: Apache-2.0 | ||
| 4 | |||
| 5 | #include "kleidicv/ctypes.h" | ||
| 6 | #include "kleidicv/filters/filter_2d_neon.h" | ||
| 7 | #include "kleidicv/filters/median_blur.h" | ||
| 8 | #include "kleidicv/filters/process_filter_2d.h" | ||
| 9 | #include "kleidicv/kleidicv.h" | ||
| 10 | #include "kleidicv/neon.h" | ||
| 11 | #include "kleidicv/workspace/border_3x3.h" | ||
| 12 | #include "kleidicv/workspace/border_5x5.h" | ||
| 13 | #include "kleidicv/workspace/border_7x7.h" | ||
| 14 | #include "median_blur_sorting_network_3x3.h" | ||
| 15 | #include "median_blur_sorting_network_5x5.h" | ||
| 16 | #include "median_blur_sorting_network_7x7.h" | ||
| 17 | |||
| 18 | namespace kleidicv::neon { | ||
| 19 | |||
| 20 | // Primary template for Median Blur filters. | ||
| 21 | template <typename ScalarType, size_t KernelSize> | ||
| 22 | class MedianBlurSortingNetwork; | ||
| 23 | |||
| 24 | template <typename ScalarType> | ||
| 25 | class VectorizedComparator { | ||
| 26 | public: | ||
| 27 | using SourceVectorType = typename VecTraits<ScalarType>::VectorType; | ||
| 28 | |||
| 29 | 4255498 | static void compare_and_swap(SourceVectorType& left, SourceVectorType& right, | |
| 30 | Monostate&) { | ||
| 31 | 4255498 | SourceVectorType max_value = vmaxq(left, right); | |
| 32 | 4255498 | SourceVectorType min_value = vminq(left, right); | |
| 33 | 4255498 | left = min_value; | |
| 34 | 4255498 | right = max_value; | |
| 35 | 4255498 | } | |
| 36 | |||
| 37 | 470532 | static void min(SourceVectorType& left, SourceVectorType& right, Monostate&) { | |
| 38 | 470532 | left = vminq(left, right); | |
| 39 | 470532 | } | |
| 40 | |||
| 41 | 456960 | static void max(SourceVectorType& left, SourceVectorType& right, Monostate&) { | |
| 42 | 456960 | right = vmaxq(left, right); | |
| 43 | 456960 | } | |
| 44 | 16064 | static SourceVectorType get_min(SourceVectorType& left, | |
| 45 | SourceVectorType& right, Monostate&) { | ||
| 46 | 16064 | return vminq(left, right); | |
| 47 | } | ||
| 48 | 16064 | static SourceVectorType get_max(SourceVectorType& left, | |
| 49 | SourceVectorType& right, Monostate&) { | ||
| 50 | 16064 | return vmaxq(left, right); | |
| 51 | } | ||
| 52 | }; | ||
| 53 | |||
| 54 | template <typename ScalarType> | ||
| 55 | class ScalarComparator { | ||
| 56 | public: | ||
| 57 | 15767992 | static void compare_and_swap(ScalarType& left, ScalarType& right, | |
| 58 | Monostate&) { | ||
| 59 |
14/14✓ Branch 0 taken 1129612 times.
✓ Branch 1 taken 632668 times.
✓ Branch 2 taken 1756077 times.
✓ Branch 3 taken 993599 times.
✓ Branch 4 taken 1685195 times.
✓ Branch 5 taken 963705 times.
✓ Branch 6 taken 1684860 times.
✓ Branch 7 taken 964040 times.
✓ Branch 8 taken 1124136 times.
✓ Branch 9 taken 633224 times.
✓ Branch 10 taken 1122010 times.
✓ Branch 11 taken 635350 times.
✓ Branch 12 taken 1556089 times.
✓ Branch 13 taken 887427 times.
|
15767992 | if (left > right) { |
| 60 | 5710013 | std::swap(left, right); | |
| 61 | 5710013 | } | |
| 62 | 15767992 | } | |
| 63 | |||
| 64 | 1702384 | static void min(ScalarType& left, ScalarType& right, Monostate&) { | |
| 65 | 1702384 | left = std::min(left, right); | |
| 66 | 1702384 | } | |
| 67 | |||
| 68 | 1648288 | static void max(ScalarType& left, ScalarType& right, Monostate&) { | |
| 69 | 1648288 | right = std::max(left, right); | |
| 70 | 1648288 | } | |
| 71 | 34560 | static ScalarType get_min(ScalarType& left, ScalarType& right, Monostate&) { | |
| 72 | 34560 | return std::min(left, right); | |
| 73 | } | ||
| 74 | 34560 | static ScalarType get_max(ScalarType& left, ScalarType& right, Monostate&) { | |
| 75 | 34560 | return std::max(left, right); | |
| 76 | } | ||
| 77 | }; | ||
| 78 | |||
| 79 | // Template for Median Blur 3x3 filters. | ||
| 80 | template <typename ScalarType> | ||
| 81 | class MedianBlurSortingNetwork<ScalarType, 3> { | ||
| 82 | public: | ||
| 83 | using SourceType = ScalarType; | ||
| 84 | using DestinationType = SourceType; | ||
| 85 | using SourceVectorType = typename VecTraits<SourceType>::VectorType; | ||
| 86 | using DestinationVectorType = typename VecTraits<DestinationType>::VectorType; | ||
| 87 | |||
| 88 | template <typename KernelWindowFunctor> | ||
| 89 | 1076 | void vector_path(KernelWindowFunctor& KernelWindow, | |
| 90 | DestinationVectorType& output_vec) const { | ||
| 91 | 1076 | Monostate ctx; | |
| 92 | 1076 | sorting_network3x3_single_row<VectorizedComparator<ScalarType>>( | |
| 93 | 1076 | KernelWindow, output_vec, ctx); | |
| 94 | 1076 | } | |
| 95 | |||
| 96 | template <typename KernelWindowFunctor> | ||
| 97 | 3478 | void vector_path_for_dual_row_handling( | |
| 98 | KernelWindowFunctor& KernelWindow, DestinationVectorType& output_vec_0, | ||
| 99 | DestinationVectorType& output_vec_1) const { | ||
| 100 | 3478 | Monostate ctx; | |
| 101 | 3478 | sorting_network3x3_dual_rows<VectorizedComparator<ScalarType>>( | |
| 102 | 3478 | KernelWindow, output_vec_0, output_vec_1, ctx); | |
| 103 | 3478 | } | |
| 104 | |||
| 105 | template <typename KernelWindowFunctor> | ||
| 106 | 1168 | void scalar_path(KernelWindowFunctor& KernelWindow, | |
| 107 | DestinationType& output_vec) const { | ||
| 108 | 1168 | Monostate ctx; | |
| 109 | 1168 | sorting_network3x3_single_row<ScalarComparator<ScalarType>>( | |
| 110 | 1168 | KernelWindow, output_vec, ctx); | |
| 111 | 1168 | } | |
| 112 | |||
| 113 | template <typename KernelWindowFunctor> | ||
| 114 | 8056 | void scalar_path_for_dual_row_handling(KernelWindowFunctor& KernelWindow, | |
| 115 | DestinationType& output_vec0, | ||
| 116 | DestinationType& output_vec1) const { | ||
| 117 | 8056 | Monostate ctx; | |
| 118 | 8056 | sorting_network3x3_dual_rows<ScalarComparator<ScalarType>>( | |
| 119 | 8056 | KernelWindow, output_vec0, output_vec1, ctx); | |
| 120 | 8056 | } | |
| 121 | }; // end of class MedianBlurSortingNetwork<ScalarType, 3> | ||
| 122 | |||
| 123 | // Template for Median Blur 5x5 filters. | ||
| 124 | template <typename ScalarType> | ||
| 125 | class MedianBlurSortingNetwork<ScalarType, 5> { | ||
| 126 | public: | ||
| 127 | using SourceType = ScalarType; | ||
| 128 | using DestinationType = SourceType; | ||
| 129 | using SourceVectorType = typename VecTraits<SourceType>::VectorType; | ||
| 130 | using DestinationVectorType = typename VecTraits<DestinationType>::VectorType; | ||
| 131 | |||
| 132 | template <typename KernelWindowFunctor> | ||
| 133 | 11308 | void vector_path(KernelWindowFunctor& KernelWindow, | |
| 134 | DestinationVectorType& output_vec) const { | ||
| 135 | 11308 | Monostate ctx; | |
| 136 | 22616 | sorting_network5x5<VectorizedComparator<ScalarType>>(KernelWindow, | |
| 137 | 11308 | output_vec, ctx); | |
| 138 | 11308 | } | |
| 139 | |||
| 140 | template <typename KernelWindowFunctor> | ||
| 141 | 32136 | void scalar_path(KernelWindowFunctor& KernelWindow, | |
| 142 | DestinationType& dst) const { | ||
| 143 | 32136 | Monostate ctx; | |
| 144 | 32136 | sorting_network5x5<ScalarComparator<ScalarType>>(KernelWindow, dst, ctx); | |
| 145 | 32136 | } | |
| 146 | }; // end of class MedianBlurSortingNetwork<ScalarType, 5> | ||
| 147 | |||
| 148 | // Template for Median Blur 7x7 filters. | ||
| 149 | template <typename ScalarType> | ||
| 150 | class MedianBlurSortingNetwork<ScalarType, 7> { | ||
| 151 | public: | ||
| 152 | using SourceType = ScalarType; | ||
| 153 | using DestinationType = SourceType; | ||
| 154 | using SourceVectorType = typename VecTraits<SourceType>::VectorType; | ||
| 155 | using DestinationVectorType = typename VecTraits<DestinationType>::VectorType; | ||
| 156 | |||
| 157 | template <typename KernelWindowFunctor> | ||
| 158 | 13572 | void vector_path(KernelWindowFunctor& KernelWindow, | |
| 159 | DestinationVectorType& dst) const { | ||
| 160 | 13572 | Monostate ctx; | |
| 161 | 13572 | sorting_network7x7<VectorizedComparator<ScalarType>>(KernelWindow, dst, | |
| 162 | ctx); | ||
| 163 | 13572 | } | |
| 164 | |||
| 165 | template <typename KernelWindowFunctor> | ||
| 166 | 54096 | void scalar_path(KernelWindowFunctor& KernelWindow, | |
| 167 | DestinationType& dst) const { | ||
| 168 | 54096 | Monostate ctx; | |
| 169 | 54096 | sorting_network7x7<ScalarComparator<ScalarType>>(KernelWindow, dst, ctx); | |
| 170 | 54096 | } | |
| 171 | }; // end of class MedianBlurSortingNetworkSortingNetwork<ScalarType, 7> | ||
| 172 | |||
| 173 | template <typename T> | ||
| 174 | 1610 | kleidicv_error_t median_blur_sorting_network_stripe( | |
| 175 | const T* src, size_t src_stride, T* dst, size_t dst_stride, size_t width, | ||
| 176 | size_t height, size_t y_begin, size_t y_end, size_t channels, | ||
| 177 | size_t kernel_width, [[maybe_unused]] size_t kernel_height, | ||
| 178 | FixedBorderType border_type) { | ||
| 179 | 1610 | Rectangle rect{width, height}; | |
| 180 | 1610 | Rows<const T> src_rows{src, src_stride, channels}; | |
| 181 | 1610 | Rows<T> dst_rows{dst, dst_stride, channels}; | |
| 182 | |||
| 183 |
14/14✓ Branch 0 taken 64 times.
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 159 times.
✓ Branch 4 taken 98 times.
✓ Branch 5 taken 159 times.
✓ Branch 6 taken 98 times.
✓ Branch 7 taken 159 times.
✓ Branch 8 taken 64 times.
✓ Branch 9 taken 130 times.
✓ Branch 10 taken 64 times.
✓ Branch 11 taken 130 times.
✓ Branch 12 taken 98 times.
✓ Branch 13 taken 159 times.
|
1610 | if (kernel_width == 3) { |
| 184 | 584 | MedianBlurSortingNetwork<T, 3> median_filter; | |
| 185 | 584 | Filter2D3x3<MedianBlurSortingNetwork<T, 3>> filter{median_filter}; | |
| 186 | 1168 | process_filter2d_by_dual_rows(rect, y_begin, y_end, src_rows, dst_rows, | |
| 187 | 584 | border_type, filter); | |
| 188 | 584 | return KLEIDICV_OK; | |
| 189 | 584 | } | |
| 190 | |||
| 191 |
14/14✓ Branch 0 taken 66 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 75 times.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 75 times.
✓ Branch 6 taken 84 times.
✓ Branch 7 taken 75 times.
✓ Branch 8 taken 66 times.
✓ Branch 9 taken 64 times.
✓ Branch 10 taken 66 times.
✓ Branch 11 taken 64 times.
✓ Branch 12 taken 84 times.
✓ Branch 13 taken 75 times.
|
1026 | if (kernel_width == 5) { |
| 192 | 534 | MedianBlurSortingNetwork<T, 5> median_filter; | |
| 193 | 534 | Filter2D5x5<MedianBlurSortingNetwork<T, 5>> filter{median_filter}; | |
| 194 | 1068 | process_filter2d(rect, y_begin, y_end, src_rows, dst_rows, border_type, | |
| 195 | 534 | filter); | |
| 196 | 534 | return KLEIDICV_OK; | |
| 197 | 534 | } | |
| 198 | |||
| 199 | 492 | MedianBlurSortingNetwork<T, 7> median_filter; | |
| 200 | 492 | Filter2D7x7<MedianBlurSortingNetwork<T, 7>> filter{median_filter}; | |
| 201 | 984 | process_filter2d(rect, y_begin, y_end, src_rows, dst_rows, border_type, | |
| 202 | 492 | filter); | |
| 203 | 492 | return KLEIDICV_OK; | |
| 204 | 1610 | } | |
| 205 | |||
| 206 | #define KLEIDICV_INSTANTIATE_TEMPLATE(type) \ | ||
| 207 | template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t \ | ||
| 208 | median_blur_sorting_network_stripe<type>( \ | ||
| 209 | const type* src, size_t src_stride, type* dst, size_t dst_stride, \ | ||
| 210 | size_t width, size_t height, size_t y_begin, size_t y_end, \ | ||
| 211 | size_t channels, size_t kernel_width, size_t kernel_height, \ | ||
| 212 | FixedBorderType border_type) | ||
| 213 | |||
| 214 | KLEIDICV_INSTANTIATE_TEMPLATE(int8_t); | ||
| 215 | KLEIDICV_INSTANTIATE_TEMPLATE(uint8_t); | ||
| 216 | KLEIDICV_INSTANTIATE_TEMPLATE(int16_t); | ||
| 217 | KLEIDICV_INSTANTIATE_TEMPLATE(uint16_t); | ||
| 218 | KLEIDICV_INSTANTIATE_TEMPLATE(int32_t); | ||
| 219 | KLEIDICV_INSTANTIATE_TEMPLATE(uint32_t); | ||
| 220 | KLEIDICV_INSTANTIATE_TEMPLATE(float); | ||
| 221 | |||
| 222 | } // namespace kleidicv::neon | ||
| 223 |