diff --git a/3rdparty/tbb/CMakeLists.txt b/3rdparty/tbb/CMakeLists.txt index 79b74a89a2..2083415c61 100644 --- a/3rdparty/tbb/CMakeLists.txt +++ b/3rdparty/tbb/CMakeLists.txt @@ -169,6 +169,6 @@ ocv_install_target(tbb EXPORT OpenCVModules OPTIONAL ) -ocv_install_3rdparty_licenses(tbb "${tbb_src_dir}/LICENSE" "${tbb_src_dir}/README") +ocv_install_3rdparty_licenses(tbb "${tbb_src_dir}/LICENSE.txt" "${tbb_src_dir}/README.md") ocv_tbb_read_version("${tbb_src_dir}/include" tbb) diff --git a/cmake/checks/cpu_fp16.cpp b/cmake/checks/cpu_fp16.cpp index 6bffc4792a..c57b5d47b6 100644 --- a/cmake/checks/cpu_fp16.cpp +++ b/cmake/checks/cpu_fp16.cpp @@ -11,7 +11,8 @@ int test() _mm_storel_epi64((__m128i*)dst, v_dst); return (int)dst[0]; } -#elif (defined __GNUC__ && (defined __arm__ || defined __aarch64__)) || (defined _MSC_VER && defined _M_ARM64) +#elif (defined __GNUC__ && (defined __arm__ || defined __aarch64__)) /*|| (defined _MSC_VER && defined _M_ARM64)*/ +// Windows + ARM64 case disabled: https://github.com/opencv/opencv/issues/25052 #include "arm_neon.h" int test() { diff --git a/modules/3d/src/calibration_base.cpp b/modules/3d/src/calibration_base.cpp index 316f77b311..37542ac40a 100644 --- a/modules/3d/src/calibration_base.cpp +++ b/modules/3d/src/calibration_base.cpp @@ -934,8 +934,8 @@ cv::Vec3d cv::RQDecomp3x3( InputArray _Marr, Qx = ( 0 c s ), c = m33/sqrt(m32^2 + m33^2), s = m32/sqrt(m32^2 + m33^2) ( 0 -s c ) */ - s = M(2, 1); - c = M(2, 2); + s = std::abs(M(2, 1)) > DBL_EPSILON ? M(2, 1): 0.; + c = std::abs(M(2, 1)) > DBL_EPSILON ? M(2, 2): 1.; z = 1./std::sqrt(c * c + s * s + DBL_EPSILON); c *= z; s *= z; @@ -952,8 +952,8 @@ cv::Vec3d cv::RQDecomp3x3( InputArray _Marr, Qy = ( 0 1 0 ), c = m33/sqrt(m31^2 + m33^2), s = -m31/sqrt(m31^2 + m33^2) ( s 0 c ) */ - s = -R(2, 0); - c = R(2, 2); + s = std::abs(R(2, 0)) > DBL_EPSILON ? -R(2, 0): 0.; + c = std::abs(R(2, 0)) > DBL_EPSILON ? R(2, 2): 1.; z = 1./std::sqrt(c * c + s * s + DBL_EPSILON); c *= z; s *= z; @@ -971,8 +971,8 @@ cv::Vec3d cv::RQDecomp3x3( InputArray _Marr, ( 0 0 1 ) */ - s = M(1, 0); - c = M(1, 1); + s = std::abs(M(1, 0)) > DBL_EPSILON ? M(1, 0): 0.; + c = std::abs(M(1, 0)) > DBL_EPSILON ? M(1, 1): 1.; z = 1./std::sqrt(c * c + s * s + DBL_EPSILON); c *= z; s *= z; diff --git a/modules/3d/test/test_decompose_projection.cpp b/modules/3d/test/test_decompose_projection.cpp index e43aa65b69..0e3a420d69 100644 --- a/modules/3d/test/test_decompose_projection.cpp +++ b/modules/3d/test/test_decompose_projection.cpp @@ -141,4 +141,23 @@ TEST(Calib3d_DecomposeProjectionMatrix, accuracy) test.safe_run(); } +TEST(Calib3d_DecomposeProjectionMatrix, degenerate_cases) +{ + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 2; j++) + { + cv::Matx34d P; + P(0, i) = 1; + P(1, (i + j + 1) % 3) = 1; + P(2, (i + 2 * j + 2) % 3) = 1; + + cv::Matx33d K, R; + cv::Vec4d t; + decomposeProjectionMatrix(P, K, R, t); + EXPECT_LT(cv::norm(K * R, P.get_minor<3, 3>(0, 0), cv::NORM_INF), 1e-6); + } + } +} + }} // namespace diff --git a/modules/dnn/src/layers/attention_layer.cpp b/modules/dnn/src/layers/attention_layer.cpp index 085ec734da..559480d599 100644 --- a/modules/dnn/src/layers/attention_layer.cpp +++ b/modules/dnn/src/layers/attention_layer.cpp @@ -83,6 +83,19 @@ class AttentionLayerImpl CV_FINAL : public AttentionLayer { } else { CV_Error(Error::StsBadArg, format("DNN/Attention: invalid output dimension %zu, valid value is 2 or 3", output_ndims)); } + + const int batch_size_ = input_shape[0], seq_len_ = input_shape[1], + hidden_size_ = weight_shape.back(), + num_heads_ = static_cast(num_heads), + v_head_size_ = static_cast((hidden_size_ - qkv_hidden_sizes[0] - qkv_hidden_sizes[1]) / num_heads); + + MatShape gemm_buffer_shape{batch_size_, seq_len_, hidden_size_}, + attention_prob_shape{batch_size_ * num_heads_, seq_len_, seq_len_}, + output_buffer_shape{batch_size_ * num_heads_, seq_len_, v_head_size_}; + internals.assign(1, gemm_buffer_shape); + internals.push_back(attention_prob_shape); + internals.push_back(output_buffer_shape); + return false; } @@ -112,9 +125,10 @@ class AttentionLayerImpl CV_FINAL : public AttentionLayer { return; } - std::vector inputs, outputs; + std::vector inputs, outputs, internals; inputs_arr.getMatVector(inputs); outputs_arr.getMatVector(outputs); + internals_arr.getMatVector(internals); // prepack weights if (!is_prepacked) { @@ -131,7 +145,8 @@ class AttentionLayerImpl CV_FINAL : public AttentionLayer { float *packed_weights[3] = {packed_weight_q.data(), packed_weight_k.data(), packed_weight_v.data()}; size_t packed_weights_size[3] = {packed_weight_q.size() / num_heads, packed_weight_k.size() / num_heads, packed_weight_v.size() / num_heads}; - Mat gemm_buffer = Mat::zeros(1, int(batch_size * seq_len * hidden_size), CV_32F); + // Compute Q/K/V + auto &gemm_buffer = internals[0]; auto *Q = gemm_buffer.ptr(); auto *K = Q + batch_size * seq_len * qkv_hidden_sizes[0]; auto *V = K + batch_size * seq_len * qkv_hidden_sizes[1]; @@ -177,9 +192,8 @@ class AttentionLayerImpl CV_FINAL : public AttentionLayer { parallel_for_(Range(0, loops), fn, nstripes); } - // Compute softmax(scale * matmul(Q, K)) - std::vector attention_prob_shape{int(batch_size * num_heads), int(seq_len), int(seq_len)}; - Mat attention_prob = Mat::zeros(attention_prob_shape.size(), attention_prob_shape.data(), CV_32F); + // Compute Softmax(scale * MatMul(Q, K)) + auto &attention_prob = internals[1]; { auto *output = attention_prob.ptr(); @@ -202,12 +216,12 @@ class AttentionLayerImpl CV_FINAL : public AttentionLayer { } }, loops * seq_len * qk_head_size * seq_len * (1 / 1024.0)); - // Compute softmax - softmax(attention_prob, attention_prob, attention_prob_shape.size() - 1); + // Compute softmax on the last dimension + softmax(attention_prob, attention_prob, shape(attention_prob).size() - 1); } - // Compute np.matmul(attention_prob, V) - Mat output_buffer = Mat::zeros(1, int(batch_size * num_heads * seq_len * qkv_head_sizes[2]), CV_32F); + // Compute MatMul(attention_prob, V) + auto &output_buffer = internals[2]; { auto *output = outputs[0].ptr(); auto *output_buff = output_buffer.ptr(); diff --git a/modules/dnn/src/layers/einsum_layer.cpp b/modules/dnn/src/layers/einsum_layer.cpp index 63fd8e4d94..b0a472bb6d 100644 --- a/modules/dnn/src/layers/einsum_layer.cpp +++ b/modules/dnn/src/layers/einsum_layer.cpp @@ -547,7 +547,7 @@ public: MatShape realOutputDims = shape(result); size_t realProd = std::accumulate(realOutputDims.begin(), realOutputDims.end(), 1, std::multiplies()); - CV_CheckEQ(reqProd, realProd, "Real output can not be shaped in to requred output"); + CV_CheckEQ(reqProd, realProd, "Real output can not be shaped in to required output"); // reduce dimentions result = result.reshape(1, einsumOutDims.size(), einsumOutDims.data()); @@ -1280,11 +1280,12 @@ Mat LayerEinsumImpl::pairwiseOperandProcess( // Covered by ExplicitEinsumAsTensorContractionReshapeFinal. output = output.reshape(1, reshaped_dims.size(), reshaped_dims.data()); } - } else { - output = Transpose( - output, - outputDims, - outputPermutation); + else { + output = Transpose( + output, + outputDims, + outputPermutation); + } } } else { // This is the final pair - Transpose directly to the output ordering required and copy the contents to the op's output // not sure if this finalize shape is needed at all diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index e5a9da64cf..e105d5784d 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -274,7 +274,8 @@ enum InterpolationFlags{ - flag is __not__ set: \f$dst( \rho , \phi ) = src(x,y)\f$ - flag is set: \f$dst(x,y) = src( \rho , \phi )\f$ */ - WARP_INVERSE_MAP = 16 + WARP_INVERSE_MAP = 16, + WARP_RELATIVE_MAP = 32 }; /** \brief Specify the polar mapping mode @@ -2510,6 +2511,7 @@ CV_EXPORTS_W void warpPerspective( InputArray src, OutputArray dst, The function remap transforms the source image using the specified map: \f[\texttt{dst} (x,y) = \texttt{src} (map_x(x,y),map_y(x,y))\f] +\f[\texttt{dst} (x,y) = \texttt{src} (x+map_x(x,y),y+map_y(x,y))\f] with WARP_RELATIVE_MAP where values of pixels with non-integer coordinates are computed using one of available interpolation methods. \f$map_x\f$ and \f$map_y\f$ can be encoded as separate floating-point maps @@ -2529,7 +2531,9 @@ representation to fixed-point for speed. @param map2 The second map of y values having the type CV_16UC1, CV_32FC1, or none (empty map if map1 is (x,y) points), respectively. @param interpolation Interpolation method (see #InterpolationFlags). The methods #INTER_AREA -and #INTER_LINEAR_EXACT are not supported by this function. +#INTER_LINEAR_EXACT and #INTER_NEAREST_EXACT are not supported by this function. +The extra flag WARP_RELATIVE_MAP that can be ORed to the interpolation method +(e.g. INTER_LINEAR | WARP_RELATIVE_MAP) @param borderMode Pixel extrapolation method (see #BorderTypes). When borderMode=#BORDER_TRANSPARENT, it means that the pixels in the destination image that corresponds to the "outliers" in the source image are not modified by the function. diff --git a/modules/imgproc/perf/perf_warp.cpp b/modules/imgproc/perf/perf_warp.cpp index 4e7de8d2fe..3716e663f9 100644 --- a/modules/imgproc/perf/perf_warp.cpp +++ b/modules/imgproc/perf/perf_warp.cpp @@ -9,14 +9,15 @@ enum{HALF_SIZE=0, UPSIDE_DOWN, REFLECTION_X, REFLECTION_BOTH}; CV_ENUM(BorderMode, BORDER_CONSTANT, BORDER_REPLICATE) CV_ENUM(InterType, INTER_NEAREST, INTER_LINEAR) +CV_ENUM(InterTypeExtended, INTER_NEAREST, INTER_LINEAR, WARP_RELATIVE_MAP) CV_ENUM(RemapMode, HALF_SIZE, UPSIDE_DOWN, REFLECTION_X, REFLECTION_BOTH) typedef TestBaseWithParam< tuple > TestWarpAffine; typedef TestBaseWithParam< tuple > TestWarpPerspective; typedef TestBaseWithParam< tuple > TestWarpPerspectiveNear_t; -typedef TestBaseWithParam< tuple > TestRemap; +typedef TestBaseWithParam< tuple > TestRemap; -void update_map(const Mat& src, Mat& map_x, Mat& map_y, const int remapMode ); +void update_map(const Mat& src, Mat& map_x, Mat& map_y, const int remapMode, bool relative = false ); PERF_TEST_P( TestWarpAffine, WarpAffine, Combine( @@ -204,7 +205,7 @@ PERF_TEST_P( TestRemap, remap, Combine( Values( CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1 ), Values( szVGA, sz1080p ), - InterType::all(), + InterTypeExtended::all(), BorderMode::all(), RemapMode::all() ) @@ -224,7 +225,7 @@ PERF_TEST_P( TestRemap, remap, declare.in(source, WARMUP_RNG); - update_map(source, map_x, map_y, remapMode); + update_map(source, map_x, map_y, remapMode, ((interpolationType & WARP_RELATIVE_MAP) != 0)); TEST_CYCLE() { @@ -234,7 +235,7 @@ PERF_TEST_P( TestRemap, remap, SANITY_CHECK_NOTHING(); } -void update_map(const Mat& src, Mat& map_x, Mat& map_y, const int remapMode ) +void update_map(const Mat& src, Mat& map_x, Mat& map_y, const int remapMode, bool relative ) { for( int j = 0; j < src.rows; j++ ) { @@ -267,6 +268,12 @@ void update_map(const Mat& src, Mat& map_x, Mat& map_y, const int remapMode ) map_y.at(j,i) = static_cast(src.rows - j) ; break; } // end of switch + + if( relative ) + { + map_x.at(j,i) -= static_cast(i); + map_y.at(j,i) -= static_cast(j); + } } } } diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index b3740d617a..d46c66ef8c 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -326,9 +326,9 @@ static inline int clip(int x, int a, int b) * General warping (affine, perspective, remap) * \****************************************************************************************/ -template +template static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, - int borderType, const Scalar& _borderValue ) + int borderType, const Scalar& _borderValue, const Point& _offset ) { Size ssize = _src.size(), dsize = _dst.size(); const int cn = _src.channels(); @@ -341,7 +341,7 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, unsigned width1 = ssize.width, height1 = ssize.height; - if( _dst.isContinuous() && _xy.isContinuous() ) + if( _dst.isContinuous() && _xy.isContinuous() && !isRelative ) { dsize.width *= dsize.height; dsize.height = 1; @@ -351,12 +351,13 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, { T* D = _dst.ptr(dy); const short* XY = _xy.ptr(dy); - + const int off_y = isRelative ? (_offset.y+dy) : 0; if( cn == 1 ) { for(int dx = 0; dx < dsize.width; dx++ ) { - int sx = XY[dx*2], sy = XY[dx*2+1]; + const int off_x = isRelative ? (_offset.x+dx) : 0; + int sx = XY[dx*2]+off_x, sy = XY[dx*2+1]+off_y; if( (unsigned)sx < width1 && (unsigned)sy < height1 ) D[dx] = S0[sy*sstep + sx]; else @@ -382,7 +383,8 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, { for(int dx = 0; dx < dsize.width; dx++, D += cn ) { - int sx = XY[dx*2], sy = XY[dx*2+1]; + const int off_x = isRelative ? (_offset.x+dx) : 0; + int sx = XY[dx*2]+off_x, sy = XY[dx*2+1]+off_y; const T *S; if( (unsigned)sx < width1 && (unsigned)sy < height1 ) { @@ -427,11 +429,11 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, } } - +template struct RemapNoVec { int operator()( const Mat&, void*, const short*, const ushort*, - const void*, int ) const { return 0; } + const void*, int, cv::Point& ) const { return 0; } }; #if CV_SIMD128 @@ -439,13 +441,13 @@ struct RemapNoVec typedef unsigned short CV_DECL_ALIGNED(1) unaligned_ushort; typedef int CV_DECL_ALIGNED(1) unaligned_int; +template struct RemapVec_8u { int operator()( const Mat& _src, void* _dst, const short* XY, - const ushort* FXY, const void* _wtab, int width ) const + const ushort* FXY, const void* _wtab, int width, const Point& _offset ) const { int cn = _src.channels(), x = 0, sstep = (int)_src.step; - if( (cn != 1 && cn != 3 && cn != 4) || sstep >= 0x8000 ) return 0; @@ -493,12 +495,25 @@ struct RemapVec_8u *(unaligned_ushort*)(base + offset[2]), *(unaligned_ushort*)(base + offset[3]), \ 0, 0, 0, 0) + const short _rel_offset_x = static_cast(_offset.x); + const short _rel_offset_y = static_cast(_offset.y); + v_int16x8 v_dxy0(_rel_offset_x, _rel_offset_y, _rel_offset_x, _rel_offset_y, _rel_offset_x, _rel_offset_y, _rel_offset_x, _rel_offset_y); + v_int16x8 v_dxy1 = v_dxy0; + v_dxy0 = v_add(v_dxy0, v_int16x8(0, 0, 1, 0, 2, 0, 3, 0)); + v_dxy1 = v_add(v_dxy1, v_int16x8(4, 0, 5, 0, 6, 0, 7, 0)); if( cn == 1 ) { for( ; x <= width - 8; x += 8 ) { v_int16x8 _xy0 = v_load(XY + x*2); v_int16x8 _xy1 = v_load(XY + x*2 + 8); + if (isRelative) + { + const short x_s16 = static_cast(x); + v_int16x8 v_dxy01(x_s16, 0, x_s16, 0, x_s16, 0, x_s16, 0); + _xy0 = v_add(_xy0, v_add(v_dxy01, v_dxy0)); + _xy1 = v_add(_xy1, v_add(v_dxy01, v_dxy1)); + } v_int32x4 v0, v1, v2, v3, a0, b0, c0, d0, a1, b1, c1, d1, a2, b2, c2, d2; v_int32x4 xy0 = v_dotprod( _xy0, xy2ofs ); @@ -545,6 +560,12 @@ struct RemapVec_8u { v_int16x8 u0, v0, u1, v1; v_int16x8 _xy0 = v_load(XY + x * 2); + if (isRelative) + { + const short x_s16 = static_cast(x); + v_int16x8 v_dxy01(x_s16, 0, x_s16, 0, x_s16, 0, x_s16, 0); + _xy0 = v_add(_xy0, v_add(v_dxy01, v_dxy0)); + } v_int32x4 xy0 = v_dotprod(_xy0, xy2ofs); v_store(iofs0, xy0); @@ -595,10 +616,17 @@ struct RemapVec_8u for( ; x <= width - 4; x += 4, D += 16 ) { v_int16x8 _xy0 = v_load(XY + x * 2); + if (isRelative) + { + const short x_s16 = static_cast(x); + v_int16x8 v_dxy01(x_s16, 0, x_s16, 0, x_s16, 0, x_s16, 0); + _xy0 = v_add(_xy0, v_add(v_dxy01, v_dxy0)); + } v_int16x8 u0, v0, u1, v1; v_int32x4 xy0 = v_dotprod( _xy0, xy2ofs ); v_store(iofs0, xy0); + int offset0 = FXY[x] * 16; int offset1 = FXY[x + 1] * 16; int offset2 = FXY[x + 2] * 16; @@ -640,15 +668,14 @@ struct RemapVec_8u #else -typedef RemapNoVec RemapVec_8u; +template using RemapVec_8u = RemapNoVec; #endif - -template +template static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, const Mat& _fxy, const void* _wtab, - int borderType, const Scalar& _borderValue ) + int borderType, const Scalar& _borderValue, const Point& _offset ) { typedef typename CastOp::rtype T; typedef typename CastOp::type1 WT; @@ -678,12 +705,12 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, const ushort* FXY = _fxy.ptr(dy); int X0 = 0; bool prevInlier = false; - + const int off_y = (isRelative ? (_offset.y+dy) : 0); for(int dx = 0; dx <= dsize.width; dx++ ) { bool curInlier = dx < dsize.width ? - (unsigned)XY[dx*2] < width1 && - (unsigned)XY[dx*2+1] < height1 : !prevInlier; + (unsigned)XY[dx*2]+(isRelative ? (_offset.x+dx) : 0) < width1 && + (unsigned)XY[dx*2+1]+off_y < height1 : !prevInlier; if( curInlier == prevInlier ) continue; @@ -694,7 +721,8 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, if( !curInlier ) { - int len = vecOp( _src, D, XY + dx*2, FXY + dx, wtab, X1 - dx ); + Point subOffset(_offset.x+dx, _offset.y+dy); + int len = vecOp( _src, D, XY + dx*2, FXY + dx, wtab, X1 - dx, subOffset ); D += len*cn; dx += len; @@ -702,7 +730,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, { for( ; dx < X1; dx++, D++ ) { - int sx = XY[dx*2], sy = XY[dx*2+1]; + int sx = XY[dx*2]+(isRelative ? (_offset.x+dx) : 0), sy = XY[dx*2+1]+off_y; const AT* w = wtab + FXY[dx]*4; const T* S = S0 + sy*sstep + sx; *D = castOp(WT(S[0]*w[0] + S[1]*w[1] + S[sstep]*w[2] + S[sstep+1]*w[3])); @@ -711,7 +739,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, else if( cn == 2 ) for( ; dx < X1; dx++, D += 2 ) { - int sx = XY[dx*2], sy = XY[dx*2+1]; + int sx = XY[dx*2]+(isRelative ? (_offset.x+dx) : 0), sy = XY[dx*2+1]+off_y; const AT* w = wtab + FXY[dx]*4; const T* S = S0 + sy*sstep + sx*2; WT t0 = S[0]*w[0] + S[2]*w[1] + S[sstep]*w[2] + S[sstep+2]*w[3]; @@ -721,7 +749,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, else if( cn == 3 ) for( ; dx < X1; dx++, D += 3 ) { - int sx = XY[dx*2], sy = XY[dx*2+1]; + int sx = XY[dx*2]+(isRelative ? (_offset.x+dx) : 0), sy = XY[dx*2+1]+off_y; const AT* w = wtab + FXY[dx]*4; const T* S = S0 + sy*sstep + sx*3; WT t0 = S[0]*w[0] + S[3]*w[1] + S[sstep]*w[2] + S[sstep+3]*w[3]; @@ -732,7 +760,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, else if( cn == 4 ) for( ; dx < X1; dx++, D += 4 ) { - int sx = XY[dx*2], sy = XY[dx*2+1]; + int sx = XY[dx*2]+(isRelative ? (_offset.x+dx) : 0), sy = XY[dx*2+1]+off_y; const AT* w = wtab + FXY[dx]*4; const T* S = S0 + sy*sstep + sx*4; WT t0 = S[0]*w[0] + S[4]*w[1] + S[sstep]*w[2] + S[sstep+4]*w[3]; @@ -745,7 +773,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, else for( ; dx < X1; dx++, D += cn ) { - int sx = XY[dx*2], sy = XY[dx*2+1]; + int sx = XY[dx*2]+(isRelative ? (_offset.x+dx) : 0), sy = XY[dx*2+1]+off_y; const AT* w = wtab + FXY[dx]*4; const T* S = S0 + sy*sstep + sx*cn; for(int k = 0; k < cn; k++ ) @@ -760,7 +788,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, if (borderType == BORDER_TRANSPARENT) { for (; dx < X1; dx++, D += cn) { if (dx >= dsize.width) continue; - const int sx = XY[dx * 2], sy = XY[dx * 2 + 1]; + const int sx = XY[dx * 2]+(isRelative ? (_offset.x+dx) : 0), sy = XY[dx * 2 + 1]+off_y; // If the mapped point is still within bounds, it did not get computed // because it lacked 4 neighbors. Still, it can be computed with an // approximate formula. If it is outside, the point is left untouched. @@ -791,7 +819,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, if( cn == 1 ) for( ; dx < X1; dx++, D++ ) { - int sx = XY[dx*2], sy = XY[dx*2+1]; + int sx = XY[dx*2]+(isRelative ? (_offset.x+dx) : 0), sy = XY[dx*2+1]+off_y; if( borderType == BORDER_CONSTANT && (sx >= ssize.width || sx+1 < 0 || sy >= ssize.height || sy+1 < 0) ) @@ -831,7 +859,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, else for( ; dx < X1; dx++, D += cn ) { - int sx = XY[dx*2], sy = XY[dx*2+1]; + int sx = XY[dx*2]+(isRelative ? (_offset.x+dx) : 0), sy = XY[dx*2+1]+off_y; if( borderType == BORDER_CONSTANT && (sx >= ssize.width || sx+1 < 0 || sy >= ssize.height || sy+1 < 0) ) @@ -876,10 +904,10 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, } -template +template static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, const Mat& _fxy, const void* _wtab, - int borderType, const Scalar& _borderValue ) + int borderType, const Scalar& _borderValue, const Point& _offset ) { typedef typename CastOp::rtype T; typedef typename CastOp::type1 WT; @@ -898,7 +926,7 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, unsigned width1 = std::max(ssize.width-3, 0), height1 = std::max(ssize.height-3, 0); - if( _dst.isContinuous() && _xy.isContinuous() && _fxy.isContinuous() ) + if( _dst.isContinuous() && _xy.isContinuous() && _fxy.isContinuous() && !isRelative ) { dsize.width *= dsize.height; dsize.height = 1; @@ -909,10 +937,11 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, T* D = _dst.ptr(dy); const short* XY = _xy.ptr(dy); const ushort* FXY = _fxy.ptr(dy); - + const int off_y = isRelative ? (_offset.y+dy) : 0; for(int dx = 0; dx < dsize.width; dx++, D += cn ) { - int sx = XY[dx*2]-1, sy = XY[dx*2+1]-1; + const int off_x = isRelative ? (_offset.x+dx) : 0; + int sx = XY[dx*2]-1+off_x, sy = XY[dx*2+1]-1+off_y; const AT* w = wtab + FXY[dx]*16; if( (unsigned)sx < width1 && (unsigned)sy < height1 ) { @@ -980,10 +1009,10 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, } -template +template static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, const Mat& _fxy, const void* _wtab, - int borderType, const Scalar& _borderValue ) + int borderType, const Scalar& _borderValue, const Point& _offset ) { typedef typename CastOp::rtype T; typedef typename CastOp::type1 WT; @@ -1002,7 +1031,7 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, unsigned width1 = std::max(ssize.width-7, 0), height1 = std::max(ssize.height-7, 0); - if( _dst.isContinuous() && _xy.isContinuous() && _fxy.isContinuous() ) + if( _dst.isContinuous() && _xy.isContinuous() && _fxy.isContinuous() && !isRelative ) { dsize.width *= dsize.height; dsize.height = 1; @@ -1013,10 +1042,11 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, T* D = _dst.ptr(dy); const short* XY = _xy.ptr(dy); const ushort* FXY = _fxy.ptr(dy); - + const int off_y = isRelative ? (_offset.y+dy) : 0; for(int dx = 0; dx < dsize.width; dx++, D += cn ) { - int sx = XY[dx*2]-3, sy = XY[dx*2+1]-3; + const int off_x = isRelative ? (_offset.x+dx) : 0; + int sx = XY[dx*2]-3+off_x, sy = XY[dx*2+1]-3+off_y; const AT* w = wtab + FXY[dx]*64; const T* S = S0 + sy*sstep + sx*cn; if( (unsigned)sx < width1 && (unsigned)sy < height1 ) @@ -1091,11 +1121,11 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, typedef void (*RemapNNFunc)(const Mat& _src, Mat& _dst, const Mat& _xy, - int borderType, const Scalar& _borderValue ); + int borderType, const Scalar& _borderValue, const Point& _offset); typedef void (*RemapFunc)(const Mat& _src, Mat& _dst, const Mat& _xy, const Mat& _fxy, const void* _wtab, - int borderType, const Scalar& _borderValue); + int borderType, const Scalar& _borderValue, const Point& _offset); class RemapInvoker : public ParallelLoopBody @@ -1186,7 +1216,7 @@ public: } } } - nnfunc( *src, dpart, bufxy, borderType, borderValue ); + nnfunc( *src, dpart, bufxy, borderType, borderValue, Point(x, y) ); continue; } @@ -1293,7 +1323,7 @@ public: } } } - ifunc(*src, dpart, bufxy, bufa, ctab, borderType, borderValue); + ifunc(*src, dpart, bufxy, bufa, ctab, borderType, borderValue, Point(x, y)); } } } @@ -1315,6 +1345,9 @@ private: static bool ocl_remap(InputArray _src, OutputArray _dst, InputArray _map1, InputArray _map2, int interpolation, int borderType, const Scalar& borderValue) { + const bool hasRelativeFlag = ((interpolation & cv::WARP_RELATIVE_MAP) != 0); + interpolation &= ~cv::WARP_RELATIVE_MAP; + const ocl::Device & dev = ocl::Device::getDefault(); int cn = _src.channels(), type = _src.type(), depth = _src.depth(), rowsPerWI = dev.isIntel() ? 4 : 1; @@ -1354,9 +1387,10 @@ static bool ocl_remap(InputArray _src, OutputArray _dst, InputArray _map1, Input static const char * const interMap[] = { "INTER_NEAREST", "INTER_LINEAR", "INTER_CUBIC", "INTER_LINEAR", "INTER_LANCZOS" }; static const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT", "BORDER_WRAP", "BORDER_REFLECT_101", "BORDER_TRANSPARENT" }; - String buildOptions = format("-D %s -D %s -D T=%s -D ROWS_PER_WI=%d", + String buildOptions = format("-D %s -D %s -D T=%s -D ROWS_PER_WI=%d -D WARP_RELATIVE=%d", interMap[interpolation], borderMap[borderType], - ocl::typeToStr(type), rowsPerWI); + ocl::typeToStr(type), rowsPerWI, + hasRelativeFlag ? 1 : 0); if (interpolation != INTER_NEAREST) { @@ -1687,38 +1721,73 @@ void cv::remap( InputArray _src, OutputArray _dst, { CV_INSTRUMENT_REGION(); - static RemapNNFunc nn_tab[CV_DEPTH_MAX] = + const bool hasRelativeFlag = ((interpolation & cv::WARP_RELATIVE_MAP) != 0); + + static RemapNNFunc nn_tab[2][CV_DEPTH_MAX] = { - remapNearest, remapNearest, remapNearest, remapNearest, - remapNearest, remapNearest, remapNearest, 0 + { + remapNearest, remapNearest, remapNearest, remapNearest, + remapNearest, remapNearest, remapNearest, 0 + }, + { + remapNearest, remapNearest, remapNearest, remapNearest, + remapNearest, remapNearest, remapNearest, 0 + } }; - static RemapFunc linear_tab[CV_DEPTH_MAX] = + static RemapFunc linear_tab[2][CV_DEPTH_MAX] = { - remapBilinear, RemapVec_8u, short>, 0, - remapBilinear, RemapNoVec, float>, - remapBilinear, RemapNoVec, float>, 0, - remapBilinear, RemapNoVec, float>, - remapBilinear, RemapNoVec, float>, 0 + { + remapBilinear, RemapVec_8u, short, false>, 0, + remapBilinear, RemapNoVec, float, false>, + remapBilinear, RemapNoVec, float, false>, 0, + remapBilinear, RemapNoVec, float, false>, + remapBilinear, RemapNoVec, float, false>, 0 + }, + { + remapBilinear, RemapVec_8u, short, true>, 0, + remapBilinear, RemapNoVec, float, true>, + remapBilinear, RemapNoVec, float, true>, 0, + remapBilinear, RemapNoVec, float, true>, + remapBilinear, RemapNoVec, float, true>, 0 + } }; - static RemapFunc cubic_tab[CV_DEPTH_MAX] = + static RemapFunc cubic_tab[2][CV_DEPTH_MAX] = { - remapBicubic, short, INTER_REMAP_COEF_SCALE>, 0, - remapBicubic, float, 1>, - remapBicubic, float, 1>, 0, - remapBicubic, float, 1>, - remapBicubic, float, 1>, 0 - }; + { + remapBicubic, short, INTER_REMAP_COEF_SCALE, false>, 0, + remapBicubic, float, 1, false>, + remapBicubic, float, 1, false>, 0, + remapBicubic, float, 1, false>, + remapBicubic, float, 1, false>, 0 + }, + { + remapBicubic, short, INTER_REMAP_COEF_SCALE, true>, 0, + remapBicubic, float, 1, true>, + remapBicubic, float, 1, true>, 0, + remapBicubic, float, 1, true>, + remapBicubic, float, 1, true>, 0 + } +}; - static RemapFunc lanczos4_tab[CV_DEPTH_MAX] = + static RemapFunc lanczos4_tab[2][8] = { - remapLanczos4, short, INTER_REMAP_COEF_SCALE>, 0, - remapLanczos4, float, 1>, - remapLanczos4, float, 1>, 0, - remapLanczos4, float, 1>, - remapLanczos4, float, 1>, 0 - }; + { + remapLanczos4, short, INTER_REMAP_COEF_SCALE, false>, 0, + remapLanczos4, float, 1, false>, + remapLanczos4, float, 1, false>, 0, + remapLanczos4, float, 1, false>, + remapLanczos4, float, 1, false>, 0 + }, + { + remapLanczos4, short, INTER_REMAP_COEF_SCALE, true>, 0, + remapLanczos4, float, 1, true>, + remapLanczos4, float, 1, true>, 0, + remapLanczos4, float, 1, true>, + remapLanczos4, float, 1, true>, 0 + } +}; CV_Assert( !_map1.empty() ); CV_Assert( _map2.empty() || (_map2.size() == _map1.size())); @@ -1738,7 +1807,8 @@ void cv::remap( InputArray _src, OutputArray _dst, ((map1.type() == CV_32FC2 && map2.empty() && map1.size == dst.size) || (map1.type() == CV_32FC1 && map2.type() == CV_32FC1 && map1.size == dst.size && map2.size == dst.size) || (map1.empty() && map2.type() == CV_32FC2 && map2.size == dst.size)) && - ((borderType & BORDER_ISOLATED) != 0 || !src.isSubmatrix()), + ((borderType & BORDER_ISOLATED) != 0 || !src.isSubmatrix()) && + !hasRelativeFlag, openvx_remap(src, dst, map1, map2, interpolation, borderValue)); CV_Assert( dst.cols < SHRT_MAX && dst.rows < SHRT_MAX && src.cols < SHRT_MAX && src.rows < SHRT_MAX ); @@ -1746,6 +1816,7 @@ void cv::remap( InputArray _src, OutputArray _dst, if( dst.data == src.data ) src = src.clone(); + interpolation &= ~cv::WARP_RELATIVE_MAP; if( interpolation == INTER_AREA ) interpolation = INTER_LINEAR; @@ -1798,21 +1869,22 @@ void cv::remap( InputArray _src, OutputArray _dst, bool fixpt = depth == CV_8U; bool planar_input = false; + const int relativeOptionIndex = (hasRelativeFlag ? 1 : 0); if( interpolation == INTER_NEAREST ) { - nnfunc = nn_tab[depth]; + nnfunc = nn_tab[relativeOptionIndex][depth]; CV_Assert( nnfunc != 0 ); } else { if( interpolation == INTER_LINEAR ) - ifunc = linear_tab[depth]; + ifunc = linear_tab[relativeOptionIndex][depth]; else if( interpolation == INTER_CUBIC ){ - ifunc = cubic_tab[depth]; + ifunc = cubic_tab[relativeOptionIndex][depth]; CV_Assert( _src.channels() <= 4 ); } else if( interpolation == INTER_LANCZOS4 ){ - ifunc = lanczos4_tab[depth]; + ifunc = lanczos4_tab[relativeOptionIndex][depth]; CV_Assert( _src.channels() <= 4 ); } else diff --git a/modules/imgproc/src/opencl/remap.cl b/modules/imgproc/src/opencl/remap.cl index 8c8b933ab5..9aadde0215 100644 --- a/modules/imgproc/src/opencl/remap.cl +++ b/modules/imgproc/src/opencl/remap.cl @@ -168,6 +168,10 @@ __kernel void remap_2_32FC1(__global const uchar * srcptr, int src_step, int src int gx = convert_int_sat_rte(map1[0]); int gy = convert_int_sat_rte(map2[0]); + #if WARP_RELATIVE + gx += x; + gy += y; + #endif if (NEED_EXTRAPOLATION(gx, gy)) { @@ -210,6 +214,11 @@ __kernel void remap_32FC2(__global const uchar * srcptr, int src_step, int src_o __global T * dst = (__global T *)(dstptr + dst_index); int2 gxy = convert_int2_sat_rte(map[0]); + #if WARP_RELATIVE + gxy.x += x; + gxy.y += y; + #endif + int gx = gxy.x, gy = gxy.y; if (NEED_EXTRAPOLATION(gx, gy)) @@ -250,6 +259,11 @@ __kernel void remap_16SC2(__global const uchar * srcptr, int src_step, int src_o __global T * dst = (__global T *)(dstptr + dst_index); int2 gxy = convert_int2(map[0]); + #if WARP_RELATIVE + gxy.x += x; + gxy.y += y; + #endif + int gx = gxy.x, gy = gxy.y; if (NEED_EXTRAPOLATION(gx, gy)) @@ -296,6 +310,11 @@ __kernel void remap_16SC2_16UC1(__global const uchar * srcptr, int src_step, int int dx = (map2Value & (INTER_TAB_SIZE - 1)) < (INTER_TAB_SIZE >> 1) ? 1 : 0; int dy = (map2Value >> INTER_BITS) < (INTER_TAB_SIZE >> 1) ? 1 : 0; int2 gxy = convert_int2(map1[0]) + (int2)(dx, dy); + #if WARP_RELATIVE + gxy.x += x; + gxy.y += y; + #endif + int gx = gxy.x, gy = gxy.y; if (NEED_EXTRAPOLATION(gx, gy)) @@ -349,6 +368,10 @@ __kernel void remap_16SC2_16UC1(__global const uchar * srcptr, int src_step, int __global T * dst = (__global T *)(dstptr + dst_index); int2 map_dataA = convert_int2(map1[0]); + #if WARP_RELATIVE + map_dataA.x += x; + map_dataA.y += y; + #endif int2 map_dataB = (int2)(map_dataA.x + 1, map_dataA.y); int2 map_dataC = (int2)(map_dataA.x, map_dataA.y + 1); int2 map_dataD = (int2)(map_dataA.x + 1, map_dataA.y + 1); @@ -414,8 +437,12 @@ __kernel void remap_2_32FC1(__global const uchar * srcptr, int src_step, int src #if defined BORDER_CONSTANT float xf = map1[0], yf = map2[0]; - int sx = convert_int_sat_rtz(mad(xf, (float)INTER_TAB_SIZE, 0.5f)) >> INTER_BITS; - int sy = convert_int_sat_rtz(mad(yf, (float)INTER_TAB_SIZE, 0.5f)) >> INTER_BITS; + int sx = (convert_int_sat_rtz(mad(xf, (float)INTER_TAB_SIZE, 0.5f)) >> INTER_BITS); + int sy = (convert_int_sat_rtz(mad(yf, (float)INTER_TAB_SIZE, 0.5f)) >> INTER_BITS); + #if WARP_RELATIVE + sx += x; + sy += y; + #endif __constant float * coeffs_x = coeffs + ((convert_int_rte(xf * INTER_TAB_SIZE) & (INTER_TAB_SIZE - 1)) << 1); __constant float * coeffs_y = coeffs + ((convert_int_rte(yf * INTER_TAB_SIZE) & (INTER_TAB_SIZE - 1)) << 1); @@ -456,6 +483,10 @@ __kernel void remap_2_32FC1(__global const uchar * srcptr, int src_step, int src storepix(CONVERT_TO_T(sum), dst); #else float2 map_data = (float2)(map1[0], map2[0]); + #if WARP_RELATIVE + map_data.x += x; + map_data.y += y; + #endif int2 map_dataA = convert_int2_sat_rtn(map_data); int2 map_dataB = (int2)(map_dataA.x + 1, map_dataA.y); @@ -520,6 +551,10 @@ __kernel void remap_32FC2(__global const uchar * srcptr, int src_step, int src_o __global T * dst = (__global T *)(dstptr + dst_index); float2 map_data = map[0]; + #if WARP_RELATIVE + map_data.x += x; + map_data.y += y; + #endif int2 map_dataA = convert_int2_sat_rtn(map_data); int2 map_dataB = (int2)(map_dataA.x + 1, map_dataA.y); int2 map_dataC = (int2)(map_dataA.x, map_dataA.y + 1); diff --git a/modules/imgproc/test/ocl/test_warp.cpp b/modules/imgproc/test/ocl/test_warp.cpp index b43c9b6732..852dc465ab 100644 --- a/modules/imgproc/test/ocl/test_warp.cpp +++ b/modules/imgproc/test/ocl/test_warp.cpp @@ -438,6 +438,101 @@ OCL_TEST_P(Remap_INTER_LINEAR, Mat) } } +///////////////////////////////////////////////////////////////////////////////////////////////// +// remap relative + +PARAM_TEST_CASE(RemapRelative, MatDepth, Channels, Interpolation, BorderType, bool) +{ + int srcType; + int interpolation; + int borderType; + bool useFixedPoint; + + Scalar val; + + TEST_DECLARE_INPUT_PARAMETER(map1); + TEST_DECLARE_INPUT_PARAMETER(map2); + TEST_DECLARE_OUTPUT_PARAMETER(dst); + + UMat uSrc; + UMat uMapRelativeX32F; + UMat uMapRelativeY32F; + UMat uMapAbsoluteX32F; + UMat uMapAbsoluteY32F; + UMat uMapRelativeX16S; + UMat uMapRelativeY16S; + UMat uMapAbsoluteX16S; + UMat uMapAbsoluteY16S; + + virtual void SetUp() + { + srcType = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1)); + interpolation = GET_PARAM(2); + borderType = GET_PARAM(3); + useFixedPoint = GET_PARAM(4); + + const int nChannels = CV_MAT_CN(srcType); + const cv::Size size(127, 61); + cv::Mat data64FC1(1, size.area()*nChannels, CV_64FC1); + data64FC1.forEach([&](double& pixel, const int* position) {pixel = static_cast(position[1]);}); + + cv::Mat src; + data64FC1.reshape(nChannels, size.height).convertTo(src, srcType); + + cv::Mat mapRelativeX32F(size, CV_32FC1); + mapRelativeX32F.setTo(cv::Scalar::all(-0.33)); + + cv::Mat mapRelativeY32F(size, CV_32FC1); + mapRelativeY32F.setTo(cv::Scalar::all(-0.33)); + + cv::Mat mapAbsoluteX32F = mapRelativeX32F.clone(); + mapAbsoluteX32F.forEach([&](float& pixel, const int* position) { + pixel += static_cast(position[1]); + }); + + cv::Mat mapAbsoluteY32F = mapRelativeY32F.clone(); + mapAbsoluteY32F.forEach([&](float& pixel, const int* position) { + pixel += static_cast(position[0]); + }); + + OCL_ON(src.copyTo(uSrc)); + OCL_ON(mapRelativeX32F.copyTo(uMapRelativeX32F)); + OCL_ON(mapRelativeY32F.copyTo(uMapRelativeY32F)); + OCL_ON(mapAbsoluteX32F.copyTo(uMapAbsoluteX32F)); + OCL_ON(mapAbsoluteY32F.copyTo(uMapAbsoluteY32F)); + + if (useFixedPoint) + { + const bool nninterpolation = (interpolation == cv::INTER_NEAREST) || (interpolation == cv::INTER_NEAREST_EXACT); + OCL_ON(cv::convertMaps(uMapAbsoluteX32F, uMapAbsoluteY32F, uMapAbsoluteX16S, uMapAbsoluteY16S, CV_16SC2, nninterpolation)); + OCL_ON(cv::convertMaps(uMapRelativeX32F, uMapRelativeY32F, uMapRelativeX16S, uMapRelativeY16S, CV_16SC2, nninterpolation)); + } + } +}; + +OCL_TEST_P(RemapRelative, Mat) +{ + cv::UMat uDstAbsolute; + cv::UMat uDstRelative; + if (useFixedPoint) + { + OCL_ON(cv::remap(uSrc, uDstAbsolute, uMapAbsoluteX16S, uMapAbsoluteY16S, interpolation, borderType)); + OCL_ON(cv::remap(uSrc, uDstRelative, uMapRelativeX16S, uMapRelativeY16S, interpolation | WARP_RELATIVE_MAP, borderType)); + } + else + { + OCL_ON(cv::remap(uSrc, uDstAbsolute, uMapAbsoluteX32F, uMapAbsoluteY32F, interpolation, borderType)); + OCL_ON(cv::remap(uSrc, uDstRelative, uMapRelativeX32F, uMapRelativeY32F, interpolation | WARP_RELATIVE_MAP, borderType)); + } + + cv::Mat dstAbsolute; + OCL_ON(uDstAbsolute.copyTo(dstAbsolute)); + cv::Mat dstRelative; + OCL_ON(uDstRelative.copyTo(dstRelative)); + + EXPECT_MAT_NEAR(dstAbsolute, dstRelative, dstAbsolute.depth() == CV_32F ? 1e-3 : 1.0); +} + ///////////////////////////////////////////////////////////////////////////////////// OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpAffine, Combine( @@ -515,6 +610,20 @@ OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, Remap_INTER_NEAREST, Combine( (BorderType)BORDER_REFLECT_101), Bool())); +OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, RemapRelative, Combine( + Values(CV_8U, CV_16U, CV_32F, CV_64F), + Values(1, 3, 4), + Values((Interpolation)INTER_NEAREST, + (Interpolation)INTER_LINEAR, + (Interpolation)INTER_CUBIC, + (Interpolation)INTER_LANCZOS4), + Values((BorderType)BORDER_CONSTANT, + (BorderType)BORDER_REPLICATE, + (BorderType)BORDER_WRAP, + (BorderType)BORDER_REFLECT, + (BorderType)BORDER_REFLECT_101), + Bool())); + } } // namespace opencv_test::ocl #endif // HAVE_OPENCL diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp index 2d6796bc75..ce7741e1db 100644 --- a/modules/imgproc/test/test_imgwarp.cpp +++ b/modules/imgproc/test/test_imgwarp.cpp @@ -751,6 +751,73 @@ TEST(Imgproc_resize_area, regression_quarter_round) check_resize_area(expected, actual, 0.5); } +typedef tuple RemapRelativeParam; +typedef testing::TestWithParam Imgproc_RemapRelative; + +TEST_P(Imgproc_RemapRelative, validity) +{ + int srcType = CV_MAKE_TYPE(get<0>(GetParam()), get<1>(GetParam())); + int interpolation = get<2>(GetParam()); + int borderType = get<3>(GetParam()); + bool useFixedPoint = get<4>(GetParam()); + + const int nChannels = CV_MAT_CN(srcType); + const cv::Size size(127, 61); + cv::Mat data64FC1(1, size.area()*nChannels, CV_64FC1); + data64FC1.forEach([&](double& pixel, const int* position) {pixel = static_cast(position[1]);}); + + cv::Mat src; + data64FC1.reshape(nChannels, size.height).convertTo(src, srcType); + + cv::Mat mapRelativeX32F(size, CV_32FC1); + mapRelativeX32F.setTo(cv::Scalar::all(-0.33)); + + cv::Mat mapRelativeY32F(size, CV_32FC1); + mapRelativeY32F.setTo(cv::Scalar::all(-0.33)); + + cv::Mat mapAbsoluteX32F = mapRelativeX32F.clone(); + mapAbsoluteX32F.forEach([&](float& pixel, const int* position) { + pixel += static_cast(position[1]); + }); + + cv::Mat mapAbsoluteY32F = mapRelativeY32F.clone(); + mapAbsoluteY32F.forEach([&](float& pixel, const int* position) { + pixel += static_cast(position[0]); + }); + + cv::Mat mapAbsoluteX16S; + cv::Mat mapAbsoluteY16S; + cv::Mat mapRelativeX16S; + cv::Mat mapRelativeY16S; + if (useFixedPoint) + { + const bool nninterpolation = (interpolation == cv::INTER_NEAREST) || (interpolation == cv::INTER_NEAREST_EXACT); + cv::convertMaps(mapAbsoluteX32F, mapAbsoluteY32F, mapAbsoluteX16S, mapAbsoluteY16S, CV_16SC2, nninterpolation); + cv::convertMaps(mapRelativeX32F, mapRelativeY32F, mapRelativeX16S, mapRelativeY16S, CV_16SC2, nninterpolation); + } + + cv::Mat dstAbsolute; + cv::Mat dstRelative; + if (useFixedPoint) + { + cv::remap(src, dstAbsolute, mapAbsoluteX16S, mapAbsoluteY16S, interpolation, borderType); + cv::remap(src, dstRelative, mapRelativeX16S, mapRelativeY16S, interpolation | WARP_RELATIVE_MAP, borderType); + } + else + { + cv::remap(src, dstAbsolute, mapAbsoluteX32F, mapAbsoluteY32F, interpolation, borderType); + cv::remap(src, dstRelative, mapRelativeX32F, mapRelativeY32F, interpolation | WARP_RELATIVE_MAP, borderType); + } + + EXPECT_EQ(cvtest::norm(dstAbsolute, dstRelative, NORM_INF), 0); +}; + +INSTANTIATE_TEST_CASE_P(ImgProc, Imgproc_RemapRelative, testing::Combine( + testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), + testing::Values(1, 3, 4), + testing::Values((int)INTER_NEAREST, (int)INTER_LINEAR, (int)INTER_CUBIC, (int)INTER_LANCZOS4), + testing::Values((int)BORDER_CONSTANT, (int)BORDER_REPLICATE, (int)BORDER_WRAP, (int)BORDER_REFLECT, (int)BORDER_REFLECT_101), + testing::Values(false, true))); ////////////////////////////////////////////////////////////////////////// diff --git a/modules/objdetect/src/face_detect.cpp b/modules/objdetect/src/face_detect.cpp index bff7e0b13e..441c55e788 100644 --- a/modules/objdetect/src/face_detect.cpp +++ b/modules/objdetect/src/face_detect.cpp @@ -200,6 +200,9 @@ private: float score = std::sqrt(cls_score * obj_score); face.at(0, 14) = score; + // Checking if the score meets the threshold before adding the face + if (score < scoreThreshold) + continue; // Get bounding box float cx = ((c + bbox_v[idx * 4 + 0]) * strides[i]); float cy = ((r + bbox_v[idx * 4 + 1]) * strides[i]); diff --git a/samples/dnn/models.yml b/samples/dnn/models.yml index 23c265112d..a8d83f76a3 100644 --- a/samples/dnn/models.yml +++ b/samples/dnn/models.yml @@ -18,6 +18,22 @@ opencv_fd: rgb: false sample: "object_detection" +# YOLOv8 object detection family from ultralytics (https://github.com/ultralytics/ultralytics) +# Might be used for all YOLOv8n YOLOv8s YOLOv8m YOLOv8l and YOLOv8x +yolov8x: + load_info: + url: "https://huggingface.co/cabelo/yolov8/resolve/main/yolov8x.onnx?download=true" + sha1: "462f15d668c046d38e27d3df01fe8142dd004cb4" + model: "yolov8x.onnx" + mean: 0.0 + scale: 0.00392 + width: 640 + height: 640 + rgb: true + classes: "object_detection_classes_yolo.txt" + background_label_id: 0 + sample: "yolo_detector" + # YOLO4 object detection family from Darknet (https://github.com/AlexeyAB/darknet) # YOLO object detection family from Darknet (https://pjreddie.com/darknet/yolo/) # Might be used for all YOLOv2, TinyYolov2, YOLOv3, YOLOv4 and TinyYolov4