1
0
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:
Alexander Smorkalov
2026-06-01 13:21:19 +03:00
30 changed files with 1245 additions and 152 deletions
@@ -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.
@@ -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}
| | |
@@ -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$
![](images/how_to_use_OpenCV_parallel_for_sqrt_scale_transformation.png)
@@ -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
@@ -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
@@ -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.
+3 -3
View File
@@ -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
+12 -4
View File
@@ -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
+148
View File
@@ -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);
}
+5
View File
@@ -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
+17
View File
@@ -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];
+14 -2
View File
@@ -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 ||
+3 -1
View File
@@ -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;
}
+138
View File
@@ -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
+6
View File
@@ -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
View File
@@ -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. */
+1 -1
View 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)
+1 -1
View File
@@ -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;
+46 -15
View File
@@ -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;
+24
View File
@@ -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
+7
View File
@@ -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;
+57
View File
@@ -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
+47
View File
@@ -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;
+3
View File
@@ -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 {};
+157
View File
@@ -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
+3 -1
View File
@@ -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())