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 | #ifndef KLEIDICV_FILTERS_GAUSSIAN_BLUR_H | ||
6 | #define KLEIDICV_FILTERS_GAUSSIAN_BLUR_H | ||
7 | |||
8 | #include "kleidicv/config.h" | ||
9 | #include "kleidicv/kleidicv.h" | ||
10 | #include "kleidicv/types.h" | ||
11 | #include "kleidicv/utils.h" | ||
12 | #include "kleidicv/workspace/border_types.h" | ||
13 | #include "kleidicv/workspace/separable.h" | ||
14 | |||
15 | extern "C" { | ||
16 | // For internal use only. See instead kleidicv_gaussian_blur_u8. | ||
17 | // Blur a horizontal stripe across an image. The stripe is defined by the | ||
18 | // range (y_begin, y_end]. | ||
19 | KLEIDICV_API_DECLARATION(kleidicv_gaussian_blur_fixed_stripe_u8, | ||
20 | const uint8_t *src, size_t src_stride, uint8_t *dst, | ||
21 | size_t dst_stride, size_t width, size_t height, | ||
22 | size_t y_begin, size_t y_end, size_t channels, | ||
23 | size_t kernel_width, size_t kernel_height, | ||
24 | float sigma_x, float sigma_y, | ||
25 | kleidicv::FixedBorderType border_type, | ||
26 | kleidicv_filter_context_t *context); | ||
27 | |||
28 | KLEIDICV_API_DECLARATION(kleidicv_gaussian_blur_arbitrary_stripe_u8, | ||
29 | const uint8_t *src, size_t src_stride, uint8_t *dst, | ||
30 | size_t dst_stride, size_t width, size_t height, | ||
31 | size_t y_begin, size_t y_end, size_t channels, | ||
32 | size_t kernel_width, size_t kernel_height, | ||
33 | float sigma_x, float sigma_y, | ||
34 | kleidicv::FixedBorderType border_type, | ||
35 | kleidicv_filter_context_t *context); | ||
36 | } | ||
37 | |||
38 | namespace kleidicv { | ||
39 | |||
40 | 1455 | inline bool gaussian_blur_is_implemented( | |
41 | size_t width, size_t height, size_t kernel_width, size_t kernel_height, | ||
42 | float sigma_x, float sigma_y, size_t channels, | ||
43 | kleidicv::FixedBorderType border_type) { | ||
44 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1452 times.
|
1455 | if (kernel_width != kernel_height) { |
45 | 3 | return false; | |
46 | } | ||
47 | |||
48 |
4/4✓ Branch 0 taken 1449 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1446 times.
|
1452 | if (kernel_width < 3 || kernel_width > 255) { |
49 | 6 | return false; | |
50 | } | ||
51 | |||
52 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1440 times.
|
1446 | if ((kernel_width & 1) != 1) { |
53 | 6 | return false; | |
54 | } | ||
55 | |||
56 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1431 times.
|
1440 | if (sigma_x != sigma_y) { |
57 | 9 | return false; | |
58 | } | ||
59 | |||
60 |
4/4✓ Branch 0 taken 1140 times.
✓ Branch 1 taken 291 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 1110 times.
|
1431 | if (width < kernel_width - 1 || height < kernel_width - 1) { |
61 | 321 | return false; | |
62 | } | ||
63 | |||
64 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1107 times.
|
1110 | if (channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { |
65 | 3 | return false; | |
66 | } | ||
67 | |||
68 |
6/6✓ Branch 0 taken 402 times.
✓ Branch 1 taken 705 times.
✓ Branch 2 taken 228 times.
✓ Branch 3 taken 174 times.
✓ Branch 4 taken 144 times.
✓ Branch 5 taken 84 times.
|
1107 | if (kernel_width > 7 && kernel_width != 15 && kernel_width != 21) { |
69 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 75 times.
|
84 | if (border_type != FixedBorderType::REPLICATE) { |
70 | 9 | return false; | |
71 | } | ||
72 | |||
73 | 75 | size_t margin = kernel_width / 2; | |
74 | // Number of 16bit elements in a 128-bit vector | ||
75 | 75 | size_t max_border_length = 8; | |
76 | 225 | size_t aligned_margin = (margin + max_border_length - 1) / | |
77 | 150 | max_border_length * max_border_length; | |
78 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 63 times.
|
75 | if (width < aligned_margin + margin) { |
79 | 12 | return false; | |
80 | } | ||
81 | 75 | } | |
82 | |||
83 | 1086 | return true; | |
84 | 1455 | } | |
85 | |||
86 | // Does not include checks for whether the operation is implemented. | ||
87 | // This must be done earlier, by gaussian_blur_is_implemented. | ||
88 | template <typename T> | ||
89 | 1101 | kleidicv_error_t gaussian_blur_checks( | |
90 | const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, | ||
91 | size_t height, size_t channels, | ||
92 | const KLEIDICV_TARGET_NAMESPACE::SeparableFilterWorkspace *workspace) | ||
93 | KLEIDICV_STREAMING { | ||
94 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1089 times.
|
1101 | CHECK_POINTERS(workspace); |
95 | |||
96 |
4/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1077 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 1077 times.
|
1089 | CHECK_POINTER_AND_STRIDE(src, src_stride, height); |
97 |
4/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1065 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 1065 times.
|
1077 | CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); |
98 |
6/6✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1062 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1056 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 1056 times.
|
1065 | CHECK_IMAGE_SIZE(width, height); |
99 | |||
100 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1050 times.
|
1056 | if (workspace->channels() < channels) { |
101 | 6 | return KLEIDICV_ERROR_CONTEXT_MISMATCH; | |
102 | } | ||
103 | |||
104 | 2100 | const KLEIDICV_TARGET_NAMESPACE::Rectangle &context_rect = | |
105 | 1050 | workspace->image_size(); | |
106 |
4/4✓ Branch 0 taken 1038 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1032 times.
|
1050 | if (context_rect.width() < width || context_rect.height() < height) { |
107 | 18 | return KLEIDICV_ERROR_CONTEXT_MISMATCH; | |
108 | } | ||
109 | |||
110 | 1032 | return KLEIDICV_OK; | |
111 | 1101 | } | |
112 | |||
113 | namespace neon { | ||
114 | |||
115 | kleidicv_error_t gaussian_blur_fixed_stripe_u8( | ||
116 | const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, | ||
117 | size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, | ||
118 | size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, | ||
119 | FixedBorderType border_type, kleidicv_filter_context_t *context); | ||
120 | |||
121 | kleidicv_error_t gaussian_blur_arbitrary_stripe_u8( | ||
122 | const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, | ||
123 | size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, | ||
124 | size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, | ||
125 | FixedBorderType border_type, kleidicv_filter_context_t *context); | ||
126 | |||
127 | } // namespace neon | ||
128 | |||
129 | namespace sve2 { | ||
130 | |||
131 | kleidicv_error_t gaussian_blur_fixed_stripe_u8( | ||
132 | const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, | ||
133 | size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, | ||
134 | size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, | ||
135 | FixedBorderType border_type, kleidicv_filter_context_t *context); | ||
136 | |||
137 | } // namespace sve2 | ||
138 | |||
139 | namespace sme { | ||
140 | |||
141 | kleidicv_error_t gaussian_blur_fixed_stripe_u8( | ||
142 | const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, | ||
143 | size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, | ||
144 | size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, | ||
145 | FixedBorderType border_type, kleidicv_filter_context_t *context); | ||
146 | |||
147 | } // namespace sme | ||
148 | |||
149 | } // namespace kleidicv | ||
150 | |||
151 | #endif // KLEIDICV_FILTERS_GAUSSIAN_BLUR_H | ||
152 |