Ocean
Loading...
Searching...
No Matches
FrameFilterSobel.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_CV_FRAME_FILTER_SOBEL_H
9#define META_OCEAN_CV_FRAME_FILTER_SOBEL_H
10
11#include "ocean/cv/CV.h"
14
15#include "ocean/base/Worker.h"
16
17#if defined(OCEAN_HARDWARE_SSE_VERSION) && OCEAN_HARDWARE_SSE_VERSION >= 41
18 #include "ocean/cv/SSE.h"
19#endif
20
21namespace Ocean
22{
23
24namespace CV
25{
26
27/**
28 * This class implements a Sobel filter.
29 * The horizontal (0 degree) and vertical (90 degree - clockwise) 3x3 Sobel box filter (not convolution filter) are defined as:
30 * <pre>
31 * horizontal: vertical (90 degree):
32 * | -1 0 1 | | -1 -2 -1 |
33 * | -2 0 2 | | 0 0 0 |
34 * | -1 0 1 | | 1 2 1 |
35 * </pre>
36 *
37 * The diagonal 3x3 Sobel filters are defined as:
38 * <pre>
39 * 45 degree: 135 degree:
40 * | -2 -1 0 | | 0 -1 -2 |
41 * | -1 0 1 | | 1 0 -1 |
42 * | 0 1 2 | | 2 1 0 |
43 * </pre>
44 * @see FrameFilterSobelMagnitude, FrameFilterScharr.
45 * @ingroup cv
46 */
47class OCEAN_CV_EXPORT FrameFilterSobel : public FrameFilter
48{
49 public:
50
51 /**
52 * The following comfort class provides comfortable functions simplifying prototyping applications but also increasing binary size of the resulting applications.
53 * Best practice is to avoid using these functions if binary size matters,<br>
54 * as for every comfort function a corresponding function exists with specialized functionality not increasing binary size significantly.<br>
55 */
56 class OCEAN_CV_EXPORT Comfort
57 {
58 public:
59
60 /**
61 * Horizontal and vertical Sobel filter for images.
62 * The resulting frame will contain interleaved horizontal and vertical Sobel responses for each individual frame channels.
63 * @param frame The 1-plane frame on which the Sobel filter will be applied, with data type 'DT_UNSIGNED_INTEGER_8', must be valid
64 * @param responseDataType The data type of the individual sobel responses, either 'DT_SIGNED_INTEGER_8' or 'DT_SIGNED_INTEGER_16'
65 * @param worker Optional worker to distribute the computation
66 * @return The resulting sobel response for the given frame, invalid in case of an error
67 */
68 static Frame filterHorizontalVertical(const Frame& frame, const FrameType::DataType responseDataType = FrameType::DT_SIGNED_INTEGER_8, Worker* worker = nullptr);
69
70 /**
71 * Horizontal, vertical, and diagonal Sobel filter for images.
72 * The resulting frame will contain interleaved horizontal, vertical, and diagonal Sobel responses for each individual frame channels.
73 * @param frame The 1-plane frame on which the Sobel filter will be applied, with data type 'DT_UNSIGNED_INTEGER_8', must be valid
74 * @param responseDataType The data type of the individual sobel responses, either 'DT_SIGNED_INTEGER_8' or 'DT_SIGNED_INTEGER_16'
75 * @param worker Optional worker to distribute the computation
76 * @return The resulting sobel response for the given frame, invalid in case of an error
77 */
78 static Frame filter(const Frame& frame, const FrameType::DataType responseDataType = FrameType::DT_SIGNED_INTEGER_8, Worker* worker = nullptr);
79 };
80
81 public:
82
83 /**
84 * Horizontal and vertical Sobel filter for images.
85 * If the target response data type is selected to be `int8_t`, each filter response is normalized by 1/8 to fit into the value range [-128, 127].<br>
86 * If the target response data type is selected to be `int16_t` no normalization will be applied.
87 * The border pixels are set to zero.
88 * @param source The source frame to which the Sobel filter will be applied, with `tSourceChannels` channels, must be valid
89 * @param target The target response frame receiving the horizontal and vertical Sobel responses, with `tSourceChannels * 2` channels, must be valid
90 * @param width The width of the frame in pixel, with range [3, infinity)
91 * @param height The height of the frame in pixel, with range [3, infinity)
92 * @param sourcePaddingElements Optional padding at the end of each source row in elements, with range [0, infinity)
93 * @param targetPaddingElements Optional padding at the end of each target row in elements, with range [0, infinity)
94 * @param worker Optional worker object to distribute the computational load
95 * @tparam TTarget The data type of the response values, either `int8_t` or `int16_t`
96 * @tparam tSourceChannels The number of channels of the source frame, with range [1, infinity)
97 */
98 template <typename TTarget, unsigned int tSourceChannels>
99 static inline void filterHorizontalVertical8BitPerChannel(const uint8_t* source, TTarget* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
100
101 /**
102 * Diagonal 45 and 135 degree Sobel filter for images.
103 * If the target response data type is selected to be `int8_t`, each filter response is normalized by 1/8 to fit into the value range [-128, 127].<br>
104 * If the target response data type is selected to be `int16_t` no normalization will be applied.
105 * The border pixels are set to zero.
106 * @param source The source frame to which the Sobel filter will be applied, with `tSourceChannels` channels, must be valid
107 * @param target The target response frame receiving the diagonal Sobel responses, with `tSourceChannels * 2` channels, must be valid
108 * @param width The width of the frame in pixel, with range [3, infinity)
109 * @param height The height of the frame in pixel, with range [3, infinity)
110 * @param sourcePaddingElements Optional padding at the end of each source row in elements, with range [0, infinity)
111 * @param targetPaddingElements Optional padding at the end of each target row in elements, with range [0, infinity)
112 * @param worker Optional worker object to distribute the computational load
113 * @tparam TTarget The data type of the response values, either `int8_t` or `int16_t`
114 * @tparam tSourceChannels The number of channels of the source frame, with range [1, infinity)
115 */
116 template <typename TTarget, unsigned int tSourceChannels>
117 static inline void filterDiagonal8BitPerChannel(const uint8_t* source, TTarget* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
118
119 /**
120 * Horizontal, vertical, and diagonal Sobel filter for images.
121 * If the target response data type is selected to be `int8_t`, each filter response is normalized by 1/8 to fit into the value range [-128, 127].<br>
122 * If the target response data type is selected to be `int16_t` no normalization will be applied.
123 * The border pixels are set to zero.
124 * @param source The source frame to which the Sobel filter will be applied, with `tSourceChannels` channels, must be valid
125 * @param target The target response frame receiving the horizontal, vertical, and both diagonal Sobel responses, with `tSourceChannels * 4` channels, must be valid
126 * @param width The width of the frame in pixel, with range [3, infinity)
127 * @param height The height of the frame in pixel, with range [3, infinity)
128 * @param sourcePaddingElements Optional padding at the end of each source row in elements, with range [0, infinity)
129 * @param targetPaddingElements Optional padding at the end of each target row in elements, with range [0, infinity)
130 * @param worker Optional worker object to distribute the computational load
131 * @tparam TTarget The data type of the response values, either `int8_t` or `int16_t`
132 * @tparam tSourceChannels The number of channels of the source frame, with range [1, infinity)
133 */
134 template <typename TTarget, unsigned int tSourceChannels>
135 static inline void filter8BitPerChannel(const uint8_t* source, TTarget* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
136
137 /**
138 * Determines the maximum of the absolute horizontal and vertical Sobel filter.
139 * If the target response data type is selected to be `uint8_t`, each filter response is normalized by 1/16 to fit into the value range [0, 255].<br>
140 * If the target response data type is selected to be `uint16_t` no normalization will be applied.
141 * The border pixels are set to zero.
142 * @param source The source frame to which the Scharr filter will be applied, with `tSourceChannels` channels, must be valid
143 * @param target The target response frame receiving the maximal Scharr responses, with `tSourceChannels` channels, must be valid
144 * @param width The width of the frame in pixel, with range [3, infinity)
145 * @param height The height of the frame in pixel, with range [3, infinity)
146 * @param sourcePaddingElements Optional padding at the end of each source row in elements, with range [0, infinity)
147 * @param targetPaddingElements Optional padding at the end of each target row in elements, with range [0, infinity)
148 * @param worker Optional worker object to distribute the computational load
149 * @tparam TTarget The data type of the response values, either `uint8_t` or `uint16_t`
150 * @tparam tSourceChannels The number of channels of the source frame, with range [1, infinity)
151 */
152 template <typename TTarget, unsigned int tSourceChannels>
153 static inline void filterHorizontalVerticalMaximumAbsolute8BitPerChannel(const uint8_t* source, TTarget* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
154
155 /**
156 * Determines the maximum of the absolute horizontal and vertical Sobel filter for a given pixel.
157 * If the target response data type is selected to be `uint8_t`, each filter response is normalized by 1/4 to fit into the value range [0, 255].<br>
158 * If the target response data type is selected to be `uint16_t` no normalization will be applied.
159 * The border pixels are set to zero.
160 * @param source The source frame to filter, with `tChannels` channels, must be valid
161 * @param width The width of the frame in pixel, with range [3, infinity)
162 * @param height The height of the frame in pixel, with range [3, infinity)
163 * @param x Horizontal filter position in pixel, with range [0, width - 1]
164 * @param y Vertical filter position in pixel, with range [0, height - 1]
165 * @param response The resulting filter response for the defined pixel, with `tChannels` channels, must be valid
166 * @param sourcePaddingElements The number of padding elements at the end of each source row, with range [0, infinity)
167 * @tparam TTarget The data type of the response values, either `uint8_t` or `uint16_t`
168 * @tparam tChannels The number of frame channels, with range [1, infinity)
169 * @tparam tIsCorePixel True, if the pixel position is known to be a core pixel (with range [1, width - 2]x[1, height - 2]; False, if the pixel position can be a border pixel as well
170 */
171 template <typename TTarget, unsigned int tChannels, bool tIsCorePixel = false>
172 static inline void filterPixelHorizontalVerticalMaximum8BitPerChannel(const uint8_t* const source, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, TTarget* const response, unsigned int sourcePaddingElements);
173
174 /**
175 * Horizontal and vertical Sobel filter for a pixel.
176 * If the target response data type is selected to be `int8_t`, each filter response is normalized by 1/8 to fit into the value range [-128, 127].<br>
177 * If the target response data type is selected to be `int16_t` no normalization will be applied.
178 * The border pixels are set to zero.
179 * @param source The source frame in which the filter will be applied, with `tSourceChannels` channels, must be valid
180 * @param width The width of the frame in pixel, with range [3, infinity)
181 * @param height The height of the frame in pixel, with range [3, infinity)
182 * @param x Horizontal filter position with range [0, width - 1]
183 * @param y Vertical filter position with range [0, height -1]
184 * @param response The resulting pixel filter response, with `tSourceChannels * 2` channels, must be valid
185 * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
186 * @tparam TTarget The data type of the response values, either `int8_t` or `int16_t`
187 * @tparam tChannels The number of frame channels, with range [1, infinity)
188 */
189 template <typename TTarget, unsigned int tSourceChannels>
190 static inline void filterPixelHorizontalVertical8BitPerChannel(const uint8_t* source, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, TTarget* response, const unsigned int sourcePaddingElements);
191
192 /**
193 * Horizontal and vertical Sobel filter for a pixel not at the boundary of the frame (in the inner core of the frame).
194 * If the target response data type is selected to be `int8_t`, each filter response is normalized by 1/8 to fit into the value range [-128, 127].<br>
195 * If the target response data type is selected to be `int16_t` no normalization will be applied.
196 * @param source The position in the source frame at that the filter has to be applied, the position inside the frame has to fit into the ranges [1, width - 2]x[1, height - 2], with `tChannels` channels, must be valid
197 * @param width The width of the frame in pixel, with `tSourceChannels` channels, with range [3, infinity)
198 * @param response The resulting pixel filter response, with `tSourceChannels * 2` channels, must be valid
199 * @param sourcePaddingElements Optional padding at the end of each source row in elements, with range [0, infinity)
200 * @tparam TTarget The data type of the response values, either 'int8_t' or 'int16_t'
201 * @tparam tChannels The number of frame channels, with range [1, infinity)
202 */
203 template <typename TTarget, unsigned int tSourceChannels>
204 static inline void filterPixelCoreHorizontalVertical8BitPerChannel(const uint8_t* source, const unsigned int width, TTarget* response, const unsigned int sourcePaddingElements);
205
206 /**
207 * Determines the squared Sobel filter responses (three products) for a 1 channel 8 bit pixel based on a horizontal and on a vertical Sobel filter (Ix, Iy).
208 * The first element is the squared horizontal response (Ixx = Ix * Ix), the second the squared vertical response (Iyy = Iy * Iy) and the third is the product between horizontal and vertical response (Ixy = Ix * Iy).
209 * @param source The pointer into the source frame at which the filter has to be applied, the position inside the frame has to fit into the ranges [1, width - 2]x[1, height - 2]
210 * @param width The width of the frame in pixel, with range [3, infinity)
211 * @param responses The three resulting pixel filter responses, with order: Ixx, Iyy, Ixy, must be valid
212 * @param paddingElements Optional padding at the end of each frame row in elements, with range [0, infinity)
213 * @tparam TTarget The data type of the response values, either 'int8_t', 'int16_t', or 'int32_t'
214 * @tparam tNormalizationDenominator The normalization factor for each individual directional response before they will be squared, either 1, 4, or 8
215 * @tparam tRoundedNormalization True, to apply a rounded normalization; False, to apply a normalization without rounding (ignored for floating point values)
216 */
217 template <typename TTarget, TTarget tNormalizationDenominator, bool tRoundedNormalization = false>
218 static inline void filterPixelCoreHorizontalVertical3Squared1Channel8Bit(const uint8_t* source, const unsigned int width, TTarget* responses, const unsigned int paddingElements);
219
220 /**
221 * Determines the squared Sobel filter responses (three products) for a 1 channel 8 bit row based on a horizontal and on a vertical Sobel filter (Ix, Iy).
222 * The tree individual response products are stored in individual buffers.<br>
223 * Each filter response is normalized by 1/8, so that the products Ixx, Iyy and Ixy fit into the range [-(128 * 128), 127 * 127].
224 * One buffer for Ixx (= Ix * Ix) responses, one buffer for Iyy (= Iy * Iy) responses, and one buffer for Ixy (= Ix * Iy) responses.<br>
225 * The first filter response will be for the second pixel within the given row.
226 * @param row The row of a frame at which the filtering starts, the row must not be the first or last row in the frame, must be valid
227 * @param width The width of the frame in pixel, with range [10, infinity)
228 * @param elements The number of elements within the row for which the filter response will be determined, with range [8, width - 2]
229 * @param paddingElements The number of padding elements at the end of each row, with range [0, infinity)
230 * @param responsesXX The resulting Ixx (= Ix * Ix) responses, the buffer must be large enough to receive 'elements' values, must be valid
231 * @param responsesYY The resulting Iyy (= Iy * Iy) responses, the buffer must be large enough to receive 'elements' values, must be valid
232 * @param responsesXY The resulting Ixy (= Ix * Iy) responses, the buffer must be large enough to receive 'elements' values, must be valid
233 */
234 static void filterHorizontalVertical3Squared1Channel8BitRow(const uint8_t* row, const unsigned int width, const unsigned int elements, const unsigned int paddingElements, int16_t* responsesXX, int16_t* responsesYY, int16_t* responsesXY);
235
236 private:
237
238 /**
239 * Applies the horizontal and vertical Sobel filter to one row of a source frame.
240 * @param sourceRow The row of the source frame, must be valid
241 * @param targetRow The row of the target response frame, must be valid
242 * @param width The width of the source and target frame in pixel, with range [3, infinity)
243 * @param height The height of the source and target frame in pixel, with range [3, infinity)
244 * @param rowIndex The index of the row to which the filter is applied, with range [0, height - 1]
245 * @param sourceStrideElements The number of elements between the start of two consecutive source rows, with range [width * tSourceChannels, infinity)
246 * @param targetStrideElements The number of elements between the start of two consecutive target rows, with range [width * tTargetChannels, infinity)
247 * @tparam TSource The data type of the source frame, must be `uint8_t`
248 * @tparam TTarget The data type oft he target response frame, must be `int8_t` or `int16_t`
249 * @tparam tSourceChannels The number of channels the source frame has, with range [1, infinity)
250 * @tparam tTargetChannels The number of channels the target frame has, must be `tSourceChannels * 2`
251 */
252 template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
253 static void filterHorizontalVerticalRow(const TSource* sourceRow, TTarget* targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int targetStrideElements);
254
255 /**
256 * Applies the diagonal (45 and 135 degree) Sobel filter to one row of a source frame.
257 * @param sourceRow The row of the source frame, must be valid
258 * @param targetRow The row of the target response frame, must be valid
259 * @param width The width of the source and target frame in pixel, with range [3, infinity)
260 * @param height The height of the source and target frame in pixel, with range [3, infinity)
261 * @param rowIndex The index of the row to which the filter is applied, with range [0, height - 1]
262 * @param sourceStrideElements The number of elements between the start of two consecutive source rows, with range [width * tSourceChannels, infinity)
263 * @param targetStrideElements The number of elements between the start of two consecutive target rows, with range [width * tTargetChannels, infinity)
264 * @tparam TSource The data type of the source frame, must be `uint8_t`
265 * @tparam TTarget The data type oft he target response frame, must be `int8_t` or `int16_t`
266 * @tparam tSourceChannels The number of channels the source frame has, with range [1, infinity)
267 * @tparam tTargetChannels The number of channels the target frame has, must be `tSourceChannels * 2`
268 */
269 template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
270 static void filterDiagonalRow(const TSource* sourceRow, TTarget* targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int targetStrideElements);
271
272
273 /**
274 * Applies the horizontal, vertical, and diagonal Sobel filter to one row of a source frame.
275 * @param sourceRow The row of the source frame, must be valid
276 * @param targetRow The row of the target response frame, must be valid
277 * @param width The width of the source and target frame in pixel, with range [3, infinity)
278 * @param height The height of the source and target frame in pixel, with range [3, infinity)
279 * @param rowIndex The index of the row to which the filter is applied, with range [0, height - 1]
280 * @param sourceStrideElements The number of elements between the start of two consecutive source rows, with range [width * tSourceChannels, infinity)
281 * @param targetStrideElements The number of elements between the start of two consecutive target rows, with range [width * tTargetChannels, infinity)
282 * @tparam TSource The data type of the source frame, must be `uint8_t`
283 * @tparam TTarget The data type oft he target response frame, must be `int8_t` or `int16_t`
284 * @tparam tSourceChannels The number of channels the source frame has, with range [1, infinity)
285 * @tparam tTargetChannels The number of channels the target frame has, must be `tSourceChannels * 2`
286 */
287 template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
288 static void filterRow(const TSource* sourceRow, TTarget* targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int targetStrideElements);
289
290 /**
291 * Applies the maximum of the absolute horizontal and vertical Sobel filter to one row of a source frame.
292 * @param sourceRow The row of the source frame, must be valid
293 * @param targetRow The row of the target response frame, must be valid
294 * @param width The width of the source and target frame in pixel, with range [3, infinity)
295 * @param height The height of the source and target frame in pixel, with range [3, infinity)
296 * @param rowIndex The index of the row to which the filter is applied, with range [0, height - 1]
297 * @param sourceStrideElements The number of elements between the start of two consecutive source rows, with range [width * tSourceChannels, infinity)
298 * @param targetStrideElements The number of elements between the start of two consecutive target rows, with range [width * tTargetChannels, infinity)
299 * @tparam TSource The data type of the source frame, must be `uint8_t`
300 * @tparam TTarget The data type oft he target response frame, must be `int8_t` or `int16_t`
301 * @tparam tSourceChannels The number of channels the source frame has, with range [1, infinity)
302 * @tparam tTargetChannels The number of channels the target frame has, must be `tSourceChannels * 2`
303 */
304 template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
305 static void filterHorizontalVerticalMaximumAbsoluteRow(const TSource* sourceRow, TTarget* targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int targetStrideElements);
306
307#if defined(OCEAN_HARDWARE_SSE_VERSION) && OCEAN_HARDWARE_SSE_VERSION >= 41
308
309 /**
310 * Block based SSE implementation of horizontal and vertical Sobel filter for 8 bit pixel.
311 * This variant calculates the Sobel response of a block consisting of 3 consecutive rows each with 16 consecutive pixel, i.e. returns 14 response values for each direction.<br>
312 * Responses are returned in SSE registers and are not normalized, each response value is of type int16_t (16 bit).
313 * @param source0 First row of input frame to filter, must be valid
314 * @param source1 Second row of input frame to filter, must be valid
315 * @param source2 Third row of input frame to filter, must be valid
316 * @param response_x_low Contains first 8 horizontal response values (each size of 2 bytes)
317 * @param response_x_high Contains remaining 6 horizontal response values (each size of 2 bytes, beginning with least significant bit)
318 * @param response_y_low Contains first 8 vertical response values (each size of 2 bytes)
319 * @param response_y_high Contains remaining 6 vertical response values (each size of 2 bytes, beginning with least significant bit)
320 */
321 static inline void filterHorizontalVertical8BitBlock14SSE(const uint8_t* source0, const uint8_t* source1, const uint8_t* source2, __m128i& response_x_low, __m128i& response_x_high, __m128i& response_y_low, __m128i& response_y_high);
322
323 /**
324 * SSE block based horizontal and vertical Sobel filter for 1 channel 8 bit frame. <br>
325 * Responses of a block (3 consecutive rows, each with 16 consecutive pixel) are calculated, yielding 14 response values for each direction. <br>
326 * The two different filter responses are zipped, thus the target must provide 14x2x16 bit.
327 * @param source The source frame to filter, must be valid
328 * @param strideElements The stride of the source frame in elements, which is width of the frame plus padding elements, with range [16, infinity)
329 * @param response Pixel filter responses, must be valid
330 */
331 static inline void filterHorizontalVertical1Channel8BitBlock14SSE(const uint8_t* source, const unsigned int strideElements, int16_t* response);
332
333 /**
334 * SSE block based horizontal and vertical Sobel filter for 1 channel 8 bit frame. <br>
335 * Responses of a block (3 consecutive rows, each with 16 consecutive pixel) are calculated, yielding 14 response values for each direction. <br>
336 * Each resulting filter value is normalized by 1/8 to fit value range [-128, 127]
337 * The two different filter responses are zipped, thus the target must provide 14x2x16 bit.
338 * @param source The source frame to filter, must be valid
339 * @param strideElements The stride of the source frame in elements, which is width of the frame plus padding elements, with range [16, infinity)
340 * @param response Pixel filter responses, must be valid
341 */
342 static inline void filterHorizontalVertical1Channel8BitBlock14SSE(const uint8_t* source, const unsigned int strideElements, int8_t* response);
343
344#endif // OCEAN_HARDWARE_SSE_VERSION >= 41
345};
346
347template <typename TTarget, unsigned int tSourceChannels>
348inline void FrameFilterSobel::filterHorizontalVertical8BitPerChannel(const uint8_t* source, TTarget* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
349{
350 static_assert(std::is_same<TTarget, int8_t>::value || std::is_same<TTarget, int16_t>::value, "Invalid target data type!");
351 static_assert(tSourceChannels >= 1u, "Invalid channel number!");
352
353 ocean_assert(source != nullptr && target != nullptr);
354 ocean_assert(width >= 3u && height >= 3u);
355
356 //using TSource = uint8_t;
357 constexpr unsigned int tTargetChannels = tSourceChannels * 2u;
358
359 FrameChannels::applyRowOperator<uint8_t, TTarget, tSourceChannels, tTargetChannels>(source, target, width, height, sourcePaddingElements, targetPaddingElements, &filterHorizontalVerticalRow<uint8_t, TTarget, tSourceChannels, tTargetChannels>, worker);
360}
361
362template <typename TTarget, unsigned int tSourceChannels>
363inline void FrameFilterSobel::filterDiagonal8BitPerChannel(const uint8_t* source, TTarget* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
364{
365 static_assert(std::is_same<TTarget, int8_t>::value || std::is_same<TTarget, int16_t>::value, "Invalid target data type!");
366 static_assert(tSourceChannels >= 1u, "Invalid channel number!");
367
368 ocean_assert(source != nullptr && target != nullptr);
369 ocean_assert(width >= 3u && height >= 3u);
370
371 //using TSource = uint8_t;
372 constexpr unsigned int tTargetChannels = tSourceChannels * 2u;
373
374 FrameChannels::applyRowOperator<uint8_t, TTarget, tSourceChannels, tTargetChannels>(source, target, width, height, sourcePaddingElements, targetPaddingElements, &filterDiagonalRow<uint8_t, TTarget, tSourceChannels, tTargetChannels>, worker);
375}
376
377template <typename TTarget, unsigned int tSourceChannels>
378inline void FrameFilterSobel::filter8BitPerChannel(const uint8_t* source, TTarget* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
379{
380 static_assert(std::is_same<TTarget, int8_t>::value || std::is_same<TTarget, int16_t>::value, "Invalid target data type!");
381 static_assert(tSourceChannels >= 1u, "Invalid channel number!");
382
383 ocean_assert(source != nullptr && target != nullptr);
384 ocean_assert(width >= 3u && height >= 3u);
385
386 //using TSource = uint8_t;
387 constexpr unsigned int tTargetChannels = tSourceChannels * 4u;
388
389 FrameChannels::applyRowOperator<uint8_t, TTarget, tSourceChannels, tTargetChannels>(source, target, width, height, sourcePaddingElements, targetPaddingElements, &filterRow<uint8_t, TTarget, tSourceChannels, tTargetChannels>, worker);
390}
391
392template <typename TTarget, unsigned int tSourceChannels>
393inline void FrameFilterSobel::filterHorizontalVerticalMaximumAbsolute8BitPerChannel(const uint8_t* const source, TTarget* const target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
394{
395 static_assert(std::is_same<TTarget, uint8_t>::value || std::is_same<TTarget, uint16_t>::value, "Invalid target data type!");
396 static_assert(tSourceChannels >= 1u, "Invalid channel number!");
397
398 ocean_assert(source != nullptr && target != nullptr);
399 ocean_assert(width >= 3u && height >= 3u);
400
401 //using TSource = uint8_t;
402 constexpr unsigned int tTargetChannels = tSourceChannels;
403
404 FrameChannels::applyRowOperator<uint8_t, TTarget, tSourceChannels, tTargetChannels>(source, target, width, height, sourcePaddingElements, targetPaddingElements, &filterHorizontalVerticalMaximumAbsoluteRow<uint8_t, TTarget, tSourceChannels, tTargetChannels>, worker);
405}
406
407template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
408void FrameFilterSobel::filterHorizontalVerticalRow(const TSource* sourceRow, TTarget* targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int /*targetStrideElements*/)
409{
410 static_assert(std::is_same<TSource, uint8_t>::value, "Invalid source data type!");
411 static_assert(std::is_same<TTarget, int8_t>::value || std::is_same<TTarget, int16_t>::value, "Invalid target data type!");
412
413 static_assert(tSourceChannels >= 1u, "Invalid source channel number!");
414 static_assert(tTargetChannels == tSourceChannels * 2u, "Invalid target channel number!");
415
416 ocean_assert(width >= 3u && height >= 3u);
417
418 if (rowIndex == 0u || rowIndex == height - 1u)
419 {
420 // setting the first row and last row to zero
421
422 memset(targetRow, 0, width * tTargetChannels * sizeof(TTarget));
423 return;
424 }
425
426 // setting first pixel to zero
427
428 for (unsigned int n = 0u; n < tTargetChannels; ++n)
429 {
430 targetRow[n] = TTarget(0);
431 }
432
433 targetRow += tTargetChannels;
434
435#if defined(OCEAN_HARDWARE_SSE_VERSION) && OCEAN_HARDWARE_SSE_VERSION >= 41
436
437 if constexpr (tSourceChannels == 1u)
438 {
439 if (width >= 16u)
440 {
441 const unsigned int blockNumber = (width - 2u) / 14u;
442
443 for (unsigned int iBlock = 0u; iBlock < blockNumber; iBlock++)
444 {
445 filterHorizontalVertical1Channel8BitBlock14SSE(sourceRow, sourceStrideElements, targetRow);
446 targetRow += 14u * 2u;
447 sourceRow += 14;
448 }
449
450 // calculate remaining elements
451
452 const unsigned int blockRest = (width - 2u) % 14u;
453
454 if (blockRest > 0u)
455 {
456 // shift back pointers
457 sourceRow -= (14u - blockRest);
458 targetRow -= (14u - blockRest) * 2u;
459
460 filterHorizontalVertical1Channel8BitBlock14SSE(sourceRow, sourceStrideElements, targetRow);
461
462 // set pointers to end of line
463 targetRow += 14u * 2u;
464 }
465
466 // setting last pixel to zero
467 for (unsigned int n = 0u; n < tTargetChannels; ++n)
468 {
469 targetRow[n] = TTarget(0);
470 }
471
472 return;
473 }
474 }
475
476#endif
477
478 const uint8_t* source0 = sourceRow - sourceStrideElements;
479 const uint8_t* source1 = sourceRow;
480 const uint8_t* source2 = sourceRow + sourceStrideElements;
481
482 for (unsigned int x = 1u; x < width - 1u; ++x)
483 {
484 if constexpr (std::is_same<TTarget, int8_t>::value)
485 {
486 for (unsigned int n = 0u; n < tSourceChannels; ++n)
487 {
488 // | -1 0 1 |
489 // | -2 0 2 | / 8
490 // | -1 0 1 |
491 *targetRow++ = TTarget((*(source0 + tSourceChannels * 2u) - *(source0) + (*(source1 + tSourceChannels * 2u) - *(source1)) * 2 + *(source2 + tSourceChannels * 2u) - *(source2)) / 8);
492
493 // | -1 -2 -1 |
494 // | 0 0 0 | / 8
495 // | 1 2 1 |
496 *targetRow++ = TTarget((*(source2) + (*(source2 + tSourceChannels) - *(source0 + tSourceChannels)) * 2 + *(source2 + tSourceChannels * 2u) - *(source0) - *(source0 + tSourceChannels * 2u)) / 8);
497
498 ++source0;
499 ++source1;
500 ++source2;
501 }
502 }
503 else
504 {
505 ocean_assert((std::is_same<TTarget, int16_t>::value));
506
507 for (unsigned int n = 0u; n < tSourceChannels; ++n)
508 {
509 // | -1 0 1 |
510 // | -2 0 2 |
511 // | -1 0 1 |
512 *targetRow++ = TTarget(*(source0 + tSourceChannels * 2u) - *(source0) + (*(source1 + tSourceChannels * 2u) - *(source1)) * 2 + *(source2 + tSourceChannels * 2u) - *(source2));
513
514 // | -1 -2 -1 |
515 // | 0 0 0 |
516 // | 1 2 1 |
517 *targetRow++ = TTarget(*(source2) + (*(source2 + tSourceChannels) - *(source0 + tSourceChannels)) * 2 + *(source2 + tSourceChannels * 2u) - *(source0) - *(source0 + tSourceChannels * 2u));
518
519 ++source0;
520 ++source1;
521 ++source2;
522 }
523 }
524 }
525
526 // setting last pixel to zero
527 for (unsigned int n = 0u; n < tTargetChannels; ++n)
528 {
529 targetRow[n] = TTarget(0);
530 }
531}
532
533template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
534void FrameFilterSobel::filterDiagonalRow(const TSource* sourceRow, TTarget* targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int /*targetStrideElements*/)
535{
536 static_assert(std::is_same<TSource, uint8_t>::value, "Invalid source data type!");
537 static_assert(std::is_same<TTarget, int8_t>::value || std::is_same<TTarget, int16_t>::value, "Invalid target data type!");
538
539 static_assert(tSourceChannels >= 1u, "Invalid source channel number!");
540 static_assert(tTargetChannels == tSourceChannels * 2u, "Invalid target channel number!");
541
542 ocean_assert(width >= 3u && height >= 3u);
543
544 if (rowIndex == 0u || rowIndex == height - 1u)
545 {
546 // setting the first row and last row to zero
547
548 memset(targetRow, 0, width * tTargetChannels * sizeof(TTarget));
549 return;
550 }
551
552 // setting first pixel to zero
553
554 for (unsigned int n = 0u; n < tTargetChannels; ++n)
555 {
556 targetRow[n] = TTarget(0);
557 }
558
559 targetRow += tTargetChannels;
560
561 const uint8_t* source0 = sourceRow - sourceStrideElements;
562 const uint8_t* source1 = sourceRow;
563 const uint8_t* source2 = sourceRow + sourceStrideElements;
564
565 for (unsigned int x = 1u; x < width - 1u; ++x)
566 {
567 if constexpr (std::is_same<TTarget, int8_t>::value)
568 {
569 for (unsigned int n = 0u; n < tSourceChannels; ++n)
570 {
571 // | -2 -1 0 |
572 // | -1 0 1 | / 8
573 // | 0 1 2 |
574 *targetRow++ = TTarget((*(source1 + tSourceChannels * 2u) + *(source2 + tSourceChannels) + (*(source2 + tSourceChannels * 2u) - *(source0)) * 2 - *(source0 + tSourceChannels) - *(source1)) / 8);
575
576 // | 0 -1 -2 |
577 // | 1 0 -1 | / 8
578 // | 2 1 0 |
579 *targetRow++ = TTarget((*(source1) + *(source2 + tSourceChannels) + (*(source2) - *(source0 + tSourceChannels * 2u)) * 2 - *(source0 + tSourceChannels) - *(source1 + tSourceChannels * 2u)) / 8);
580
581 ++source0;
582 ++source1;
583 ++source2;
584 }
585 }
586 else
587 {
588 ocean_assert((std::is_same<TTarget, int16_t>::value));
589
590 for (unsigned int n = 0u; n < tSourceChannels; ++n)
591 {
592 // | -2 -1 0 |
593 // | -1 0 1 |
594 // | 0 1 2 |
595 *targetRow++ = TTarget(*(source1 + tSourceChannels * 2u) + *(source2 + tSourceChannels) + (*(source2 + tSourceChannels * 2u) - *(source0)) * 2 - *(source0 + tSourceChannels) - *(source1));
596
597 // | 0 -1 -2 |
598 // | 1 0 -1 |
599 // | 2 1 0 |
600 *targetRow++ = TTarget(*(source1) + *(source2 + tSourceChannels) + (*(source2) - *(source0 + tSourceChannels * 2u)) * 2 - *(source0 + tSourceChannels) - *(source1 + tSourceChannels * 2u));
601
602 ++source0;
603 ++source1;
604 ++source2;
605 }
606 }
607 }
608
609 // setting last pixel to zero
610 for (unsigned int n = 0u; n < tTargetChannels; ++n)
611 {
612 targetRow[n] = TTarget(0);
613 }
614}
615
616template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
617void FrameFilterSobel::filterRow(const TSource* sourceRow, TTarget* targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int /*targetStrideElements*/)
618{
619 static_assert(std::is_same<TSource, uint8_t>::value, "Invalid source data type!");
620 static_assert(std::is_same<TTarget, int8_t>::value || std::is_same<TTarget, int16_t>::value, "Invalid target data type!");
621
622 static_assert(tSourceChannels >= 1u, "Invalid source channel number!");
623 static_assert(tTargetChannels == tSourceChannels * 4u, "Invalid target channel number!");
624
625 ocean_assert(width >= 3u && height >= 3u);
626
627 if (rowIndex == 0u || rowIndex == height - 1u)
628 {
629 // setting the first row and last row to zero
630
631 memset(targetRow, 0, width * tTargetChannels * sizeof(TTarget));
632 return;
633 }
634
635 const uint8_t* source0 = sourceRow - sourceStrideElements;
636 const uint8_t* source1 = sourceRow;
637 const uint8_t* source2 = sourceRow + sourceStrideElements;
638
639 // setting first pixel to zero
640
641 for (unsigned int n = 0u; n < tTargetChannels; ++n)
642 {
643 targetRow[n] = TTarget(0);
644 }
645
646 targetRow += tTargetChannels;
647
648 for (unsigned int x = 1u; x < width - 1u; ++x)
649 {
650 if constexpr (std::is_same<TTarget, int8_t>::value)
651 {
652 for (unsigned int n = 0u; n < tSourceChannels; ++n)
653 {
654 // | -1 0 1 |
655 // | -2 0 2 | / 8
656 // | -1 0 1 |
657 *targetRow++ = TTarget((*(source0 + tSourceChannels * 2u) - *(source0) + (*(source1 + tSourceChannels * 2u) - *(source1)) * 2 + *(source2 + tSourceChannels * 2u) - *(source2)) / 8);
658
659 // | -1 -2 -1 |
660 // | 0 0 0 | / 8
661 // | 1 2 1 |
662 *targetRow++ = TTarget((*(source2) + (*(source2 + tSourceChannels) - *(source0 + tSourceChannels)) * 2 + *(source2 + tSourceChannels * 2u) - *(source0) - *(source0 + tSourceChannels * 2u)) / 8);
663
664 // | -2 -1 0 |
665 // | -1 0 1 | / 8
666 // | 0 1 2 |
667 *targetRow++ = TTarget((*(source1 + tSourceChannels * 2u) + *(source2 + tSourceChannels) + (*(source2 + tSourceChannels * 2u) - *(source0)) * 2 - *(source0 + tSourceChannels) - *(source1)) / 8);
668
669 // | 0 -1 -2 |
670 // | 1 0 -1 | / 8
671 // | 2 1 0 |
672 *targetRow++ = TTarget((*(source1) + *(source2 + tSourceChannels) + (*(source2) - *(source0 + tSourceChannels * 2u)) * 2 - *(source0 + tSourceChannels) - *(source1 + tSourceChannels * 2u)) / 8);
673
674 ++source0;
675 ++source1;
676 ++source2;
677 }
678 }
679 else
680 {
681 ocean_assert((std::is_same<TTarget, int16_t>::value));
682
683 for (unsigned int n = 0u; n < tSourceChannels; ++n)
684 {
685 // | -1 0 1 |
686 // | -2 0 2 |
687 // | -1 0 1 |
688 *targetRow++ = TTarget(*(source0 + tSourceChannels * 2u) - *(source0) + (*(source1 + tSourceChannels * 2u) - *(source1)) * 2 + *(source2 + tSourceChannels * 2u) - *(source2));
689
690 // | -1 -2 -1 |
691 // | 0 0 0 |
692 // | 1 2 1 |
693 *targetRow++ = TTarget(*(source2) + (*(source2 + tSourceChannels) - *(source0 + tSourceChannels)) * 2 + *(source2 + tSourceChannels * 2u) - *(source0) - *(source0 + tSourceChannels * 2u));
694
695 // | -2 -1 0 |
696 // | -1 0 1 |
697 // | 0 1 2 |
698 *targetRow++ = TTarget(*(source1 + tSourceChannels * 2u) + *(source2 + tSourceChannels) + (*(source2 + tSourceChannels * 2u) - *(source0)) * 2 - *(source0 + tSourceChannels) - *(source1));
699
700 // | 0 -1 -2 |
701 // | 1 0 -1 |
702 // | 2 1 0 |
703 *targetRow++ = TTarget(*(source1) + *(source2 + tSourceChannels) + (*(source2) - *(source0 + tSourceChannels * 2u)) * 2 - *(source0 + tSourceChannels) - *(source1 + tSourceChannels * 2u));
704
705 ++source0;
706 ++source1;
707 ++source2;
708 }
709 }
710 }
711
712 // setting last pixel to zero
713 for (unsigned int n = 0u; n < tTargetChannels; ++n)
714 {
715 targetRow[n] = TTarget(0);
716 }
717}
718
719template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
720void FrameFilterSobel::filterHorizontalVerticalMaximumAbsoluteRow(const TSource* sourceRow, TTarget* targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int /*targetStrideElements*/)
721{
722 static_assert(std::is_same<TSource, uint8_t>::value, "Invalid source data type!");
723 static_assert(std::is_same<TTarget, uint8_t>::value || std::is_same<TTarget, uint16_t>::value, "Invalid target data type!");
724
725 static_assert(tSourceChannels >= 1u, "Invalid source channel number!");
726 static_assert(tTargetChannels == tSourceChannels, "Invalid target channel number!");
727
728 ocean_assert(width >= 3u && height >= 3u);
729
730 if (rowIndex == 0u || rowIndex == height - 1u)
731 {
732 // setting the first row and last row to zero
733
734 memset(targetRow, 0, width * tTargetChannels * sizeof(TTarget));
735 return;
736 }
737
738 const uint8_t* source0 = sourceRow - sourceStrideElements;
739 const uint8_t* source1 = sourceRow;
740 const uint8_t* source2 = sourceRow + sourceStrideElements;
741
742 // setting first pixel to zero
743
744 for (unsigned int n = 0u; n < tTargetChannels; ++n)
745 {
746 targetRow[n] = TTarget(0);
747 }
748
749 targetRow += tTargetChannels;
750
751 for (unsigned int x = 1u; x < width - 1u; ++x)
752 {
753 if constexpr (std::is_same<TTarget, uint8_t>::value)
754 {
755 for (unsigned int n = 0u; n < tSourceChannels; ++n)
756 {
757 // | -1 0 1 |
758 // | -2 0 2 | / 4
759 // | -1 0 1 |
760 *targetRow++ = TTarget((max(abs(*(source0 + tSourceChannels * 2u) - *(source0) + (*(source1 + tSourceChannels * 2u) - *(source1)) * 2 + *(source2 + tSourceChannels * 2u) - *(source2)),
761
762 // | -1 -2 -1 |
763 // | 0 0 0 | / 4
764 // | 1 2 1 |
765 abs(*(source2) + (*(source2 + tSourceChannels) - *(source0 + tSourceChannels)) * 2 + *(source2 + tSourceChannels * 2u) - *(source0) - *(source0 + tSourceChannels * 2u))) + 2u) / 4u);
766
767 ++source0;
768 ++source1;
769 ++source2;
770 }
771 }
772 else
773 {
774 ocean_assert((std::is_same<TTarget, uint16_t>::value));
775
776 for (unsigned int n = 0u; n < tSourceChannels; ++n)
777 {
778 // | -1 0 1 |
779 // | -2 0 2 |
780 // | -1 0 1 |
781 *targetRow++ = TTarget(max(abs(*(source0 + tSourceChannels * 2u) - *(source0) + (*(source1 + tSourceChannels * 2u) - *(source1)) * 2 + *(source2 + tSourceChannels * 2u) - *(source2)),
782
783 // | -1 -2 -1 |
784 // | 0 0 0 |
785 // | 1 2 1 |
786 abs(*(source2) + (*(source2 + tSourceChannels) - *(source0 + tSourceChannels)) * 2 + *(source2 + tSourceChannels * 2u) - *(source0) - *(source0 + tSourceChannels * 2u))));
787
788 ++source0;
789 ++source1;
790 ++source2;
791 }
792 }
793 }
794
795 // setting last pixel to zero
796 for (unsigned int n = 0u; n < tTargetChannels; ++n)
797 {
798 targetRow[n] = TTarget(0);
799 }
800}
801
802template <typename TTarget, unsigned int tSourceChannels>
803inline void FrameFilterSobel::filterPixelHorizontalVertical8BitPerChannel(const uint8_t* source, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, TTarget* response, const unsigned int sourcePaddingElements)
804{
805 static_assert(std::is_same<TTarget, int8_t>::value || std::is_same<TTarget, int16_t>::value, "Invalid target data type!");
806 static_assert(tSourceChannels >= 1u, "Invalid channel number!");
807
808 ocean_assert(source != nullptr && response != nullptr);
809 ocean_assert(x < width && y < height);
810 ocean_assert(width >= 3u && height >= 3u);
811
812 ocean_assert((x - 1u < width - 2u && y - 1u < height - 2u) == (x >= 1u && y >= 1u && x + 1u < width && y + 1u < height));
813
814 if (x - 1u < width - 2u && y - 1u < height - 2u)
815 {
816 const unsigned int sourceStrideElements = width * tSourceChannels + sourcePaddingElements;
817
818 filterPixelCoreHorizontalVertical8BitPerChannel<TTarget, tSourceChannels>(source + y * sourceStrideElements + x * tSourceChannels, width, response, sourcePaddingElements);
819 }
820 else
821 {
822 for (unsigned int n = 0u; n < tSourceChannels * 2u; ++n)
823 {
824 response[n] = TTarget(0);
825 }
826 }
827}
828
829template <typename TTarget, unsigned int tSourceChannels>
830inline void FrameFilterSobel::filterPixelCoreHorizontalVertical8BitPerChannel(const uint8_t* source, const unsigned int width, TTarget* response, const unsigned int sourcePaddingElements)
831{
832 static_assert(std::is_same<TTarget, int8_t>::value || std::is_same<TTarget, int16_t>::value, "Invalid target data type!");
833 static_assert(tSourceChannels >= 1u, "Invalid channel number!");
834
835 ocean_assert(source != nullptr && response != nullptr);
836 ocean_assert(width >= 3u);
837
838 const unsigned int sourceStrideElements = width * tSourceChannels + sourcePaddingElements;
839
840 if constexpr (std::is_same<TTarget, int8_t>::value)
841 {
842 for (unsigned int n = 0u; n < tSourceChannels; ++n)
843 {
844 // | -1 0 1 |
845 // | -2 0 2 | / 8
846 // | -1 0 1 |
847 *response++ = TTarget((*(source - sourceStrideElements + tSourceChannels) - *(source - sourceStrideElements - tSourceChannels) + (*(source + tSourceChannels) - *(source - tSourceChannels)) * 2 + *(source + sourceStrideElements + tSourceChannels) - *(source + sourceStrideElements - tSourceChannels)) / 8);
848
849 // | -1 -2 -1 |
850 // | 0 0 0 | / 8
851 // | 1 2 1 |
852 *response++ = TTarget((*(source + sourceStrideElements - tSourceChannels) + (*(source + sourceStrideElements) - *(source - sourceStrideElements)) * 2 + *(source + sourceStrideElements + tSourceChannels) - *(source - sourceStrideElements - tSourceChannels) - *(source - sourceStrideElements + tSourceChannels)) / 8);
853
854 ++source;
855 }
856 }
857 else
858 {
859 ocean_assert((std::is_same<TTarget, int16_t>::value));
860
861 for (unsigned int n = 0u; n < tSourceChannels; ++n)
862 {
863 // | -1 0 1 |
864 // | -2 0 2 |
865 // | -1 0 1 |
866 *response++ = TTarget(*(source - sourceStrideElements + tSourceChannels) - *(source - sourceStrideElements - tSourceChannels) + (*(source + tSourceChannels) - *(source - tSourceChannels)) * 2 + *(source + sourceStrideElements + tSourceChannels) - *(source + sourceStrideElements - tSourceChannels));
867
868 // | -1 -2 -1 |
869 // | 0 0 0 |
870 // | 1 2 1 |
871 *response++ = TTarget(*(source + sourceStrideElements - tSourceChannels) + (*(source + sourceStrideElements) - *(source - sourceStrideElements)) * 2 + *(source + sourceStrideElements + tSourceChannels) - *(source - sourceStrideElements - tSourceChannels) - *(source - sourceStrideElements + tSourceChannels));
872
873 ++source;
874 }
875 }
876}
877
878template <typename TTarget, TTarget tNormalizationDenominator, bool tRoundedNormalization>
879inline void FrameFilterSobel::filterPixelCoreHorizontalVertical3Squared1Channel8Bit(const uint8_t* source, const unsigned int width, TTarget* responses, const unsigned int paddingElements)
880{
881 static_assert(tNormalizationDenominator == 1 || tNormalizationDenominator == 4 || tNormalizationDenominator == 8, "Invalid normalization factor!");
882
883 ocean_assert(source != nullptr && responses != nullptr);
884 ocean_assert(width >= 3u);
885
886 const unsigned int strideElements = width + paddingElements;
887
888 // | -1 0 1 |
889 // | -2 0 2 |
890 // | -1 0 1 |
891 const TTarget horizontal = TTarget(FrameFilter::normalizeValue<int32_t, tNormalizationDenominator, tRoundedNormalization>(*(source - strideElements + 1u) - *(source - strideElements - 1u) + (*(source + 1u) - *(source - 1u)) * 2 + *(source + strideElements + 1u) - *(source + strideElements - 1u)));
892
893 // | -1 -2 -1 |
894 // | 0 0 0 |
895 // | 1 2 1 |
896 const TTarget vertical = TTarget(FrameFilter::normalizeValue<int32_t, tNormalizationDenominator, tRoundedNormalization>(*(source + strideElements - 1u) + (*(source + strideElements) - *(source - strideElements)) * 2 + *(source + strideElements + 1u) - *(source - strideElements - 1u) - *(source - strideElements + 1u)));
897
898 *responses++ = horizontal * horizontal;
899 *responses++ = vertical * vertical;
900 *responses = horizontal * vertical;
901}
902
903template <typename TTarget, unsigned int tChannels, bool tIsCorePixel>
904inline void FrameFilterSobel::filterPixelHorizontalVerticalMaximum8BitPerChannel(const uint8_t* const source, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, TTarget* const response, unsigned int sourcePaddingElements)
905{
906 static_assert(std::is_same<TTarget, uint8_t>::value || std::is_same<TTarget, uint16_t>::value, "Invalid target data type!");
907 static_assert(tChannels >= 1u, "Invalid channel number!");
908
909 ocean_assert(source != nullptr && response != nullptr);
910
911 ocean_assert((x >= 1u && x < width - 1u && y >= 1u && y < height - 1u) == (x - 1u < width - 2u && y - 1u < height - 2u));
912
913 if (tIsCorePixel || (x - 1u < width - 2u && y - 1u < height - 2u))
914 {
915 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
916
917 const uint8_t* source0 = source + (y - 1u) * sourceStrideElements + x * tChannels;
918 const uint8_t* source1 = source + (y + 0u) * sourceStrideElements + x * tChannels;
919 const uint8_t* source2 = source + (y + 1u) * sourceStrideElements + x * tChannels;
920
921 if (std::is_same<TTarget, uint8_t>::value)
922 {
923 for (unsigned int n = 0u; n < tChannels; ++n)
924 {
925 // | -1 0 1 |
926 // | -2 0 2 |
927 // | -1 0 1 |
928 response[n] = TTarget((max(abs(*(source0 + tChannels) - *(source0 - tChannels) + (*(source1 + tChannels) - *(source1 - tChannels)) * 2 + *(source2 + tChannels) - *(source2 - tChannels)),
929
930 // | -1 -2 -1 |
931 // | 0 0 0 |
932 // | 1 2 1 |
933 abs(*(source2 - tChannels) + (*(source2) - *(source0)) * 2 + *(source2 + tChannels) - *(source0 - tChannels) - *(source0 + tChannels))) + 2u) / 4u);
934
935 ++source0;
936 ++source1;
937 ++source2;
938 }
939 }
940 else
941 {
942 ocean_assert((std::is_same<TTarget, uint16_t>::value));
943
944 for (unsigned int n = 0u; n < tChannels; ++n)
945 {
946 // | -1 0 1 |
947 // | -2 0 2 |
948 // | -1 0 1 |
949 response[n] = TTarget(max(abs(*(source0 + tChannels) - *(source0 - tChannels) + (*(source1 + tChannels) - *(source1 - tChannels)) * 2 + *(source2 + tChannels) - *(source2 - tChannels)),
950
951 // | -1 -2 -1 |
952 // | 0 0 0 |
953 // | 1 2 1 |
954 abs(*(source2 - tChannels) + (*(source2) - *(source0)) * 2 + *(source2 + tChannels) - *(source0 - tChannels) - *(source0 + tChannels))));
955
956 ++source0;
957 ++source1;
958 ++source2;
959 }
960 }
961 }
962 else
963 {
964 for (unsigned int n = 0u; n < tChannels; ++n)
965 {
966 response[n] = TTarget(0);
967 }
968 }
969}
970
971#if defined(OCEAN_HARDWARE_SSE_VERSION) && OCEAN_HARDWARE_SSE_VERSION >= 41
972
973inline void FrameFilterSobel::filterHorizontalVertical8BitBlock14SSE(const uint8_t* source0, const uint8_t* source1, const uint8_t* source2, __m128i& response_x_low, __m128i& response_x_high, __m128i& response_y_low, __m128i& response_y_high)
974{
975 ocean_assert(source0 && source1 && source2);
976
977 // load 16 byte-elements of 3 consecutive rows
978 const __m128i row0 = _mm_lddqu_si128((__m128i*)source0);
979 const __m128i row1 = _mm_lddqu_si128((__m128i*)source1);
980 const __m128i row2 = _mm_lddqu_si128((__m128i*)source2);
981
982 // unpack 8-bit values to 16-bit vectors
983 // row = [15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0]
984 // row_low = [ 7 6 5 4 3 2 1 0]
985 // row_high = [15 14 13 12 11 10 9 8]
986 const __m128i row0_low = _mm_unpacklo_epi8(row0, _mm_set1_epi8(0u));
987 const __m128i row0_high = _mm_unpackhi_epi8(row0, _mm_set1_epi8(0u));
988 const __m128i row1_low = _mm_unpacklo_epi8(row1, _mm_set1_epi8(0u));
989 const __m128i row1_high = _mm_unpackhi_epi8(row1, _mm_set1_epi8(0u));
990 const __m128i row2_low = _mm_unpacklo_epi8(row2, _mm_set1_epi8(0u));
991 const __m128i row2_high = _mm_unpackhi_epi8(row2, _mm_set1_epi8(0u));
992
993 // double row0, row1 and row2
994 const __m128i row0_x2_high = _mm_slli_epi16(row0_high, 1);
995 const __m128i row1_x2_high = _mm_slli_epi16(row1_high, 1);
996 const __m128i row2_x2_high = _mm_slli_epi16(row2_high, 1);
997 const __m128i row0_x2_low = _mm_slli_epi16(row0_low, 1);
998 const __m128i row1_x2_low = _mm_slli_epi16(row1_low, 1);
999 const __m128i row2_x2_low = _mm_slli_epi16(row2_low, 1);
1000
1001 // vertical
1002 // | -1 -2 -1 |
1003 // | 0 0 0 |
1004 // | 1 2 1 |
1005
1006 // subtract element wise row0 from row2
1007 const __m128i diff_row02_high = _mm_sub_epi16(row2_high, row0_high);
1008 const __m128i diff_row02_low = _mm_sub_epi16(row2_low, row0_low);
1009
1010 const __m128i diff_row02_x2_high = _mm_sub_epi16(row2_x2_high, row0_x2_high);
1011 const __m128i diff_row02_x2_low = _mm_sub_epi16(row2_x2_low, row0_x2_low);
1012
1013 // add elements
1014 // row_sum_1 = [7 6 5 4 3 2 1 0] + [9 8 7 6 5 4 3 2]
1015 // row_sum_2 = [15 14 13 12 11 10 9 8] + [x x 15 14 13 12 11 10]
1016 const __m128i row02_sum_1 = _mm_add_epi16(diff_row02_low, _mm_or_si128(_mm_srli_si128(diff_row02_low, 4u), _mm_slli_si128(diff_row02_high, 12u)));
1017
1018 // [15 14 13 12 11 10 9 8] [xx xx 15 14 13 12 11 10]
1019 const __m128i row02_sum_2 = _mm_add_epi16(diff_row02_high, _mm_srli_si128(diff_row02_high, 4u));
1020
1021 // add double weighted elements [x 7 6 5 4 3 2 1] [8 x x x x x x x]
1022 response_y_low = _mm_adds_epi16(row02_sum_1, _mm_or_si128(_mm_srli_si128(diff_row02_x2_low, 2u), _mm_slli_si128(diff_row02_x2_high, 14u)));
1023
1024 response_y_high = _mm_adds_epi16(row02_sum_2, _mm_srli_si128(diff_row02_x2_high, 2u));
1025
1026 // normalize sums (shift sums to right by 3 - division by 8)
1027 //response_y_low = _mm_srai_epi16(addOffsetForRightShiftDivision(sum_vert_low), 3u);
1028 //response_y_high = _mm_srai_epi16(addOffsetForRightShiftDivision(sum_vert_high), 3u);
1029
1030 // horizontal
1031 // | -1 0 1 |
1032 // | -2 0 2 |
1033 // | -1 0 1 |
1034
1035 // [x x 7 6 5 4 3 2] [9 8 x x x x x x]
1036 const __m128i row0_low_shifted = _mm_or_si128(_mm_srli_si128(row0_low, 4u), _mm_slli_si128(row0_high, 12u));
1037
1038 // [x x 7 6 5 4 3 2] [9 8 x x x x x x ]
1039 const __m128i row1_x2_low_shifted = _mm_or_si128(_mm_srli_si128(row1_x2_low, 4u), _mm_slli_si128(row1_x2_high, 12u));
1040
1041 // [x x 7 6 5 4 3 2] [9 8 x x x x x x ]
1042 const __m128i row2_low_shifted = _mm_or_si128(_mm_srli_si128(row2_low, 4u), _mm_slli_si128(row2_high, 12u));
1043
1044 // subtract
1045 // diff_low = [9-7 8-6 7-5 6-4 5-3 4-2 3-1 2-0]
1046 // diff_high = [xxx xxx 15-13 14-12 13-11 12-10 11-9 10-8]
1047 const __m128i diff_cols_r0_low = _mm_sub_epi16(row0_low_shifted, row0_low);
1048 const __m128i diff_cols_r0_high = _mm_sub_epi16(_mm_srli_si128(row0_high, 4u), row0_high);
1049 const __m128i diff_cols_r2_low = _mm_sub_epi16(row2_low_shifted, row2_low);
1050 const __m128i diff_cols_r2_high = _mm_sub_epi16(_mm_srli_si128(row2_high, 4u), row2_high);
1051 const __m128i diff_cols_r1_x2_low = _mm_sub_epi16(row1_x2_low_shifted, row1_x2_low);
1052 const __m128i diff_cols_r1_x2_high = _mm_sub_epi16(_mm_srli_si128(row1_x2_high, 4u), row1_x2_high);
1053
1054 // add
1055 response_x_low = _mm_adds_epi16(_mm_adds_epi16(diff_cols_r0_low, diff_cols_r2_low), diff_cols_r1_x2_low);
1056 response_x_high = _mm_adds_epi16(_mm_adds_epi16(diff_cols_r0_high, diff_cols_r2_high), diff_cols_r1_x2_high);
1057
1058 // normalize
1059 //response_x_low = _mm_srai_epi16(addOffsetForRightShiftDivision(sum_horz_low), 3u);
1060 //response_x_high = _mm_srai_epi16(addOffsetForRightShiftDivision(sum_horz_high), 3u);
1061}
1062
1063inline void FrameFilterSobel::filterHorizontalVertical1Channel8BitBlock14SSE(const uint8_t* source, const unsigned int strideElements, int8_t* response)
1064{
1065 ocean_assert(source != nullptr && response != nullptr);
1066 ocean_assert(strideElements >= 16u);
1067
1068 __m128i response_y_low;
1069 __m128i response_y_high;
1070 __m128i response_x_low;
1071 __m128i response_x_high;
1072
1073 filterHorizontalVertical8BitBlock14SSE(source - strideElements, source, source + strideElements, response_x_low, response_x_high, response_y_low, response_y_high);
1074
1075 // normalize responses
1076 const __m128i response_x_low_norm = SSE::divideByRightShiftSigned16Bit(response_x_low, 3u);
1077 const __m128i response_x_high_norm = SSE::divideByRightShiftSigned16Bit(response_x_high, 3u);
1078 const __m128i response_y_low_norm = SSE::divideByRightShiftSigned16Bit(response_y_low, 3u);
1079 const __m128i response_y_high_norm = SSE::divideByRightShiftSigned16Bit(response_y_high, 3u);
1080
1081 // pack into one vector
1082 const __m128i response_x_norm = _mm_packs_epi16(response_x_low_norm, response_x_high_norm);
1083 const __m128i response_y_norm = _mm_packs_epi16(response_y_low_norm, response_y_high_norm);
1084
1085 // zip response values
1086 const __m128i response_zipped_lo = _mm_unpacklo_epi8(response_x_norm, response_y_norm);
1087 const __m128i response_zipped_hi = _mm_unpackhi_epi8(response_x_norm, response_y_norm);
1088
1089 _mm_storeu_si128((__m128i*)response, response_zipped_lo);
1090 memcpy(response + 16, &response_zipped_hi, 12);
1091}
1092
1093inline void FrameFilterSobel::filterHorizontalVertical1Channel8BitBlock14SSE(const uint8_t* source, const unsigned int strideElements, int16_t* response)
1094{
1095 ocean_assert(source != nullptr && response != nullptr);
1096 ocean_assert(strideElements >= 16u);
1097
1098 __m128i response_y_low;
1099 __m128i response_y_high;
1100 __m128i response_x_low;
1101 __m128i response_x_high;
1102
1103 filterHorizontalVertical8BitBlock14SSE(source - strideElements, source, source + strideElements, response_x_low, response_x_high, response_y_low, response_y_high);
1104
1105 // zip response values
1106 const __m128i response_zipped_lo = _mm_unpacklo_epi16(response_x_low, response_y_low);
1107 const __m128i response_zipped_hi = _mm_unpackhi_epi16(response_x_low, response_y_low);
1108 const __m128i response_zipped_lo_2 = _mm_unpacklo_epi16(response_x_high, response_y_high);
1109 const __m128i response_zipped_hi_2 = _mm_unpackhi_epi16(response_x_high, response_y_high);
1110
1111 // copy to memory. only first 2 16-bit values of response_zipped_hi_2 are relevant
1112 memcpy(response, &response_zipped_lo, 16);
1113 memcpy(response + 8, &response_zipped_hi, 16);
1114 memcpy(response + 16, &response_zipped_lo_2, 16);
1115 memcpy(response + 24, &response_zipped_hi_2, 8);
1116}
1117
1118#endif
1119
1120}
1121
1122}
1123
1124#endif // META_OCEAN_CV_FRAME_FILTER_SOBEL_H
This class implements the base class for all filter.
Definition FrameFilter.h:29
The following comfort class provides comfortable functions simplifying prototyping applications but a...
Definition FrameFilterSobel.h:57
static Frame filterHorizontalVertical(const Frame &frame, const FrameType::DataType responseDataType=FrameType::DT_SIGNED_INTEGER_8, Worker *worker=nullptr)
Horizontal and vertical Sobel filter for images.
static Frame filter(const Frame &frame, const FrameType::DataType responseDataType=FrameType::DT_SIGNED_INTEGER_8, Worker *worker=nullptr)
Horizontal, vertical, and diagonal Sobel filter for images.
This class implements a Sobel filter.
Definition FrameFilterSobel.h:48
static void filterHorizontalVertical8BitPerChannel(const uint8_t *source, TTarget *target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Horizontal and vertical Sobel filter for images.
Definition FrameFilterSobel.h:348
static void filterHorizontalVerticalMaximumAbsoluteRow(const TSource *sourceRow, TTarget *targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int targetStrideElements)
Applies the maximum of the absolute horizontal and vertical Sobel filter to one row of a source frame...
Definition FrameFilterSobel.h:720
static void filterPixelCoreHorizontalVertical8BitPerChannel(const uint8_t *source, const unsigned int width, TTarget *response, const unsigned int sourcePaddingElements)
Horizontal and vertical Sobel filter for a pixel not at the boundary of the frame (in the inner core ...
Definition FrameFilterSobel.h:830
static void filterPixelCoreHorizontalVertical3Squared1Channel8Bit(const uint8_t *source, const unsigned int width, TTarget *responses, const unsigned int paddingElements)
Determines the squared Sobel filter responses (three products) for a 1 channel 8 bit pixel based on a...
Definition FrameFilterSobel.h:879
static void filterPixelHorizontalVertical8BitPerChannel(const uint8_t *source, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, TTarget *response, const unsigned int sourcePaddingElements)
Horizontal and vertical Sobel filter for a pixel.
Definition FrameFilterSobel.h:803
static void filterHorizontalVertical1Channel8BitBlock14SSE(const uint8_t *source, const unsigned int strideElements, int16_t *response)
SSE block based horizontal and vertical Sobel filter for 1 channel 8 bit frame.
Definition FrameFilterSobel.h:1093
static void filter8BitPerChannel(const uint8_t *source, TTarget *target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Horizontal, vertical, and diagonal Sobel filter for images.
Definition FrameFilterSobel.h:378
static void filterHorizontalVerticalRow(const TSource *sourceRow, TTarget *targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int targetStrideElements)
Applies the horizontal and vertical Sobel filter to one row of a source frame.
Definition FrameFilterSobel.h:408
static void filterHorizontalVerticalMaximumAbsolute8BitPerChannel(const uint8_t *source, TTarget *target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Determines the maximum of the absolute horizontal and vertical Sobel filter.
Definition FrameFilterSobel.h:393
static void filterDiagonalRow(const TSource *sourceRow, TTarget *targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int targetStrideElements)
Applies the diagonal (45 and 135 degree) Sobel filter to one row of a source frame.
Definition FrameFilterSobel.h:534
static void filterPixelHorizontalVerticalMaximum8BitPerChannel(const uint8_t *const source, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, TTarget *const response, unsigned int sourcePaddingElements)
Determines the maximum of the absolute horizontal and vertical Sobel filter for a given pixel.
Definition FrameFilterSobel.h:904
static void filterHorizontalVertical3Squared1Channel8BitRow(const uint8_t *row, const unsigned int width, const unsigned int elements, const unsigned int paddingElements, int16_t *responsesXX, int16_t *responsesYY, int16_t *responsesXY)
Determines the squared Sobel filter responses (three products) for a 1 channel 8 bit row based on a h...
static void filterHorizontalVertical8BitBlock14SSE(const uint8_t *source0, const uint8_t *source1, const uint8_t *source2, __m128i &response_x_low, __m128i &response_x_high, __m128i &response_y_low, __m128i &response_y_high)
Block based SSE implementation of horizontal and vertical Sobel filter for 8 bit pixel.
Definition FrameFilterSobel.h:973
static void filterDiagonal8BitPerChannel(const uint8_t *source, TTarget *target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Diagonal 45 and 135 degree Sobel filter for images.
Definition FrameFilterSobel.h:363
static void filterRow(const TSource *sourceRow, TTarget *targetRow, const unsigned int width, const unsigned int height, unsigned int rowIndex, const unsigned int sourceStrideElements, const unsigned int targetStrideElements)
Applies the horizontal, vertical, and diagonal Sobel filter to one row of a source frame.
Definition FrameFilterSobel.h:617
static __m128i divideByRightShiftSigned16Bit(const __m128i &value, const unsigned int rightShifts)
Divides eight signed 16 bit values by applying a right shift.
Definition SSE.h:3066
This class implements Ocean's image class.
Definition Frame.h:1808
DataType
Definition of individual channel data type.
Definition Frame.h:37
This class implements a worker able to distribute function calls over different threads.
Definition Worker.h:33
The namespace covering the entire Ocean framework.
Definition Accessor.h:15