mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge branch 4.x
This commit is contained in:
@@ -25,7 +25,7 @@ Theory
|
||||
|
||||
@note
|
||||
The explanation below belongs to the book [Computer Vision: Algorithms and
|
||||
Applications](http://szeliski.org/Book/) by Richard Szeliski
|
||||
Applications](https://szeliski.org/Book/) by Richard Szeliski
|
||||
|
||||
From our previous tutorial, we already know a bit of *Pixel operators*. An interesting dyadic
|
||||
(two-input) operator is the *linear blend operator*:
|
||||
|
||||
@@ -27,7 +27,7 @@ Theory
|
||||
|
||||
@note
|
||||
The explanation below belongs to the book [Computer Vision: Algorithms and
|
||||
Applications](http://szeliski.org/Book/) by Richard Szeliski
|
||||
Applications](https://szeliski.org/Book/) by Richard Szeliski
|
||||
|
||||
### Image Processing
|
||||
|
||||
@@ -266,14 +266,14 @@ be the opposite with \f$ \gamma > 1 \f$.
|
||||
|
||||
The following image has been corrected with: \f$ \alpha = 1.3 \f$ and \f$ \beta = 40 \f$.
|
||||
|
||||
![By Visem (Own work) [CC BY-SA 3.0], via Wikimedia Commons](images/Basic_Linear_Transform_Tutorial_linear_transform_correction.jpg)
|
||||
![By Visem (Own work) [CC BY-SA 3.0], via Wikimedia Commons](images/Basic_Linear_Transform_Tutorial_linear_transform_correction.jpg) { width=90% }
|
||||
|
||||
The overall brightness has been improved but you can notice that the clouds are now greatly saturated due to the numerical saturation
|
||||
of the implementation used ([highlight clipping](https://en.wikipedia.org/wiki/Clipping_(photography)) in photography).
|
||||
|
||||
The following image has been corrected with: \f$ \gamma = 0.4 \f$.
|
||||
|
||||
![By Visem (Own work) [CC BY-SA 3.0], via Wikimedia Commons](images/Basic_Linear_Transform_Tutorial_gamma_correction.jpg)
|
||||
![By Visem (Own work) [CC BY-SA 3.0], via Wikimedia Commons](images/Basic_Linear_Transform_Tutorial_gamma_correction.jpg) { width=90% }
|
||||
|
||||
The gamma correction should tend to add less saturation effect as the mapping is non linear and there is no numerical saturation possible as in the previous method.
|
||||
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ File Input and Output using XML / YAML / JSON files {#tutorial_file_input_output
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_discrete_fourier_transform}
|
||||
@next_tutorial{tutorial_how_to_use_OpenCV_parallel_for_}
|
||||
@next_tutorial{tutorial_how_to_use_OpenCV_parallel_for_new}
|
||||
|
||||
| | |
|
||||
|
||||
+15
-13
@@ -1,16 +1,18 @@
|
||||
How to use the OpenCV parallel_for_ to parallelize your code {#tutorial_how_to_use_OpenCV_parallel_for_}
|
||||
How to use the OpenCV parallel_for_ function to parallelize your code (Mandelbrot set example) {#tutorial_how_to_use_OpenCV_parallel_for_}
|
||||
==================================================================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_file_input_output_with_xml_yml}
|
||||
@next_tutorial{tutorial_how_to_use_OpenCV_parallel_for_new}
|
||||
@next_tutorial{tutorial_univ_intrin}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
|
||||
@note See also C++ lambda usage with parallel for in [tuturial](@ref tutorial_how_to_use_OpenCV_parallel_for_new).
|
||||
@note See this [tuturial](@ref tutorial_how_to_use_OpenCV_parallel_for_new) for a `parallel_for_` usage applied to image convolution.
|
||||
|
||||
Goal
|
||||
----
|
||||
@@ -26,17 +28,17 @@ Precondition
|
||||
------------
|
||||
|
||||
The first precondition is to have OpenCV built with a parallel framework.
|
||||
In OpenCV 3.2, the following parallel frameworks are available in that order:
|
||||
In OpenCV 4, the following parallel frameworks are available in that order:
|
||||
|
||||
1. Intel Threading Building Blocks (3rdparty library, should be explicitly enabled)
|
||||
2. C= Parallel C/C++ Programming Language Extension (3rdparty library, should be explicitly enabled)
|
||||
3. OpenMP (integrated to compiler, should be explicitly enabled)
|
||||
4. APPLE GCD (system wide, used automatically (APPLE only))
|
||||
5. Windows RT concurrency (system wide, used automatically (Windows RT only))
|
||||
6. Windows concurrency (part of runtime, used automatically (Windows only - MSVC++ >= 10))
|
||||
7. Pthreads (if available)
|
||||
2. OpenMP (integrated to compiler, should be explicitly enabled)
|
||||
3. APPLE GCD (system wide, used automatically (APPLE only))
|
||||
4. Windows RT concurrency (system wide, used automatically (Windows RT only))
|
||||
5. Windows concurrency (part of runtime, used automatically (Windows only - MSVC++ >= 10))
|
||||
6. Pthreads (if available)
|
||||
|
||||
As you can see, several parallel frameworks can be used in the OpenCV library. Some parallel libraries
|
||||
are third party libraries and have to be explicitly built and enabled in CMake (e.g. TBB, C=), others are
|
||||
are third party libraries and have to be explicitly built and enabled in CMake (e.g. TBB), others are
|
||||
automatically available with the platform (e.g. APPLE GCD) but chances are that you should be enable to
|
||||
have access to a parallel framework either directly or by enabling the option in CMake and rebuild the library.
|
||||
|
||||
@@ -120,7 +122,7 @@ Escape time algorithm implementation
|
||||
|
||||
@snippet how_to_use_OpenCV_parallel_for_.cpp mandelbrot-escape-time-algorithm
|
||||
|
||||
Here, we used the [`std::complex`](http://en.cppreference.com/w/cpp/numeric/complex) template class to represent a
|
||||
Here, we used the [`std::complex`](https://en.cppreference.com/cpp/numeric/complex) template class to represent a
|
||||
complex number. This function performs the test to check if the pixel is in set or not and returns the "escaped" iteration.
|
||||
|
||||
Sequential Mandelbrot implementation
|
||||
@@ -143,7 +145,7 @@ Finally, to assign the grayscale value to the pixels, we use the following rule:
|
||||
|
||||
Using a linear scale transformation is not enough to perceive the grayscale variation. To overcome this, we will boost
|
||||
the perception by using a square root scale transformation (borrowed from Jeremy D. Frens in his
|
||||
[blog post](http://www.programming-during-recess.net/2016/06/26/color-schemes-for-mandelbrot-sets/)):
|
||||
[blog post](https://web.archive.org/web/20250419124416/http://www.programming-during-recess.net/2016/06/26/color-schemes-for-mandelbrot-sets/)):
|
||||
\f$ f \left( x \right) = \sqrt{\frac{x}{\text{maxIter}}} \times 255 \f$
|
||||
|
||||

|
||||
@@ -179,7 +181,7 @@ or setting `nstripes=2` should be the same as by default it will use all the pro
|
||||
workload only on two threads.
|
||||
|
||||
@note
|
||||
C++ 11 standard allows to simplify the parallel implementation by get rid of the `ParallelMandelbrot` class and replacing it with lambda expression:
|
||||
C++ 11 standard allows simplifying the parallel implementation by get rid of the `ParallelMandelbrot` class and replacing it with lambda expression:
|
||||
|
||||
@snippet how_to_use_OpenCV_parallel_for_.cpp mandelbrot-parallel-call-cxx11
|
||||
|
||||
|
||||
+3
-2
@@ -1,9 +1,10 @@
|
||||
How to use the OpenCV parallel_for_ to parallelize your code {#tutorial_how_to_use_OpenCV_parallel_for_new}
|
||||
How to use the OpenCV parallel_for_ function to parallelize your code (convolution example) {#tutorial_how_to_use_OpenCV_parallel_for_new}
|
||||
==================================================================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_file_input_output_with_xml_yml}
|
||||
@prev_tutorial{tutorial_how_to_use_OpenCV_parallel_for_}
|
||||
@next_tutorial{tutorial_univ_intrin}
|
||||
|
||||
| | |
|
||||
@@ -122,7 +123,7 @@ For example, we can either
|
||||
|
||||
To set the number of threads, you can use: @ref cv::setNumThreads. You can also specify the number of splitting using the nstripes parameter in @ref cv::parallel_for_. For instance, if your processor has 4 threads, setting `cv::setNumThreads(2)` or setting `nstripes=2` should be the same as by default it will use all the processor threads available but will split the workload only on two threads.
|
||||
|
||||
@note C++ 11 standard allows to simplify the parallel implementation by get rid of the `parallelConvolution` class and replacing it with lambda expression:
|
||||
@note C++ 11 standard allows simplifying the parallel implementation by getting rid of the `parallelConvolution` class and replacing it with lambda expression:
|
||||
|
||||
@snippet how_to_use_OpenCV_parallel_for_new.cpp convolution-parallel-cxx11
|
||||
|
||||
|
||||
@@ -14,5 +14,6 @@ The Core Functionality (core module) {#tutorial_table_of_content_core}
|
||||
##### Advanced
|
||||
- @subpage tutorial_discrete_fourier_transform
|
||||
- @subpage tutorial_file_input_output_with_xml_yml
|
||||
- @subpage tutorial_how_to_use_OpenCV_parallel_for_
|
||||
- @subpage tutorial_how_to_use_OpenCV_parallel_for_new
|
||||
- @subpage tutorial_univ_intrin
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ Theory
|
||||
------
|
||||
|
||||
@note The explanation below belongs to the book [Computer Vision: Algorithms and
|
||||
Applications](http://szeliski.org/Book/) by Richard Szeliski and to *LearningOpenCV*
|
||||
Applications](https://szeliski.org/Book/) by Richard Szeliski and to *LearningOpenCV*
|
||||
|
||||
- *Smoothing*, also called *blurring*, is a simple and frequently used image processing
|
||||
operation.
|
||||
|
||||
@@ -228,10 +228,10 @@ int ipp_hal_warpPerspective(int src_type, const uchar *src_data, size_t src_step
|
||||
/* C1 C2 C3 C4 */
|
||||
char impl[CV_DEPTH_MAX][4][2]={{{0, 0}, {0, 0}, {0, 0}, {0, 0}}, //8U
|
||||
{{0, 0}, {0, 0}, {0, 0}, {0, 0}}, //8S
|
||||
{{0, 0}, {0, 0}, {0, 1}, {0, 1}}, //16U
|
||||
{{1, 1}, {0, 0}, {1, 1}, {1, 1}}, //16S
|
||||
{{0, 0}, {0, 0}, {0, 0}, {0, 1}}, //16U
|
||||
{{1, 1}, {0, 0}, {1, 0}, {1, 1}}, //16S
|
||||
{{1, 1}, {0, 0}, {1, 0}, {1, 1}}, //32S
|
||||
{{1, 0}, {0, 0}, {0, 0}, {1, 0}}, //32F
|
||||
{{0, 0}, {0, 0}, {0, 0}, {1, 0}}, //32F
|
||||
{{0, 0}, {0, 0}, {0, 0}, {0, 0}}}; //64F
|
||||
#endif
|
||||
|
||||
|
||||
@@ -238,10 +238,8 @@ int integral(int depth, int sdepth, int sqdepth,
|
||||
uchar* tilted_data, [[maybe_unused]] size_t tilted_step,
|
||||
int width, int height, int cn);
|
||||
|
||||
// Diasbled due to accuracy issue.
|
||||
// Details see https://github.com/opencv/opencv/issues/27407.
|
||||
//#undef cv_hal_integral
|
||||
//#define cv_hal_integral cv::rvv_hal::imgproc::integral
|
||||
#undef cv_hal_integral
|
||||
#define cv_hal_integral cv::rvv_hal::imgproc::integral
|
||||
|
||||
/* ############ laplacian ############ */
|
||||
int laplacian(const uint8_t* src_data, size_t src_step,
|
||||
@@ -276,6 +274,16 @@ int canny(const uint8_t *src_data, size_t src_step,
|
||||
#undef cv_hal_canny
|
||||
#define cv_hal_canny cv::rvv_hal::imgproc::canny
|
||||
|
||||
/* ############ spatialGradient ############ */
|
||||
int spatialGradient(const uint8_t* src_data, size_t src_step,
|
||||
int16_t* dx_data, size_t dx_step,
|
||||
int16_t* dy_data, size_t dy_step,
|
||||
int width, int height,
|
||||
int ksize, int border_type);
|
||||
|
||||
#undef cv_hal_spatialGradient
|
||||
#define cv_hal_spatialGradient cv::rvv_hal::imgproc::spatialGradient
|
||||
|
||||
#endif // CV_HAL_RVV_1P0_ENABLED
|
||||
|
||||
#if CV_HAL_RVV_071_ENABLED
|
||||
|
||||
@@ -62,6 +62,141 @@ inline int convertScale_8U32F(const uchar* src, size_t src_step, uchar* dst, siz
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
inline int convertScale_8U16U(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta)
|
||||
{
|
||||
if (alpha == 1.0 && beta == 0.0)
|
||||
{
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
const uchar* src_row = src + i * src_step;
|
||||
ushort* dst_row = reinterpret_cast<ushort*>(dst + i * dst_step);
|
||||
int vl;
|
||||
for (int j = 0; j < width; j += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e8m2(width - j);
|
||||
auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl);
|
||||
auto vec_dst = __riscv_vzext_vf2(vec_src, vl);
|
||||
__riscv_vse16_v_u16m4(dst_row + j, vec_dst, vl);
|
||||
}
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
int vlmax = __riscv_vsetvlmax_e32m8();
|
||||
auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax);
|
||||
float a = alpha;
|
||||
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
const uchar* src_row = src + i * src_step;
|
||||
ushort* dst_row = reinterpret_cast<ushort*>(dst + i * dst_step);
|
||||
int vl;
|
||||
for (int j = 0; j < width; j += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e8m2(width - j);
|
||||
auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl);
|
||||
auto vec_src_u16 = __riscv_vzext_vf2(vec_src, vl);
|
||||
auto vec_src_f32 = __riscv_vfwcvt_f(vec_src_u16, vl);
|
||||
auto vec_fma = __riscv_vfmadd(vec_src_f32, a, vec_b, vl);
|
||||
auto vec_dst = __riscv_vfncvt_xu(vec_fma, vl);
|
||||
__riscv_vse16_v_u16m4(dst_row + j, vec_dst, vl);
|
||||
}
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
inline int convertScale_8U16S(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta)
|
||||
{
|
||||
if (alpha == 1.0 && beta == 0.0)
|
||||
{
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
const uchar* src_row = src + i * src_step;
|
||||
short* dst_row = reinterpret_cast<short*>(dst + i * dst_step);
|
||||
int vl;
|
||||
for (int j = 0; j < width; j += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e8m2(width - j);
|
||||
auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl);
|
||||
auto vec_dst = __riscv_vreinterpret_v_u16m4_i16m4(__riscv_vzext_vf2(vec_src, vl));
|
||||
__riscv_vse16_v_i16m4(dst_row + j, vec_dst, vl);
|
||||
}
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
int vlmax = __riscv_vsetvlmax_e32m8();
|
||||
auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax);
|
||||
float a = alpha;
|
||||
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
const uchar* src_row = src + i * src_step;
|
||||
short* dst_row = reinterpret_cast<short*>(dst + i * dst_step);
|
||||
int vl;
|
||||
for (int j = 0; j < width; j += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e8m2(width - j);
|
||||
auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl);
|
||||
auto vec_src_u16 = __riscv_vzext_vf2(vec_src, vl);
|
||||
auto vec_src_f32 = __riscv_vfwcvt_f(vec_src_u16, vl);
|
||||
auto vec_fma = __riscv_vfmadd(vec_src_f32, a, vec_b, vl);
|
||||
auto vec_dst = __riscv_vfncvt_x(vec_fma, vl);
|
||||
__riscv_vse16_v_i16m4(dst_row + j, vec_dst, vl);
|
||||
}
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
inline int convertScale_16U8U(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta)
|
||||
{
|
||||
if (alpha == 1.0 && beta == 0.0)
|
||||
{
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
const ushort* src_row = reinterpret_cast<const ushort*>(src + i * src_step);
|
||||
uchar* dst_row = dst + i * dst_step;
|
||||
int vl;
|
||||
for (int j = 0; j < width; j += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e16m4(width - j);
|
||||
auto vec_src = __riscv_vle16_v_u16m4(src_row + j, vl);
|
||||
auto vec_dst = __riscv_vnclipu(vec_src, 0, __RISCV_VXRM_RNU, vl);
|
||||
__riscv_vse8_v_u8m2(dst_row + j, vec_dst, vl);
|
||||
}
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
int vlmax = __riscv_vsetvlmax_e32m8();
|
||||
auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax);
|
||||
float a = alpha;
|
||||
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
const ushort* src_row = reinterpret_cast<const ushort*>(src + i * src_step);
|
||||
uchar* dst_row = dst + i * dst_step;
|
||||
int vl;
|
||||
for (int j = 0; j < width; j += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e16m4(width - j);
|
||||
auto vec_src = __riscv_vle16_v_u16m4(src_row + j, vl);
|
||||
auto vec_src_f32 = __riscv_vfwcvt_f(vec_src, vl);
|
||||
auto vec_fma = __riscv_vfmadd(vec_src_f32, a, vec_b, vl);
|
||||
auto vec_dst_u16 = __riscv_vfncvt_xu(vec_fma, vl);
|
||||
auto vec_dst = __riscv_vnclipu(vec_dst_u16, 0, __RISCV_VXRM_RNU, vl);
|
||||
__riscv_vse8_v_u8m2(dst_row + j, vec_dst, vl);
|
||||
}
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
inline int convertScale_16U32F(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta)
|
||||
{
|
||||
int vlmax = __riscv_vsetvlmax_e32m8();
|
||||
@@ -164,6 +299,13 @@ int convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step,
|
||||
if (!dst)
|
||||
return CV_HAL_ERROR_OK;
|
||||
|
||||
if ((unsigned)ddepth >= CV_DEPTH_MAX)
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
// Column-shaped sources can target row-shaped continuous vectors.
|
||||
if (width == 1 && height > 1 && dst_step != CV_ELEM_SIZE1(ddepth))
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
switch (sdepth)
|
||||
{
|
||||
case CV_8U:
|
||||
@@ -171,6 +313,10 @@ int convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step,
|
||||
{
|
||||
case CV_8U:
|
||||
return convertScale_8U8U(src, src_step, dst, dst_step, width, height, alpha, beta);
|
||||
case CV_16U:
|
||||
return convertScale_8U16U(src, src_step, dst, dst_step, width, height, alpha, beta);
|
||||
case CV_16S:
|
||||
return convertScale_8U16S(src, src_step, dst, dst_step, width, height, alpha, beta);
|
||||
case CV_32F:
|
||||
return convertScale_8U32F(src, src_step, dst, dst_step, width, height, alpha, beta);
|
||||
}
|
||||
@@ -178,6 +324,8 @@ int convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step,
|
||||
case CV_16U:
|
||||
switch (ddepth)
|
||||
{
|
||||
case CV_8U:
|
||||
return convertScale_16U8U(src, src_step, dst, dst_step, width, height, alpha, beta);
|
||||
case CV_32F:
|
||||
return convertScale_16U32F(src, src_step, dst, dst_step, width, height, alpha, beta);
|
||||
}
|
||||
|
||||
@@ -129,6 +129,11 @@ int integral(int depth, int sdepth, int sqdepth,
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// CV_32F sqsum kept on generic path due to accumulation-order sensitivity, see #27407
|
||||
if (sqsum_data && (sdepth == CV_32F || sqdepth == CV_32F)) {
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Skip images that are too small
|
||||
if (!(width >> 8 || height >> 8)) {
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "rvv_hal.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
namespace cv { namespace rvv_hal { namespace imgproc {
|
||||
|
||||
#if CV_HAL_RVV_1P0_ENABLED
|
||||
|
||||
namespace {
|
||||
|
||||
static inline vint16m2_t widen_u8_to_i16(vuint8m1_t v, size_t vl)
|
||||
{
|
||||
vuint16m2_t widened = __riscv_vzext_vf2(v, vl);
|
||||
return __riscv_vreinterpret_v_u16m2_i16m2(widened);
|
||||
}
|
||||
|
||||
static inline void spatialGradientKernel(int16_t& dx, int16_t& dy,
|
||||
int16_t v00, int16_t v01, int16_t v02,
|
||||
int16_t v10, int16_t v12,
|
||||
int16_t v20, int16_t v21, int16_t v22)
|
||||
{
|
||||
int16_t tmp_add = v22 - v00;
|
||||
int16_t tmp_sub = v02 - v20;
|
||||
int16_t tmp_x = v12 - v10;
|
||||
int16_t tmp_y = v21 - v01;
|
||||
|
||||
dx = tmp_add + tmp_sub + tmp_x + tmp_x;
|
||||
dy = tmp_add - tmp_sub + tmp_y + tmp_y;
|
||||
}
|
||||
|
||||
static inline void loadRow3(const uint8_t* row, int x, size_t vl,
|
||||
vint16m2_t& m, vint16m2_t& n, vint16m2_t& p)
|
||||
{
|
||||
m = widen_u8_to_i16(__riscv_vle8_v_u8m1(row + x - 1, vl), vl);
|
||||
n = widen_u8_to_i16(__riscv_vle8_v_u8m1(row + x, vl), vl);
|
||||
p = widen_u8_to_i16(__riscv_vle8_v_u8m1(row + x + 1, vl), vl);
|
||||
}
|
||||
|
||||
static inline void spatialGradientKernelVec(vint16m2_t& vdx, vint16m2_t& vdy,
|
||||
const vint16m2_t& v_s1m,
|
||||
const vint16m2_t& v_s1n,
|
||||
const vint16m2_t& v_s1p,
|
||||
const vint16m2_t& v_s2m,
|
||||
const vint16m2_t& v_s2p,
|
||||
const vint16m2_t& v_s3m,
|
||||
const vint16m2_t& v_s3n,
|
||||
const vint16m2_t& v_s3p,
|
||||
size_t vl)
|
||||
{
|
||||
// vdx = (v_s3p - v_s1m) + (v_s1p - v_s3m) + 2 * (v_s2p - v_s2m)
|
||||
// vdy = (v_s3p - v_s1m) - (v_s1p - v_s3m) + 2 * (v_s3n - v_s1n)
|
||||
vint16m2_t tmp_add = __riscv_vsub_vv_i16m2(v_s3p, v_s1m, vl);
|
||||
vint16m2_t tmp_sub = __riscv_vsub_vv_i16m2(v_s1p, v_s3m, vl);
|
||||
vint16m2_t tmp_x = __riscv_vsub_vv_i16m2(v_s2p, v_s2m, vl);
|
||||
vint16m2_t tmp_y = __riscv_vsub_vv_i16m2(v_s3n, v_s1n, vl);
|
||||
|
||||
vdx = __riscv_vadd_vv_i16m2(tmp_add, tmp_sub, vl);
|
||||
vdx = __riscv_vadd_vv_i16m2(vdx, tmp_x, vl);
|
||||
vdx = __riscv_vadd_vv_i16m2(vdx, tmp_x, vl);
|
||||
|
||||
vdy = __riscv_vsub_vv_i16m2(tmp_add, tmp_sub, vl);
|
||||
vdy = __riscv_vadd_vv_i16m2(vdy, tmp_y, vl);
|
||||
vdy = __riscv_vadd_vv_i16m2(vdy, tmp_y, vl);
|
||||
}
|
||||
|
||||
static inline void processBorderPixels(const uint8_t* p_src,
|
||||
const uint8_t* c_src,
|
||||
const uint8_t* n_src,
|
||||
int16_t* c_dx,
|
||||
int16_t* c_dy,
|
||||
int width,
|
||||
int j_offl,
|
||||
int j_offr)
|
||||
{
|
||||
int j = 0;
|
||||
int j_p = j + j_offl;
|
||||
int j_n = 1;
|
||||
if (j_n >= width)
|
||||
j_n = j + j_offr;
|
||||
|
||||
int16_t v00 = p_src[j_p], v01 = p_src[j], v02 = p_src[j_n];
|
||||
int16_t v10 = c_src[j_p], v12 = c_src[j_n];
|
||||
int16_t v20 = n_src[j_p], v21 = n_src[j], v22 = n_src[j_n];
|
||||
spatialGradientKernel(c_dx[j], c_dy[j], v00, v01, v02, v10, v12, v20, v21, v22);
|
||||
|
||||
if (width > 1)
|
||||
{
|
||||
j = width - 1;
|
||||
j_p = j - 1;
|
||||
j_n = j + j_offr;
|
||||
|
||||
v00 = p_src[j_p]; v01 = p_src[j]; v02 = p_src[j_n];
|
||||
v10 = c_src[j_p]; v12 = c_src[j_n];
|
||||
v20 = n_src[j_p]; v21 = n_src[j]; v22 = n_src[j_n];
|
||||
spatialGradientKernel(c_dx[j], c_dy[j], v00, v01, v02, v10, v12, v20, v21, v22);
|
||||
}
|
||||
}
|
||||
|
||||
// Characters in variable names have the following meanings:
|
||||
// m: offset -1
|
||||
// n: offset 0
|
||||
// p: offset 1
|
||||
static int spatialGradient_row(int start, int end,
|
||||
const uint8_t* src_data, size_t src_step,
|
||||
int16_t* dx_data, size_t dx_step,
|
||||
int16_t* dy_data, size_t dy_step,
|
||||
int width, int height,
|
||||
int border_type)
|
||||
{
|
||||
int i_top = 0;
|
||||
int i_bottom = height - 1;
|
||||
int j_offl = 0;
|
||||
int j_offr = 0;
|
||||
|
||||
if (border_type == BORDER_DEFAULT)
|
||||
{
|
||||
if (height > 1)
|
||||
{
|
||||
i_top = 1;
|
||||
i_bottom = height - 2;
|
||||
}
|
||||
if (width > 1)
|
||||
{
|
||||
j_offl = 1;
|
||||
j_offr = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int y = start;
|
||||
for (; y + 1 < end; y += 2)
|
||||
{
|
||||
const uint8_t* p_src = src_data + (y == 0 ? i_top : y - 1) * src_step;
|
||||
const uint8_t* c_src = src_data + y * src_step;
|
||||
const uint8_t* n_src = src_data + (y + 1) * src_step;
|
||||
const uint8_t* m_src = src_data + (y == height - 2 ? i_bottom : y + 2) * src_step;
|
||||
|
||||
int16_t* c_dx = reinterpret_cast<int16_t*>(
|
||||
reinterpret_cast<uint8_t*>(dx_data) + y * dx_step);
|
||||
int16_t* c_dy = reinterpret_cast<int16_t*>(
|
||||
reinterpret_cast<uint8_t*>(dy_data) + y * dy_step);
|
||||
int16_t* n_dx = reinterpret_cast<int16_t*>(
|
||||
reinterpret_cast<uint8_t*>(dx_data) + (y + 1) * dx_step);
|
||||
int16_t* n_dy = reinterpret_cast<int16_t*>(
|
||||
reinterpret_cast<uint8_t*>(dy_data) + (y + 1) * dy_step);
|
||||
|
||||
processBorderPixels(p_src, c_src, n_src, c_dx, c_dy, width, j_offl, j_offr);
|
||||
processBorderPixels(c_src, n_src, m_src, n_dx, n_dy, width, j_offl, j_offr);
|
||||
|
||||
// Process rest of columns
|
||||
int x = 1;
|
||||
const int last = width - 1;
|
||||
while (x < last)
|
||||
{
|
||||
size_t vl = __riscv_vsetvl_e8m1((size_t)(last - x));
|
||||
|
||||
vint16m2_t v_s1m, v_s1n, v_s1p;
|
||||
vint16m2_t v_s2m, v_s2n, v_s2p;
|
||||
vint16m2_t v_s3m, v_s3n, v_s3p;
|
||||
loadRow3(p_src, x, vl, v_s1m, v_s1n, v_s1p);
|
||||
loadRow3(c_src, x, vl, v_s2m, v_s2n, v_s2p);
|
||||
loadRow3(n_src, x, vl, v_s3m, v_s3n, v_s3p);
|
||||
|
||||
vint16m2_t vdx, vdy;
|
||||
spatialGradientKernelVec(vdx, vdy,
|
||||
v_s1m, v_s1n, v_s1p,
|
||||
v_s2m, v_s2p,
|
||||
v_s3m, v_s3n, v_s3p, vl);
|
||||
__riscv_vse16_v_i16m2(c_dx + x, vdx, vl);
|
||||
__riscv_vse16_v_i16m2(c_dy + x, vdy, vl);
|
||||
|
||||
vint16m2_t v_s4m, v_s4n, v_s4p;
|
||||
loadRow3(m_src, x, vl, v_s4m, v_s4n, v_s4p);
|
||||
spatialGradientKernelVec(vdx, vdy,
|
||||
v_s2m, v_s2n, v_s2p,
|
||||
v_s3m, v_s3p,
|
||||
v_s4m, v_s4n, v_s4p, vl);
|
||||
__riscv_vse16_v_i16m2(n_dx + x, vdx, vl);
|
||||
__riscv_vse16_v_i16m2(n_dy + x, vdy, vl);
|
||||
|
||||
x += (int)vl;
|
||||
}
|
||||
}
|
||||
|
||||
for (; y < end; ++y)
|
||||
{
|
||||
const uint8_t* p_src = src_data + (y == 0 ? i_top : y - 1) * src_step;
|
||||
const uint8_t* c_src = src_data + y * src_step;
|
||||
const uint8_t* n_src = src_data + (y == height - 1 ? i_bottom : y + 1) * src_step;
|
||||
|
||||
int16_t* c_dx = reinterpret_cast<int16_t*>(
|
||||
reinterpret_cast<uint8_t*>(dx_data) + y * dx_step);
|
||||
int16_t* c_dy = reinterpret_cast<int16_t*>(
|
||||
reinterpret_cast<uint8_t*>(dy_data) + y * dy_step);
|
||||
|
||||
processBorderPixels(p_src, c_src, n_src, c_dx, c_dy, width, j_offl, j_offr);
|
||||
|
||||
int x = 1;
|
||||
const int last = width - 1;
|
||||
while (x < last)
|
||||
{
|
||||
size_t vl = __riscv_vsetvl_e8m1((size_t)(last - x));
|
||||
vint16m2_t v_s1m, v_s1n, v_s1p;
|
||||
vint16m2_t v_s2m, v_s2p;
|
||||
vint16m2_t v_s3m, v_s3n, v_s3p;
|
||||
loadRow3(p_src, x, vl, v_s1m, v_s1n, v_s1p);
|
||||
v_s2m = widen_u8_to_i16(__riscv_vle8_v_u8m1(c_src + x - 1, vl), vl);
|
||||
v_s2p = widen_u8_to_i16(__riscv_vle8_v_u8m1(c_src + x + 1, vl), vl);
|
||||
loadRow3(n_src, x, vl, v_s3m, v_s3n, v_s3p);
|
||||
|
||||
vint16m2_t vdx, vdy;
|
||||
spatialGradientKernelVec(vdx, vdy,
|
||||
v_s1m, v_s1n, v_s1p,
|
||||
v_s2m, v_s2p,
|
||||
v_s3m, v_s3n, v_s3p, vl);
|
||||
__riscv_vse16_v_i16m2(c_dx + x, vdx, vl);
|
||||
__riscv_vse16_v_i16m2(c_dy + x, vdy, vl);
|
||||
|
||||
x += (int)vl;
|
||||
}
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
int spatialGradient(const uint8_t* src_data, size_t src_step,
|
||||
int16_t* dx_data, size_t dx_step,
|
||||
int16_t* dy_data, size_t dy_step,
|
||||
int width, int height,
|
||||
int ksize, int border_type)
|
||||
{
|
||||
if (ksize != 3)
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
if (border_type != BORDER_REPLICATE && border_type != BORDER_DEFAULT)
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
if (width < 1 || height < 1)
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
return common::invoke(height, {spatialGradient_row},
|
||||
src_data, src_step,
|
||||
dx_data, dx_step,
|
||||
dy_data, dy_step,
|
||||
width, height, border_type);
|
||||
}
|
||||
|
||||
#endif // CV_HAL_RVV_1P0_ENABLED
|
||||
|
||||
}}} // cv::rvv_hal::imgproc
|
||||
@@ -2,10 +2,27 @@
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef OPENCV_IMGCODECS_APPLE_CONVERSIONS_H
|
||||
#define OPENCV_IMGCODECS_APPLE_CONVERSIONS_H
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
#import <Accelerate/Accelerate.h>
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#ifdef HAVE_AVFOUNDATION
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IPHONE || (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080)
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#else
|
||||
#import <ApplicationServices/ApplicationServices.h>
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
CV_EXPORTS CGImageRef MatToCGImage(const cv::Mat& image) CF_RETURNS_RETAINED;
|
||||
CV_EXPORTS void CGImageToMat(const CGImageRef image, cv::Mat& m, bool alphaExist);
|
||||
|
||||
#endif // OPENCV_IMGCODECS_APPLE_CONVERSIONS_H
|
||||
@@ -5,6 +5,12 @@
|
||||
#include "apple_conversions.h"
|
||||
#include "precomp.hpp"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#ifndef __bridge
|
||||
#define __bridge
|
||||
#endif
|
||||
|
||||
CGImageRef MatToCGImage(const cv::Mat& image) {
|
||||
NSData *data = [NSData dataWithBytes:image.data
|
||||
length:image.step.p[0] * image.rows];
|
||||
|
||||
@@ -61,10 +61,22 @@ bool SunRasterDecoder::readHeader()
|
||||
int palSize = (m_bpp > 0 && m_bpp <= 8) ? (3*(1 << m_bpp)) : 0;
|
||||
|
||||
m_strm.skip( 4 );
|
||||
m_encoding = (SunRasType)m_strm.getDWord();
|
||||
m_maptype = (SunRasMapType)m_strm.getDWord();
|
||||
// Read as plain integers first; validate before casting to enum types.
|
||||
// Casting an out-of-range integer directly to an enum with no fixed
|
||||
// underlying type is undefined behavior (C++11 §7.2/8). Reject invalid
|
||||
// values early so no downstream code ever touches an ill-formed enum.
|
||||
const int raw_encoding = (int)m_strm.getDWord();
|
||||
const int raw_maptype = (int)m_strm.getDWord();
|
||||
m_maplength = m_strm.getDWord();
|
||||
|
||||
if (raw_encoding < RAS_OLD || raw_encoding > RAS_FORMAT_RGB)
|
||||
return false;
|
||||
if (raw_maptype < RMT_NONE || raw_maptype > RMT_EQUAL_RGB)
|
||||
return false;
|
||||
|
||||
m_encoding = (SunRasType)raw_encoding;
|
||||
m_maptype = (SunRasMapType)raw_maptype;
|
||||
|
||||
if( m_width > 0 && m_height > 0 &&
|
||||
(m_bpp == 1 || m_bpp == 8 || m_bpp == 24 || m_bpp == 32) &&
|
||||
(m_encoding == RAS_OLD || m_encoding == RAS_STANDARD ||
|
||||
|
||||
@@ -13,9 +13,11 @@ NSImage* MatToNSImage(const cv::Mat& image) {
|
||||
CGImageRef imageRef = MatToCGImage(image);
|
||||
|
||||
// Getting NSImage from CGImage
|
||||
NSImage *nsImage = [[NSImage alloc] initWithCGImage:imageRef size:CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef))];
|
||||
NSSize imageSize = NSMakeSize(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
|
||||
NSImage *nsImage = [[NSImage alloc] initWithCGImage:imageRef size:imageSize];
|
||||
CGImageRelease(imageRef);
|
||||
|
||||
|
||||
return nsImage;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
// Regression tests for the Sun Raster decoder (grfmt_sunras.cpp).
|
||||
// These tests guard against:
|
||||
// - UBSan "load of invalid enum value" in SunRasterDecoder::readHeader()
|
||||
// (see https://github.com/opencv/opencv/issues/29150)
|
||||
// - Out-of-range SunRasType / SunRasMapType values causing UB via unchecked C-cast
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper: build a minimal Sun Raster byte buffer with caller-supplied fields.
|
||||
// Sun Raster header layout (all fields big-endian, 32-bit):
|
||||
// [0] magic = 0x59a66a95
|
||||
// [4] width
|
||||
// [8] height
|
||||
// [12] depth (bits-per-pixel)
|
||||
// [16] length (image data length, may be 0 for RAS_OLD)
|
||||
// [20] ras_type (SunRasType)
|
||||
// [24] maptype (SunRasMapType)
|
||||
// [28] maplength
|
||||
// ---------------------------------------------------------------------------
|
||||
static std::vector<uint8_t> makeSunRasHeader(
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
uint32_t length, uint32_t ras_type, uint32_t maptype, uint32_t maplength)
|
||||
{
|
||||
std::vector<uint8_t> buf(32);
|
||||
auto put32 = [&](size_t off, uint32_t v) {
|
||||
buf[off+0] = (v >> 24) & 0xff;
|
||||
buf[off+1] = (v >> 16) & 0xff;
|
||||
buf[off+2] = (v >> 8) & 0xff;
|
||||
buf[off+3] = (v ) & 0xff;
|
||||
};
|
||||
put32( 0, 0x59a66a95u); // magic
|
||||
put32( 4, width);
|
||||
put32( 8, height);
|
||||
put32(12, depth);
|
||||
put32(16, length);
|
||||
put32(20, ras_type);
|
||||
put32(24, maptype);
|
||||
put32(28, maplength);
|
||||
return buf;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Crash / UBSan regression — issue #29150
|
||||
// Feeding an invalid maptype value (34077 / 0x851d) must NOT trigger UB;
|
||||
// imdecode must return an empty Mat gracefully.
|
||||
// ---------------------------------------------------------------------------
|
||||
TEST(Imgcodecs_SunRaster, invalid_maptype_returns_empty_29150)
|
||||
{
|
||||
// Crafted header from the original bug report:
|
||||
// magic=0x59a66a95, width=0x10101, height=0x10000, depth=1, length=0x1000000
|
||||
// ras_type=0 (RAS_OLD, valid), maptype=0x851d (34077, INVALID)
|
||||
const std::vector<uint8_t> image_data = {
|
||||
0x59,0xa6,0x6a,0x95, 0x01,0x01,0x00,0x00,
|
||||
0x00,0x01,0x00,0x00, 0x00,0x00,0x00,0x01,
|
||||
0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x85,0x1d, 0xae,0x5b,0x8d,0xd5,
|
||||
0x9c,0x25,0x22,0x41, 0x51,0x92,0x13,0x14,0x33
|
||||
};
|
||||
|
||||
cv::Mat result;
|
||||
ASSERT_NO_THROW(result = cv::imdecode(image_data, cv::IMREAD_REDUCED_GRAYSCALE_2));
|
||||
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for invalid maptype";
|
||||
}
|
||||
|
||||
// Invalid ras_type (value well outside [0,3]) must be rejected cleanly.
|
||||
TEST(Imgcodecs_SunRaster, invalid_rastype_returns_empty)
|
||||
{
|
||||
auto buf = makeSunRasHeader(/*w*/8, /*h*/8, /*depth*/8,
|
||||
/*len*/0, /*ras_type*/0xFFFF, /*maptype*/0, /*mapllen*/0);
|
||||
cv::Mat result;
|
||||
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
|
||||
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for invalid ras_type";
|
||||
}
|
||||
|
||||
// maptype = 2 is outside [0,1] (only RMT_NONE=0, RMT_EQUAL_RGB=1 are defined).
|
||||
TEST(Imgcodecs_SunRaster, maptype_2_returns_empty)
|
||||
{
|
||||
auto buf = makeSunRasHeader(8, 8, 8, 0, /*ras_type*/0, /*maptype*/2, 0);
|
||||
cv::Mat result;
|
||||
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
|
||||
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for maptype=2";
|
||||
}
|
||||
|
||||
// maptype = UINT32_MAX is also invalid.
|
||||
TEST(Imgcodecs_SunRaster, maptype_max_returns_empty)
|
||||
{
|
||||
auto buf = makeSunRasHeader(8, 8, 8, 0, 0, 0xFFFFFFFFu, 0);
|
||||
cv::Mat result;
|
||||
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
|
||||
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for maptype=UINT_MAX";
|
||||
}
|
||||
|
||||
// A truncated buffer (shorter than the 32-byte header) must not crash.
|
||||
TEST(Imgcodecs_SunRaster, truncated_header_returns_empty)
|
||||
{
|
||||
// Only 16 bytes — header read will run out of data.
|
||||
const std::vector<uint8_t> buf = {
|
||||
0x59,0xa6,0x6a,0x95, 0x00,0x00,0x00,0x08,
|
||||
0x00,0x00,0x00,0x08, 0x00,0x00,0x00,0x08
|
||||
};
|
||||
cv::Mat result;
|
||||
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
|
||||
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for truncated header";
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Sanity: a well-formed 8-bpp grayscale Sun Raster (RMT_NONE) still decodes.
|
||||
// We build the full header + pixel data manually so the test has no file I/O.
|
||||
// ---------------------------------------------------------------------------
|
||||
TEST(Imgcodecs_SunRaster, valid_8bpp_grayscale_decodes)
|
||||
{
|
||||
const int W = 4, H = 4;
|
||||
// RAS_OLD(0), maptype=RMT_NONE(0), maplength=0
|
||||
auto buf = makeSunRasHeader(W, H, 8, W*H, 0, 0, 0);
|
||||
|
||||
// Sun Raster rows are padded to 16-bit boundary.
|
||||
// W=4: row_bytes = 4 (already even), no padding needed.
|
||||
for (int i = 0; i < W * H; ++i)
|
||||
buf.push_back(static_cast<uint8_t>(i * 16)); // arbitrary gray values
|
||||
|
||||
cv::Mat result;
|
||||
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
|
||||
EXPECT_FALSE(result.empty()) << "imdecode must succeed for a valid 8-bpp Sun Raster";
|
||||
EXPECT_EQ(result.cols, W);
|
||||
EXPECT_EQ(result.rows, H);
|
||||
EXPECT_EQ(result.type(), CV_8UC1);
|
||||
}
|
||||
|
||||
}} // namespace opencv_test
|
||||
@@ -45,6 +45,12 @@ PERF_TEST_P_ACCUMULATE(Accumulate, MAT_TYPES_ACCUMLATE,
|
||||
PERF_TEST_P_ACCUMULATE(AccumulateMask, MAT_TYPES_ACCUMLATE_C,
|
||||
PERF_ACCUMULATE_MASK_INIT(CV_32FC), accumulate(src1, dst, mask))
|
||||
|
||||
PERF_TEST_P_ACCUMULATE(AccumulateMask32FC4, CV_32FC4,
|
||||
PERF_ACCUMULATE_MASK_INIT(CV_32FC), accumulate(src1, dst, mask))
|
||||
|
||||
PERF_TEST_P_ACCUMULATE(AccumulateMask8UC4To32FC4, CV_8UC4,
|
||||
PERF_ACCUMULATE_MASK_INIT(CV_32FC), accumulate(src1, dst, mask))
|
||||
|
||||
PERF_TEST_P_ACCUMULATE(AccumulateDouble, MAT_TYPES_ACCUMLATE_D,
|
||||
PERF_ACCUMULATE_INIT(CV_64FC), accumulate(src1, dst))
|
||||
|
||||
|
||||
+265
-101
@@ -317,79 +317,183 @@ void acc_simd_(const uchar* src, float* dst, const uchar* mask, int len, int cn)
|
||||
}
|
||||
else
|
||||
{
|
||||
v_uint8 v_0 = vx_setall_u8(0);
|
||||
if (cn == 1)
|
||||
if (x <= len - cVectorWidth)
|
||||
{
|
||||
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
|
||||
v_uint8 v_0 = vx_setall_u8(0);
|
||||
if (cn == 1)
|
||||
{
|
||||
v_uint8 v_mask = vx_load(mask + x);
|
||||
v_mask = v_not(v_eq(v_0, v_mask));
|
||||
v_uint8 v_src = vx_load(src + x);
|
||||
v_src = v_and(v_src, v_mask);
|
||||
v_uint16 v_src0, v_src1;
|
||||
v_expand(v_src, v_src0, v_src1);
|
||||
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
|
||||
{
|
||||
v_uint8 v_mask = vx_load(mask + x);
|
||||
v_mask = v_ne(v_0, v_mask);
|
||||
v_uint8 v_src = vx_load(src + x);
|
||||
v_src = v_and(v_src, v_mask);
|
||||
v_uint16 v_src0, v_src1;
|
||||
v_expand(v_src, v_src0, v_src1);
|
||||
|
||||
v_uint32 v_src00, v_src01, v_src10, v_src11;
|
||||
v_expand(v_src0, v_src00, v_src01);
|
||||
v_expand(v_src1, v_src10, v_src11);
|
||||
v_uint32 v_src00, v_src01, v_src10, v_src11;
|
||||
v_expand(v_src0, v_src00, v_src01);
|
||||
v_expand(v_src1, v_src10, v_src11);
|
||||
|
||||
v_store(dst + x, v_add(vx_load(dst + x), v_cvt_f32(v_reinterpret_as_s32(v_src00))));
|
||||
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_cvt_f32(v_reinterpret_as_s32(v_src01))));
|
||||
v_store(dst + x + step * 2, v_add(vx_load(dst + x + step * 2), v_cvt_f32(v_reinterpret_as_s32(v_src10))));
|
||||
v_store(dst + x + step * 3, v_add(vx_load(dst + x + step * 3), v_cvt_f32(v_reinterpret_as_s32(v_src11))));
|
||||
v_store(dst + x, v_add(vx_load(dst + x), v_cvt_f32(v_reinterpret_as_s32(v_src00))));
|
||||
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_cvt_f32(v_reinterpret_as_s32(v_src01))));
|
||||
v_store(dst + x + step * 2, v_add(vx_load(dst + x + step * 2), v_cvt_f32(v_reinterpret_as_s32(v_src10))));
|
||||
v_store(dst + x + step * 3, v_add(vx_load(dst + x + step * 3), v_cvt_f32(v_reinterpret_as_s32(v_src11))));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cn == 3)
|
||||
{
|
||||
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
|
||||
else if (cn == 3)
|
||||
{
|
||||
v_uint8 v_mask = vx_load(mask + x);
|
||||
v_mask = v_not(v_eq(v_0, v_mask));
|
||||
v_uint8 v_src0, v_src1, v_src2;
|
||||
v_load_deinterleave(src + (x * cn), v_src0, v_src1, v_src2);
|
||||
v_src0 = v_and(v_src0, v_mask);
|
||||
v_src1 = v_and(v_src1, v_mask);
|
||||
v_src2 = v_and(v_src2, v_mask);
|
||||
v_uint16 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
|
||||
v_expand(v_src0, v_src00, v_src01);
|
||||
v_expand(v_src1, v_src10, v_src11);
|
||||
v_expand(v_src2, v_src20, v_src21);
|
||||
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
|
||||
{
|
||||
v_uint8 v_mask = vx_load(mask + x);
|
||||
v_mask = v_ne(v_0, v_mask);
|
||||
v_uint8 v_src0, v_src1, v_src2;
|
||||
v_load_deinterleave(src + (x * cn), v_src0, v_src1, v_src2);
|
||||
v_src0 = v_and(v_src0, v_mask);
|
||||
v_src1 = v_and(v_src1, v_mask);
|
||||
v_src2 = v_and(v_src2, v_mask);
|
||||
v_uint16 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
|
||||
v_expand(v_src0, v_src00, v_src01);
|
||||
v_expand(v_src1, v_src10, v_src11);
|
||||
v_expand(v_src2, v_src20, v_src21);
|
||||
|
||||
v_uint32 v_src000, v_src001, v_src010, v_src011;
|
||||
v_uint32 v_src100, v_src101, v_src110, v_src111;
|
||||
v_uint32 v_src200, v_src201, v_src210, v_src211;
|
||||
v_expand(v_src00, v_src000, v_src001);
|
||||
v_expand(v_src01, v_src010, v_src011);
|
||||
v_expand(v_src10, v_src100, v_src101);
|
||||
v_expand(v_src11, v_src110, v_src111);
|
||||
v_expand(v_src20, v_src200, v_src201);
|
||||
v_expand(v_src21, v_src210, v_src211);
|
||||
v_uint32 v_src000, v_src001, v_src010, v_src011;
|
||||
v_uint32 v_src100, v_src101, v_src110, v_src111;
|
||||
v_uint32 v_src200, v_src201, v_src210, v_src211;
|
||||
v_expand(v_src00, v_src000, v_src001);
|
||||
v_expand(v_src01, v_src010, v_src011);
|
||||
v_expand(v_src10, v_src100, v_src101);
|
||||
v_expand(v_src11, v_src110, v_src111);
|
||||
v_expand(v_src20, v_src200, v_src201);
|
||||
v_expand(v_src21, v_src210, v_src211);
|
||||
|
||||
v_float32 v_dst000, v_dst001, v_dst010, v_dst011;
|
||||
v_float32 v_dst100, v_dst101, v_dst110, v_dst111;
|
||||
v_float32 v_dst200, v_dst201, v_dst210, v_dst211;
|
||||
v_load_deinterleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
|
||||
v_load_deinterleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
|
||||
v_load_deinterleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
|
||||
v_load_deinterleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
|
||||
v_float32 v_dst000, v_dst001, v_dst010, v_dst011;
|
||||
v_float32 v_dst100, v_dst101, v_dst110, v_dst111;
|
||||
v_float32 v_dst200, v_dst201, v_dst210, v_dst211;
|
||||
v_load_deinterleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
|
||||
v_load_deinterleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
|
||||
v_load_deinterleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
|
||||
v_load_deinterleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
|
||||
|
||||
v_dst000 = v_add(v_dst000, v_cvt_f32(v_reinterpret_as_s32(v_src000)));
|
||||
v_dst100 = v_add(v_dst100, v_cvt_f32(v_reinterpret_as_s32(v_src100)));
|
||||
v_dst200 = v_add(v_dst200, v_cvt_f32(v_reinterpret_as_s32(v_src200)));
|
||||
v_dst001 = v_add(v_dst001, v_cvt_f32(v_reinterpret_as_s32(v_src001)));
|
||||
v_dst101 = v_add(v_dst101, v_cvt_f32(v_reinterpret_as_s32(v_src101)));
|
||||
v_dst201 = v_add(v_dst201, v_cvt_f32(v_reinterpret_as_s32(v_src201)));
|
||||
v_dst010 = v_add(v_dst010, v_cvt_f32(v_reinterpret_as_s32(v_src010)));
|
||||
v_dst110 = v_add(v_dst110, v_cvt_f32(v_reinterpret_as_s32(v_src110)));
|
||||
v_dst210 = v_add(v_dst210, v_cvt_f32(v_reinterpret_as_s32(v_src210)));
|
||||
v_dst011 = v_add(v_dst011, v_cvt_f32(v_reinterpret_as_s32(v_src011)));
|
||||
v_dst111 = v_add(v_dst111, v_cvt_f32(v_reinterpret_as_s32(v_src111)));
|
||||
v_dst211 = v_add(v_dst211, v_cvt_f32(v_reinterpret_as_s32(v_src211)));
|
||||
v_dst000 = v_add(v_dst000, v_cvt_f32(v_reinterpret_as_s32(v_src000)));
|
||||
v_dst100 = v_add(v_dst100, v_cvt_f32(v_reinterpret_as_s32(v_src100)));
|
||||
v_dst200 = v_add(v_dst200, v_cvt_f32(v_reinterpret_as_s32(v_src200)));
|
||||
v_dst001 = v_add(v_dst001, v_cvt_f32(v_reinterpret_as_s32(v_src001)));
|
||||
v_dst101 = v_add(v_dst101, v_cvt_f32(v_reinterpret_as_s32(v_src101)));
|
||||
v_dst201 = v_add(v_dst201, v_cvt_f32(v_reinterpret_as_s32(v_src201)));
|
||||
v_dst010 = v_add(v_dst010, v_cvt_f32(v_reinterpret_as_s32(v_src010)));
|
||||
v_dst110 = v_add(v_dst110, v_cvt_f32(v_reinterpret_as_s32(v_src110)));
|
||||
v_dst210 = v_add(v_dst210, v_cvt_f32(v_reinterpret_as_s32(v_src210)));
|
||||
v_dst011 = v_add(v_dst011, v_cvt_f32(v_reinterpret_as_s32(v_src011)));
|
||||
v_dst111 = v_add(v_dst111, v_cvt_f32(v_reinterpret_as_s32(v_src111)));
|
||||
v_dst211 = v_add(v_dst211, v_cvt_f32(v_reinterpret_as_s32(v_src211)));
|
||||
|
||||
v_store_interleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
|
||||
v_store_interleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
|
||||
v_store_interleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
|
||||
v_store_interleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
|
||||
v_store_interleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
|
||||
v_store_interleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
|
||||
v_store_interleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
|
||||
v_store_interleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
|
||||
}
|
||||
}
|
||||
else if (cn == 4)
|
||||
{
|
||||
v_uint8 v_zero = vx_setzero_u8();
|
||||
|
||||
for (; x <= len - cVectorWidth; x += cVectorWidth)
|
||||
{
|
||||
v_uint8 v_mask = vx_load(mask + x);
|
||||
v_mask = v_ne(v_mask, v_zero);
|
||||
|
||||
v_uint8 v_src0, v_src1, v_src2, v_src3;
|
||||
|
||||
v_load_deinterleave(src + x * cn,
|
||||
v_src0, v_src1, v_src2, v_src3);
|
||||
|
||||
v_src0 = v_and(v_src0, v_mask);
|
||||
v_src1 = v_and(v_src1, v_mask);
|
||||
v_src2 = v_and(v_src2, v_mask);
|
||||
v_src3 = v_and(v_src3, v_mask);
|
||||
|
||||
v_uint16 v_src0_u16_0, v_src0_u16_1;
|
||||
v_uint16 v_src1_u16_0, v_src1_u16_1;
|
||||
v_uint16 v_src2_u16_0, v_src2_u16_1;
|
||||
v_uint16 v_src3_u16_0, v_src3_u16_1;
|
||||
|
||||
v_expand(v_src0, v_src0_u16_0, v_src0_u16_1);
|
||||
v_expand(v_src1, v_src1_u16_0, v_src1_u16_1);
|
||||
v_expand(v_src2, v_src2_u16_0, v_src2_u16_1);
|
||||
v_expand(v_src3, v_src3_u16_0, v_src3_u16_1);
|
||||
|
||||
v_uint32 v_src0_u32_0, v_src0_u32_1, v_src0_u32_2, v_src0_u32_3;
|
||||
v_uint32 v_src1_u32_0, v_src1_u32_1, v_src1_u32_2, v_src1_u32_3;
|
||||
v_uint32 v_src2_u32_0, v_src2_u32_1, v_src2_u32_2, v_src2_u32_3;
|
||||
v_uint32 v_src3_u32_0, v_src3_u32_1, v_src3_u32_2, v_src3_u32_3;
|
||||
|
||||
v_expand(v_src0_u16_0, v_src0_u32_0, v_src0_u32_1);
|
||||
v_expand(v_src0_u16_1, v_src0_u32_2, v_src0_u32_3);
|
||||
|
||||
v_expand(v_src1_u16_0, v_src1_u32_0, v_src1_u32_1);
|
||||
v_expand(v_src1_u16_1, v_src1_u32_2, v_src1_u32_3);
|
||||
|
||||
v_expand(v_src2_u16_0, v_src2_u32_0, v_src2_u32_1);
|
||||
v_expand(v_src2_u16_1, v_src2_u32_2, v_src2_u32_3);
|
||||
|
||||
v_expand(v_src3_u16_0, v_src3_u32_0, v_src3_u32_1);
|
||||
v_expand(v_src3_u16_1, v_src3_u32_2, v_src3_u32_3);
|
||||
|
||||
v_float32 v_src0_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_0));
|
||||
v_float32 v_src0_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_1));
|
||||
v_float32 v_src0_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_2));
|
||||
v_float32 v_src0_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_3));
|
||||
|
||||
v_float32 v_src1_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_0));
|
||||
v_float32 v_src1_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_1));
|
||||
v_float32 v_src1_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_2));
|
||||
v_float32 v_src1_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_3));
|
||||
|
||||
v_float32 v_src2_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_0));
|
||||
v_float32 v_src2_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_1));
|
||||
v_float32 v_src2_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_2));
|
||||
v_float32 v_src2_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_3));
|
||||
|
||||
v_float32 v_src3_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_0));
|
||||
v_float32 v_src3_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_1));
|
||||
v_float32 v_src3_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_2));
|
||||
v_float32 v_src3_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_3));
|
||||
|
||||
v_float32 v_dst0, v_dst1, v_dst2, v_dst3;
|
||||
|
||||
v_load_deinterleave(dst + x * cn, v_dst0, v_dst1, v_dst2, v_dst3);
|
||||
|
||||
v_store_interleave(dst + x * cn,
|
||||
v_add(v_dst0, v_src0_f0),
|
||||
v_add(v_dst1, v_src1_f0),
|
||||
v_add(v_dst2, v_src2_f0),
|
||||
v_add(v_dst3, v_src3_f0));
|
||||
|
||||
v_load_deinterleave(dst + (x + step) * cn, v_dst0, v_dst1, v_dst2, v_dst3);
|
||||
|
||||
v_store_interleave(dst + (x + step) * cn,
|
||||
v_add(v_dst0, v_src0_f1),
|
||||
v_add(v_dst1, v_src1_f1),
|
||||
v_add(v_dst2, v_src2_f1),
|
||||
v_add(v_dst3, v_src3_f1));
|
||||
|
||||
v_load_deinterleave(dst + (x + 2 * step) * cn, v_dst0, v_dst1, v_dst2, v_dst3);
|
||||
|
||||
v_store_interleave(dst + (x + 2 * step) * cn,
|
||||
v_add(v_dst0, v_src0_f2),
|
||||
v_add(v_dst1, v_src1_f2),
|
||||
v_add(v_dst2, v_src2_f2),
|
||||
v_add(v_dst3, v_src3_f2));
|
||||
|
||||
v_load_deinterleave(dst + (x + 3 * step) * cn, v_dst0, v_dst1, v_dst2, v_dst3);
|
||||
|
||||
v_store_interleave(dst + (x + 3 * step) * cn,
|
||||
v_add(v_dst0, v_src0_f3),
|
||||
v_add(v_dst1, v_src1_f3),
|
||||
v_add(v_dst2, v_src2_f3),
|
||||
v_add(v_dst3, v_src3_f3));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -500,49 +604,109 @@ void acc_simd_(const float* src, float* dst, const uchar* mask, int len, int cn)
|
||||
}
|
||||
else
|
||||
{
|
||||
v_float32 v_0 = vx_setzero_f32();
|
||||
if (cn == 1)
|
||||
if (x <= len - cVectorWidth)
|
||||
{
|
||||
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
|
||||
v_float32 v_0 = vx_setzero_f32();
|
||||
if (cn == 1)
|
||||
{
|
||||
v_uint16 v_masku16 = vx_load_expand(mask + x);
|
||||
v_uint32 v_masku320, v_masku321;
|
||||
v_expand(v_masku16, v_masku320, v_masku321);
|
||||
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
|
||||
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
|
||||
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
|
||||
{
|
||||
v_uint16 v_masku16 = vx_load_expand(mask + x);
|
||||
v_uint32 v_masku320, v_masku321;
|
||||
v_expand(v_masku16, v_masku320, v_masku321);
|
||||
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
|
||||
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
|
||||
|
||||
v_store(dst + x, v_add(vx_load(dst + x), v_and(vx_load(src + x), v_mask0)));
|
||||
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_and(vx_load(src + x + step), v_mask1)));
|
||||
v_store(dst + x, v_add(vx_load(dst + x), v_and(vx_load(src + x), v_mask0)));
|
||||
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_and(vx_load(src + x + step), v_mask1)));
|
||||
}
|
||||
}
|
||||
else if (cn == 3)
|
||||
{
|
||||
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
|
||||
{
|
||||
v_uint16 v_masku16 = vx_load_expand(mask + x);
|
||||
v_uint32 v_masku320, v_masku321;
|
||||
v_expand(v_masku16, v_masku320, v_masku321);
|
||||
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
|
||||
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
|
||||
|
||||
v_float32 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
|
||||
v_load_deinterleave(src + x * cn, v_src00, v_src10, v_src20);
|
||||
v_load_deinterleave(src + (x + step) * cn, v_src01, v_src11, v_src21);
|
||||
v_src00 = v_and(v_src00, v_mask0);
|
||||
v_src01 = v_and(v_src01, v_mask1);
|
||||
v_src10 = v_and(v_src10, v_mask0);
|
||||
v_src11 = v_and(v_src11, v_mask1);
|
||||
v_src20 = v_and(v_src20, v_mask0);
|
||||
v_src21 = v_and(v_src21, v_mask1);
|
||||
|
||||
v_float32 v_dst00, v_dst01, v_dst10, v_dst11, v_dst20, v_dst21;
|
||||
v_load_deinterleave(dst + x * cn, v_dst00, v_dst10, v_dst20);
|
||||
v_load_deinterleave(dst + (x + step) * cn, v_dst01, v_dst11, v_dst21);
|
||||
|
||||
v_store_interleave(dst + x * cn, v_add(v_dst00, v_src00), v_add(v_dst10, v_src10), v_add(v_dst20, v_src20));
|
||||
v_store_interleave(dst + (x + step) * cn, v_add(v_dst01, v_src01), v_add(v_dst11, v_src11), v_add(v_dst21, v_src21));
|
||||
}
|
||||
}
|
||||
else if (cn == 4)
|
||||
{
|
||||
for (; x <= len - cVectorWidth; x += cVectorWidth)
|
||||
{
|
||||
v_uint16 v_masku16 = vx_load_expand(mask + x);
|
||||
|
||||
v_uint32 v_masku320, v_masku321;
|
||||
v_expand(v_masku16, v_masku320, v_masku321);
|
||||
|
||||
v_float32 v_mask0 = v_reinterpret_as_f32(v_ne(v_masku320, v_reinterpret_as_u32(v_0)));
|
||||
|
||||
v_float32 v_mask1 = v_reinterpret_as_f32(v_ne(v_masku321, v_reinterpret_as_u32(v_0)));
|
||||
|
||||
v_float32 v_src00, v_src01;
|
||||
v_float32 v_src10, v_src11;
|
||||
v_float32 v_src20, v_src21;
|
||||
v_float32 v_src30, v_src31;
|
||||
|
||||
v_load_deinterleave(src + x * cn,
|
||||
v_src00, v_src10, v_src20, v_src30);
|
||||
|
||||
v_load_deinterleave(src + (x + step) * cn,
|
||||
v_src01, v_src11, v_src21, v_src31);
|
||||
|
||||
v_src00 = v_and(v_src00, v_mask0);
|
||||
v_src10 = v_and(v_src10, v_mask0);
|
||||
v_src20 = v_and(v_src20, v_mask0);
|
||||
v_src30 = v_and(v_src30, v_mask0);
|
||||
|
||||
v_src01 = v_and(v_src01, v_mask1);
|
||||
v_src11 = v_and(v_src11, v_mask1);
|
||||
v_src21 = v_and(v_src21, v_mask1);
|
||||
v_src31 = v_and(v_src31, v_mask1);
|
||||
|
||||
v_float32 v_dst00, v_dst01;
|
||||
v_float32 v_dst10, v_dst11;
|
||||
v_float32 v_dst20, v_dst21;
|
||||
v_float32 v_dst30, v_dst31;
|
||||
|
||||
v_load_deinterleave(dst + x * cn, v_dst00, v_dst10, v_dst20, v_dst30);
|
||||
|
||||
v_load_deinterleave(dst + (x + step) * cn, v_dst01, v_dst11, v_dst21, v_dst31);
|
||||
|
||||
v_store_interleave(dst + x * cn,
|
||||
v_add(v_dst00, v_src00),
|
||||
v_add(v_dst10, v_src10),
|
||||
v_add(v_dst20, v_src20),
|
||||
v_add(v_dst30, v_src30));
|
||||
|
||||
v_store_interleave(dst + (x + step) * cn,
|
||||
v_add(v_dst01, v_src01),
|
||||
v_add(v_dst11, v_src11),
|
||||
v_add(v_dst21, v_src21),
|
||||
v_add(v_dst31, v_src31));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cn == 3)
|
||||
{
|
||||
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
|
||||
{
|
||||
v_uint16 v_masku16 = vx_load_expand(mask + x);
|
||||
v_uint32 v_masku320, v_masku321;
|
||||
v_expand(v_masku16, v_masku320, v_masku321);
|
||||
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
|
||||
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
|
||||
|
||||
v_float32 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
|
||||
v_load_deinterleave(src + x * cn, v_src00, v_src10, v_src20);
|
||||
v_load_deinterleave(src + (x + step) * cn, v_src01, v_src11, v_src21);
|
||||
v_src00 = v_and(v_src00, v_mask0);
|
||||
v_src01 = v_and(v_src01, v_mask1);
|
||||
v_src10 = v_and(v_src10, v_mask0);
|
||||
v_src11 = v_and(v_src11, v_mask1);
|
||||
v_src20 = v_and(v_src20, v_mask0);
|
||||
v_src21 = v_and(v_src21, v_mask1);
|
||||
|
||||
v_float32 v_dst00, v_dst01, v_dst10, v_dst11, v_dst20, v_dst21;
|
||||
v_load_deinterleave(dst + x * cn, v_dst00, v_dst10, v_dst20);
|
||||
v_load_deinterleave(dst + (x + step) * cn, v_dst01, v_dst11, v_dst21);
|
||||
|
||||
v_store_interleave(dst + x * cn, v_add(v_dst00, v_src00), v_add(v_dst10, v_src10), v_add(v_dst20, v_src20));
|
||||
v_store_interleave(dst + (x + step) * cn, v_add(v_dst01, v_src01), v_add(v_dst11, v_src11), v_add(v_dst21, v_src21));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CV_SIMD
|
||||
acc_general_(src, dst, mask, len, cn, x);
|
||||
@@ -3106,4 +3270,4 @@ CV_CPU_OPTIMIZATION_NAMESPACE_END
|
||||
|
||||
} // namespace cv
|
||||
|
||||
///* End of file. */
|
||||
///* End of file. */
|
||||
@@ -649,7 +649,7 @@ void cv::findContours(InputArray _image,
|
||||
}
|
||||
|
||||
// Fast path: RETR_LIST without hierarchy → findTRUContours (parallel contour extraction)
|
||||
if (mode == RETR_LIST && !_hierarchy.needed())
|
||||
if (mode == RETR_LIST && !_hierarchy.needed() && _image.type() == CV_8UC1)
|
||||
{
|
||||
// findTRUContours requires FOREGROUND=255; binarize=true thresholds the padded
|
||||
// image in-place, avoiding an extra allocation (findContours accepts any non-zero value)
|
||||
|
||||
@@ -618,7 +618,7 @@ void findTRUContours(InputArray _src, OutputArrayOfArrays _contours, int minSize
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
Mat src = _src.getMat();
|
||||
CV_Assert(!src.empty() && src.type() == CV_8UC1);
|
||||
CV_Assert(src.type() == CV_8UC1);
|
||||
|
||||
// Buffer handling
|
||||
cv::Mat padded;
|
||||
|
||||
@@ -415,22 +415,21 @@ public:
|
||||
int w = std::min(tileSize, dst.cols - dst_x);
|
||||
int h = std::min(tileSize, dst.rows - dst_y);
|
||||
|
||||
int src_x1 = dst_x - dx1, src_y1 = dst_y - dy1;
|
||||
int src_x2 = dst_x + w + dx2, src_y2 = dst_y + h + dy2;
|
||||
Size wholeSize;
|
||||
Point ofs;
|
||||
src.locateROI(wholeSize, ofs);
|
||||
|
||||
// Parent coordinates.
|
||||
int src_x1 = ofs.x + dst_x - dx1, src_y1 = ofs.y + dst_y - dy1;
|
||||
int src_x2 = ofs.x + dst_x + w + dx2,
|
||||
src_y2 = ofs.y + dst_y + h + dy2;
|
||||
|
||||
int pad_top = std::max(0, -src_y1);
|
||||
int pad_bottom = std::max(0, src_y2 - src.rows);
|
||||
int pad_bottom = std::max(0, src_y2 - wholeSize.height);
|
||||
int pad_left = std::max(0, -src_x1);
|
||||
int pad_right = std::max(0, src_x2 - src.cols);
|
||||
int pad_right = std::max(0, src_x2 - wholeSize.width);
|
||||
|
||||
int clamped_x1 = std::max(0, src_x1);
|
||||
int clamped_y1 = std::max(0, src_y1);
|
||||
int clamped_x2 = std::min(src.cols, src_x2);
|
||||
int clamped_y2 = std::min(src.rows, src_y2);
|
||||
|
||||
Mat src_region = src(Rect(clamped_x1, clamped_y1,
|
||||
clamped_x2 - clamped_x1,
|
||||
clamped_y2 - clamped_y1));
|
||||
Mat src_region = src(Rect(dst_x, dst_y, w, h)).adjustROI(dy1, dy2, dx1, dx2);
|
||||
|
||||
Mat tile_mat;
|
||||
if (pad_top == 0 && pad_bottom == 0 && pad_left == 0 && pad_right == 0)
|
||||
@@ -542,9 +541,41 @@ void FilterEngine__apply(FilterEngine& this_, const Mat& src, Mat& dst, const Si
|
||||
(size_t)src.total() >= std::max((size_t)1024 * 1024, (size_t)nthreads * 64 * 1024) &&
|
||||
this_.rowBorderType == this_.columnBorderType)
|
||||
{
|
||||
// For in-place operations (e.g. morphologyEx MORPH_OPEN), clone src so that
|
||||
// concurrent tiles read from an immutable snapshot rather than racing on writes.
|
||||
Mat src_copy = (src.data == dst.data) ? src.clone() : src;
|
||||
// Robust cloning for in-place/overlapping operations with ROI support.
|
||||
Size resolved_wsz = wsz;
|
||||
Point resolved_ofs = ofs;
|
||||
if (resolved_wsz.width < 0) {
|
||||
src.locateROI(resolved_wsz, resolved_ofs);
|
||||
}
|
||||
|
||||
bool overlap = (src.data <= dst.dataend && dst.data <= src.dataend);
|
||||
Mat src_copy;
|
||||
if (resolved_wsz == src.size()) {
|
||||
src_copy = overlap ? src.clone() : src;
|
||||
} else {
|
||||
// In case of ROI.
|
||||
Mat parent(resolved_wsz, src.type(),
|
||||
(void*)(src.data - resolved_ofs.y * src.step -
|
||||
resolved_ofs.x * src.elemSize()),
|
||||
src.step);
|
||||
if (overlap) {
|
||||
int dx1 = this_.anchor.x, dx2 = this_.ksize.width - dx1 - 1;
|
||||
int dy1 = this_.anchor.y, dy2 = this_.ksize.height - dy1 - 1;
|
||||
|
||||
int p_x1 = std::max(0, resolved_ofs.x - dx1);
|
||||
int p_y1 = std::max(0, resolved_ofs.y - dy1);
|
||||
|
||||
// Clone the required region only.
|
||||
Mat required_region = parent(Rect(resolved_ofs, src.size())).adjustROI(dy1, dy2, dx1, dx2).clone();
|
||||
|
||||
src_copy = required_region(Rect(resolved_ofs - Point(p_x1, p_y1), src.size()));
|
||||
} else {
|
||||
// Actually src_copy = src but makes sure src_copy is seen as a sub-matrix
|
||||
// because sepFilter2D creates a submatrix on the fly without having it be
|
||||
// an official sub-matrix (which would make locateROI fail in TiledFilterInvoker)
|
||||
src_copy = parent(Rect(resolved_ofs, src.size()));
|
||||
}
|
||||
}
|
||||
|
||||
// Heuristic: Balance L2 cache locality (128) vs parallel load balancing (64).
|
||||
int tileSize = (src.total() < (size_t)nthreads * 128 * 128 * 4) ? 64 : 128;
|
||||
|
||||
@@ -1409,6 +1409,30 @@ inline int hal_ni_laplacian(const uchar* src_data, size_t src_step, uchar* dst_d
|
||||
#define cv_hal_laplacian hal_ni_laplacian
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
@brief Compute spatial gradient (Sobel X and Y simultaneously).
|
||||
@param src_data Source image data (8-bit single channel)
|
||||
@param src_step Source image step
|
||||
@param dx_data Destination X-gradient data (16-bit signed)
|
||||
@param dx_step Destination X-gradient step
|
||||
@param dy_data Destination Y-gradient data (16-bit signed)
|
||||
@param dy_step Destination Y-gradient step
|
||||
@param width Image width
|
||||
@param height Image height
|
||||
@param ksize Kernel size (must be 3)
|
||||
@param border_type Border type (BORDER_DEFAULT or BORDER_REPLICATE)
|
||||
*/
|
||||
inline int hal_ni_spatialGradient(const uchar* src_data, size_t src_step,
|
||||
short* dx_data, size_t dx_step,
|
||||
short* dy_data, size_t dy_step,
|
||||
int width, int height,
|
||||
int ksize, int border_type)
|
||||
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @cond IGNORED
|
||||
#define cv_hal_spatialGradient hal_ni_spatialGradient
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
@brief Perform Gaussian Blur and downsampling for input tile.
|
||||
@param depth Depths of source and destination image
|
||||
|
||||
@@ -113,6 +113,13 @@ void spatialGradient( InputArray _src, OutputArray _dx, OutputArray _dy,
|
||||
// TODO: Allow for other kernel sizes
|
||||
CV_Assert(ksize == 3);
|
||||
|
||||
CALL_HAL(spatialGradient, cv_hal_spatialGradient,
|
||||
src.data, src.step,
|
||||
dx.ptr<short>(), dx.step,
|
||||
dy.ptr<short>(), dy.step,
|
||||
src.cols, src.rows,
|
||||
ksize, borderType);
|
||||
|
||||
// Get dimensions
|
||||
const int H = src.rows,
|
||||
W = src.cols;
|
||||
|
||||
@@ -1450,4 +1450,61 @@ TEST(Imgproc_Filter2D, padding_bounds_roi_isolated)
|
||||
}
|
||||
}
|
||||
|
||||
class FastFilterEngineTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Prepare separable kernels (3x3 averaging filter [1, 1, 1]).
|
||||
kX = cv::Mat::ones(1, 3, CV_32F) / 3.0f;
|
||||
kY = cv::Mat::ones(3, 1, CV_32F) / 3.0f;
|
||||
}
|
||||
|
||||
cv::Mat kX, kY;
|
||||
};
|
||||
|
||||
TEST_F(FastFilterEngineTest, Submatrix) {
|
||||
// num_threads == 2 triggers the fast path.
|
||||
for(int num_threads : {1, 2}) {
|
||||
setNumThreads(num_threads);
|
||||
Mat1b parent(1200, 1200, 255);
|
||||
Mat roi = parent(Rect(100, 100, 1024, 1024));
|
||||
roi.setTo(Scalar(0));
|
||||
Mat dst;
|
||||
|
||||
sepFilter2D(roi, dst, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
|
||||
|
||||
// Before fix in fast path: dst.at<uchar>(0,0) == 0 (treated as isolated).
|
||||
// With fix in fast path: dst.at<uchar>(0,0) > 0 (correctly reads 255 padding from parent).
|
||||
EXPECT_GT(dst.at<uchar>(0, 0), 0);
|
||||
|
||||
// Filter in-place directly into 'roi' (dst == roi).
|
||||
sepFilter2D(roi, roi, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
|
||||
|
||||
// Before fix in fast path: roi.at<uchar>(0,0) == 0 (cloned only ROI, lost parent padding).
|
||||
// With fix in fast path: roi.at<uchar>(0,0) > 0 (clones required_region including padding).
|
||||
EXPECT_GT(roi.at<uchar>(0, 0), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FastFilterEngineTest, FullImage) {
|
||||
// num_threads == 2 triggers the fast path.
|
||||
for(int num_threads : {1, 2}) {
|
||||
setNumThreads(num_threads);
|
||||
Mat1b img(1024, 1024, 100);
|
||||
|
||||
Mat dst;
|
||||
|
||||
sepFilter2D(img, dst, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
|
||||
|
||||
// Verifies direct pass-through (src_copy = src) executes correctly.
|
||||
EXPECT_EQ(dst.at<uchar>(0, 0), 100);
|
||||
|
||||
// Filter in-place directly into 'img' (dst == img).
|
||||
sepFilter2D(img, img, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
|
||||
|
||||
// Verifies that full-image cloning (src.clone()) executes correctly without memory corruption.
|
||||
EXPECT_EQ(img.at<uchar>(0, 0), 100);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
ECC multiscale alignment test
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
import inspect
|
||||
import math
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class eccms_test(NewOpenCVTests):
|
||||
def test_eccms(self):
|
||||
expected_res = np.array([
|
||||
[1.0225, 0.0606, -28.6452],
|
||||
[-0.0475, 1.0314, 11.819],
|
||||
[8.21e-06, -3.65e-07, 1.0]
|
||||
], dtype=np.float32)
|
||||
|
||||
largeGray0 = self.get_sample('cv/shared/halmosh0.jpg', cv.IMREAD_GRAYSCALE)
|
||||
largeGray1 = self.get_sample('cv/shared/halmosh2.jpg', cv.IMREAD_GRAYSCALE)
|
||||
roiMask0 = self.get_sample('cv/shared/halmosh0mask.png', cv.IMREAD_GRAYSCALE)
|
||||
roiMask1 = self.get_sample('cv/shared/halmosh2mask.png', cv.IMREAD_GRAYSCALE)
|
||||
|
||||
if largeGray0 is None or largeGray1 is None or roiMask0 is None or roiMask1 is None:
|
||||
self.assertEqual(0, 1, 'Missing test data')
|
||||
|
||||
found = np.eye(3, 3, dtype=np.float32)
|
||||
n_iters = 23
|
||||
termination_eps = 1e-6
|
||||
params = cv.ECCParameters()
|
||||
params.criteria = (cv.TERM_CRITERIA_COUNT + cv.TERM_CRITERIA_EPS, n_iters, termination_eps)
|
||||
params.motionType = cv.MOTION_HOMOGRAPHY
|
||||
params.nlevels = 5
|
||||
params.itersPerLevel = [5, 10, 300, 300, 1000]
|
||||
|
||||
_, found = cv.findTransformECCMultiScale(largeGray0,largeGray1, found, params, roiMask0, roiMask1)
|
||||
|
||||
self.assertLess(cv.norm(found - expected_res, cv.NORM_L1), 0.1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
NewOpenCVTests.bootstrap()
|
||||
@@ -453,10 +453,10 @@ Affects accuracy, especially when motionType == MOTION_TRANSLATION. (DEFAULT: IN
|
||||
*/
|
||||
struct CV_EXPORTS_W_SIMPLE ECCParameters
|
||||
{
|
||||
CV_WRAP ECCParameters() {}
|
||||
CV_WRAP ECCParameters();
|
||||
CV_PROP_RW int motionType = MOTION_AFFINE;
|
||||
CV_PROP_RW cv::TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 50, 1e-6);
|
||||
CV_PROP_RW std::vector<int> itersPerLevel = std::vector<int>();
|
||||
CV_PROP_RW cv::TermCriteria criteria;
|
||||
CV_PROP_RW std::vector<int> itersPerLevel;
|
||||
CV_PROP_RW int gaussFiltSize = 5;
|
||||
CV_PROP_RW int nlevels = 4;
|
||||
CV_PROP_RW int interpolation = INTER_LINEAR;
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
\****************************************************************************************/
|
||||
|
||||
namespace cv {
|
||||
ECCParameters::ECCParameters() : criteria(TermCriteria::COUNT + TermCriteria::EPS, 50, 1e-6)
|
||||
{}
|
||||
|
||||
typedef std::vector<cv::Mat> MatPyramid;
|
||||
|
||||
template<int motionType> struct MotionTraits {};
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef testing::TestWithParam<tuple<Size, int, int> > Video_Acc_Cn4;
|
||||
|
||||
TEST_P(Video_Acc_Cn4, accuracy)
|
||||
{
|
||||
const Size size = get<0>(GetParam());
|
||||
const int pattern = get<1>(GetParam());
|
||||
const int srcType = get<2>(GetParam());
|
||||
|
||||
RNG& rng = theRNG();
|
||||
|
||||
Mat src(size, srcType);
|
||||
Mat dst(size, CV_32FC4);
|
||||
Mat mask(size, CV_8UC1);
|
||||
|
||||
if (srcType == CV_8UC4)
|
||||
rng.fill(src, RNG::UNIFORM, Scalar::all(0), Scalar::all(256));
|
||||
else
|
||||
rng.fill(src, RNG::UNIFORM, Scalar::all(-10.0), Scalar::all(10.0));
|
||||
|
||||
rng.fill(dst, RNG::UNIFORM, Scalar::all(-1000.0), Scalar::all(1000.0));
|
||||
|
||||
for (int y = 0; y < mask.rows; ++y)
|
||||
{
|
||||
uchar* row = mask.ptr<uchar>(y);
|
||||
|
||||
for (int x = 0; x < mask.cols; ++x)
|
||||
{
|
||||
switch (pattern)
|
||||
{
|
||||
case 0:
|
||||
row[x] = 0;
|
||||
break;
|
||||
case 1:
|
||||
row[x] = 255;
|
||||
break;
|
||||
case 2:
|
||||
row[x] = ((x + y) % 2) ? 255 : 0;
|
||||
break;
|
||||
case 3:
|
||||
row[x] = ((x * 13 + y * 7) % 5) ? 255 : 0;
|
||||
break;
|
||||
default:
|
||||
row[x] = ((x * 17 + y * 11) % 3) ? 255 : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mat dstRef = dst.clone();
|
||||
|
||||
if (srcType == CV_32FC4)
|
||||
{
|
||||
for (int y = 0; y < src.rows; ++y)
|
||||
{
|
||||
const Vec4f* srcRow = src.ptr<Vec4f>(y);
|
||||
Vec4f* dstRefRow = dstRef.ptr<Vec4f>(y);
|
||||
const uchar* maskRow = mask.ptr<uchar>(y);
|
||||
|
||||
for (int x = 0; x < src.cols; ++x)
|
||||
{
|
||||
if (maskRow[x])
|
||||
{
|
||||
for (int c = 0; c < 4; ++c)
|
||||
dstRefRow[x][c] += srcRow[x][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Assert(srcType == CV_8UC4);
|
||||
|
||||
for (int y = 0; y < src.rows; ++y)
|
||||
{
|
||||
const Vec4b* srcRow = src.ptr<Vec4b>(y);
|
||||
Vec4f* dstRefRow = dstRef.ptr<Vec4f>(y);
|
||||
const uchar* maskRow = mask.ptr<uchar>(y);
|
||||
|
||||
for (int x = 0; x < src.cols; ++x)
|
||||
{
|
||||
if (maskRow[x])
|
||||
{
|
||||
for (int c = 0; c < 4; ++c)
|
||||
dstRefRow[x][c] += static_cast<float>(srcRow[x][c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv::accumulate(src, dst, mask);
|
||||
|
||||
const double err = cv::norm(dst, dstRef, NORM_INF);
|
||||
|
||||
EXPECT_EQ(0.0, err)
|
||||
<< "size=" << size
|
||||
<< ", pattern=" << pattern
|
||||
<< ", srcType=" << srcType;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Accumulate,
|
||||
Video_Acc_Cn4,
|
||||
testing::Combine(
|
||||
testing::Values(Size(1, 1),
|
||||
Size(3, 5),
|
||||
Size(17, 7),
|
||||
Size(37, 19),
|
||||
Size(128, 16),
|
||||
Size(641, 37)),
|
||||
testing::Values(0, 1, 2, 3, 4),
|
||||
testing::Values(CV_32FC4, CV_8UC4)));
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -1633,7 +1633,9 @@ bool CvCapture_MSMF::configureAudioFrame()
|
||||
chunkLengthOfBytes = bufferAudioData.size();
|
||||
audioSamplePos += chunkLengthOfBytes/bytesPerSample;
|
||||
}
|
||||
CV_Check((double)chunkLengthOfBytes, chunkLengthOfBytes >= INT_MIN || chunkLengthOfBytes <= INT_MAX, "MSMF: The chunkLengthOfBytes is out of the allowed range");
|
||||
if ((LONGLONG)bufferAudioData.size() < chunkLengthOfBytes)
|
||||
chunkLengthOfBytes = (LONGLONG)bufferAudioData.size();
|
||||
CV_Check((double)chunkLengthOfBytes, chunkLengthOfBytes >= INT_MIN && chunkLengthOfBytes <= INT_MAX, "MSMF: The chunkLengthOfBytes is out of the allowed range");
|
||||
copy(bufferAudioData.begin(), bufferAudioData.begin() + (int)chunkLengthOfBytes, std::back_inserter(audioDataInUse));
|
||||
bufferAudioData.erase(bufferAudioData.begin(), bufferAudioData.begin() + (int)chunkLengthOfBytes);
|
||||
if (audioFrame.empty())
|
||||
|
||||
Reference in New Issue
Block a user