Ocean
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"
12 #include "ocean/cv/FrameChannels.h"
13 #include "ocean/cv/FrameFilter.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 
21 namespace Ocean
22 {
23 
24 namespace 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  */
47 class 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 
347 template <typename TTarget, unsigned int tSourceChannels>
348 inline 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 
362 template <typename TTarget, unsigned int tSourceChannels>
363 inline 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 
377 template <typename TTarget, unsigned int tSourceChannels>
378 inline 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 
392 template <typename TTarget, unsigned int tSourceChannels>
393 inline 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 
407 template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
408 void 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 
533 template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
534 void 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 
616 template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
617 void 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 
719 template <typename TSource, typename TTarget, unsigned int tSourceChannels, unsigned int tTargetChannels>
720 void 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 
802 template <typename TTarget, unsigned int tSourceChannels>
803 inline 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 
829 template <typename TTarget, unsigned int tSourceChannels>
830 inline 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 
878 template <typename TTarget, TTarget tNormalizationDenominator, bool tRoundedNormalization>
879 inline 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 
903 template <typename TTarget, unsigned int tChannels, bool tIsCorePixel>
904 inline 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 
973 inline 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 
1063 inline 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 
1093 inline 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:1792
DataType
Definition of individual channel data type.
Definition: Frame.h:37
@ DT_SIGNED_INTEGER_8
Signed 8 bit integer data type (int8_t).
Definition: Frame.h:43
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