diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index 268555bada..e5d9b0defb 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -757,6 +757,37 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, } else { + 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]; + // 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. + if (sx >= 0 && sx <= ssize.width - 1 && sy >= 0 && sy <= ssize.height - 1) { + const AT* w = wtab + FXY[dx] * 4; + WT w_tot = 0; + if (sx >= 0 && sy >= 0) w_tot += w[0]; + if (sy >= 0 && sx < ssize.width - 1) w_tot += w[1]; + if (sx >= 0 && sy < ssize.height - 1) w_tot += w[2]; + if (sx < ssize.width - 1 && sy < ssize.height - 1) w_tot += w[3]; + if (w_tot == 0.f) continue; + const WT w_tot_ini = (WT)w[0] + w[1] + w[2] + w[3]; + const T* S = S0 + sy * sstep + sx * cn; + for (int k = 0; k < cn; k++) { + WT t0 = 0; + if (sx >= 0 && sy >= 0) t0 += S[k] * w[0]; + if (sy >= 0 && sx < ssize.width - 1) t0 += S[k + cn] * w[1]; + if (sx >= 0 && sy < ssize.height - 1) t0 += S[sstep + k] * w[2]; + if (sx < ssize.width - 1 && sy < ssize.height - 1) t0 += S[sstep + k + cn] * w[3]; + t0 = (WT)(t0 * (float)w_tot_ini / w_tot); + D[k] = castOp(t0); + } + } + } + continue; + } + if( cn == 1 ) for( ; dx < X1; dx++, D++ ) { @@ -767,12 +798,6 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, { D[0] = cval[0]; } - else if (borderType == BORDER_TRANSPARENT) - { - if (sx < ssize.width && sx >= 0 && - sy < ssize.height && sy >= 0) - D[0] = S0[sy*sstep + sx]; - } else { int sx0, sx1, sy0, sy1; @@ -814,13 +839,6 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, for(int k = 0; k < cn; k++ ) D[k] = cval[k]; } - else if (borderType == BORDER_TRANSPARENT) - { - if (sx < ssize.width && sx >= 0 && - sy < ssize.height && sy >= 0) - for(int k = 0; k < cn; k++ ) - D[k] = S0[sy*sstep + sx*cn + k]; - } else { int sx0, sx1, sy0, sy1; @@ -837,10 +855,6 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, v2 = S0 + sy1*sstep + sx0*cn; v3 = S0 + sy1*sstep + sx1*cn; } - else if( borderType == BORDER_TRANSPARENT && - ((unsigned)sx >= (unsigned)(ssize.width-1) || - (unsigned)sy >= (unsigned)(ssize.height-1))) - continue; else { sx0 = borderInterpolate(sx, ssize.width, borderType); diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp index 68208caa04..4ba2ab80b4 100644 --- a/modules/imgproc/test/test_imgwarp.cpp +++ b/modules/imgproc/test/test_imgwarp.cpp @@ -1672,6 +1672,28 @@ TEST(Imgproc_Remap, issue_23562) remap(src, dst, mapx, mapy, INTER_LINEAR, BORDER_TRANSPARENT); ASSERT_EQ(0.0, cvtest::norm(ref, dst, NORM_INF)) << "channels=" << cn; } + + mapx = Mat1f({3, 3}, {0, 1, 2, 0, 1, 2, 0, 1, 2}); + mapy = Mat1f({3, 3}, {0, 0, 0, 1, 1, 1, 2, 2, 1.5}); + for (int cn = 1; cn <= 4; ++cn) { + Mat src = cv::Mat(3, 3, CV_32FC(cn)); + Mat dst = 10 * Mat::ones(3, 3, CV_32FC(cn)); + for(int y = 0; y < 3; ++y) { + for(int x = 0; x < 3; ++x) { + for(int k = 0; k < cn; ++k) { + src.ptr(y,x)[k] = 10.f * y + x; + } + } + } + + Mat ref = src.clone(); + for(int k = 0; k < cn; ++k) { + ref.ptr(2,2)[k] = (src.ptr(1, 2)[k] + src.ptr(2, 2)[k]) / 2.f; + } + + remap(src, dst, mapx, mapy, INTER_LINEAR, BORDER_TRANSPARENT); + ASSERT_EQ(0.0, cvtest::norm(ref, dst, NORM_INF)) << "channels=" << cn; + } } }} // namespace