Commit b3d128bb authored by Alexander Alekhin's avatar Alexander Alekhin

Merge pull request #8401 from avartenkov:multichannel_warp

parents 741e5139 3fbe1f8d
...@@ -3533,14 +3533,13 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -3533,14 +3533,13 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy,
int borderType, const Scalar& _borderValue ) int borderType, const Scalar& _borderValue )
{ {
Size ssize = _src.size(), dsize = _dst.size(); Size ssize = _src.size(), dsize = _dst.size();
int cn = _src.channels(); const int cn = _src.channels();
const T* S0 = _src.ptr<T>(); const T* S0 = _src.ptr<T>();
T cval[CV_CN_MAX];
size_t sstep = _src.step/sizeof(S0[0]); size_t sstep = _src.step/sizeof(S0[0]);
Scalar_<T> cval(saturate_cast<T>(_borderValue[0]),
saturate_cast<T>(_borderValue[1]), for(int k = 0; k < cn; k++ )
saturate_cast<T>(_borderValue[2]), cval[k] = saturate_cast<T>(_borderValue[k & 3]);
saturate_cast<T>(_borderValue[3]));
int dx, dy;
unsigned width1 = ssize.width, height1 = ssize.height; unsigned width1 = ssize.width, height1 = ssize.height;
...@@ -3550,14 +3549,14 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -3550,14 +3549,14 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy,
dsize.height = 1; dsize.height = 1;
} }
for( dy = 0; dy < dsize.height; dy++ ) for(int dy = 0; dy < dsize.height; dy++ )
{ {
T* D = _dst.ptr<T>(dy); T* D = _dst.ptr<T>(dy);
const short* XY = _xy.ptr<short>(dy); const short* XY = _xy.ptr<short>(dy);
if( cn == 1 ) if( cn == 1 )
{ {
for( dx = 0; dx < dsize.width; dx++ ) for(int dx = 0; dx < dsize.width; dx++ )
{ {
int sx = XY[dx*2], sy = XY[dx*2+1]; int sx = XY[dx*2], sy = XY[dx*2+1];
if( (unsigned)sx < width1 && (unsigned)sy < height1 ) if( (unsigned)sx < width1 && (unsigned)sy < height1 )
...@@ -3583,9 +3582,9 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -3583,9 +3582,9 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy,
} }
else else
{ {
for( dx = 0; dx < dsize.width; dx++, D += cn ) for(int dx = 0; dx < dsize.width; dx++, D += cn )
{ {
int sx = XY[dx*2], sy = XY[dx*2+1], k; int sx = XY[dx*2], sy = XY[dx*2+1];
const T *S; const T *S;
if( (unsigned)sx < width1 && (unsigned)sy < height1 ) if( (unsigned)sx < width1 && (unsigned)sy < height1 )
{ {
...@@ -3602,7 +3601,7 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -3602,7 +3601,7 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy,
else else
{ {
S = S0 + sy*sstep + sx*cn; S = S0 + sy*sstep + sx*cn;
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
D[k] = S[k]; D[k] = S[k];
} }
} }
...@@ -3622,7 +3621,7 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -3622,7 +3621,7 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy,
sy = borderInterpolate(sy, ssize.height, borderType); sy = borderInterpolate(sy, ssize.height, borderType);
S = S0 + sy*sstep + sx*cn; S = S0 + sy*sstep + sx*cn;
} }
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
D[k] = S[k]; D[k] = S[k];
} }
} }
...@@ -3852,16 +3851,15 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -3852,16 +3851,15 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy,
typedef typename CastOp::rtype T; typedef typename CastOp::rtype T;
typedef typename CastOp::type1 WT; typedef typename CastOp::type1 WT;
Size ssize = _src.size(), dsize = _dst.size(); Size ssize = _src.size(), dsize = _dst.size();
int k, cn = _src.channels(); const int cn = _src.channels();
const AT* wtab = (const AT*)_wtab; const AT* wtab = (const AT*)_wtab;
const T* S0 = _src.ptr<T>(); const T* S0 = _src.ptr<T>();
size_t sstep = _src.step/sizeof(S0[0]); size_t sstep = _src.step/sizeof(S0[0]);
T cval[CV_CN_MAX]; T cval[CV_CN_MAX];
int dx, dy;
CastOp castOp; CastOp castOp;
VecOp vecOp; VecOp vecOp;
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
cval[k] = saturate_cast<T>(_borderValue[k & 3]); cval[k] = saturate_cast<T>(_borderValue[k & 3]);
unsigned width1 = std::max(ssize.width-1, 0), height1 = std::max(ssize.height-1, 0); unsigned width1 = std::max(ssize.width-1, 0), height1 = std::max(ssize.height-1, 0);
...@@ -3871,7 +3869,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -3871,7 +3869,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy,
width1 = std::max(ssize.width-2, 0); width1 = std::max(ssize.width-2, 0);
#endif #endif
for( dy = 0; dy < dsize.height; dy++ ) for(int dy = 0; dy < dsize.height; dy++ )
{ {
T* D = _dst.ptr<T>(dy); T* D = _dst.ptr<T>(dy);
const short* XY = _xy.ptr<short>(dy); const short* XY = _xy.ptr<short>(dy);
...@@ -3879,7 +3877,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -3879,7 +3877,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy,
int X0 = 0; int X0 = 0;
bool prevInlier = false; bool prevInlier = false;
for( dx = 0; dx <= dsize.width; dx++ ) for(int dx = 0; dx <= dsize.width; dx++ )
{ {
bool curInlier = dx < dsize.width ? bool curInlier = dx < dsize.width ?
(unsigned)XY[dx*2] < width1 && (unsigned)XY[dx*2] < width1 &&
...@@ -3948,7 +3946,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -3948,7 +3946,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy,
int sx = XY[dx*2], sy = XY[dx*2+1]; int sx = XY[dx*2], sy = XY[dx*2+1];
const AT* w = wtab + FXY[dx]*4; const AT* w = wtab + FXY[dx]*4;
const T* S = S0 + sy*sstep + sx*cn; const T* S = S0 + sy*sstep + sx*cn;
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
{ {
WT t0 = S[k]*w[0] + S[k+cn]*w[1] + S[sstep+k]*w[2] + S[sstep+k+cn]*w[3]; WT t0 = S[k]*w[0] + S[k+cn]*w[1] + S[sstep+k]*w[2] + S[sstep+k+cn]*w[3];
D[k] = castOp(t0); D[k] = castOp(t0);
...@@ -4012,7 +4010,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -4012,7 +4010,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy,
(sx >= ssize.width || sx+1 < 0 || (sx >= ssize.width || sx+1 < 0 ||
sy >= ssize.height || sy+1 < 0) ) sy >= ssize.height || sy+1 < 0) )
{ {
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
D[k] = cval[k]; D[k] = cval[k];
} }
else else
...@@ -4046,7 +4044,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -4046,7 +4044,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy,
v2 = sx0 >= 0 && sy1 >= 0 ? S0 + sy1*sstep + sx0*cn : &cval[0]; v2 = sx0 >= 0 && sy1 >= 0 ? S0 + sy1*sstep + sx0*cn : &cval[0];
v3 = sx1 >= 0 && sy1 >= 0 ? S0 + sy1*sstep + sx1*cn : &cval[0]; v3 = sx1 >= 0 && sy1 >= 0 ? S0 + sy1*sstep + sx1*cn : &cval[0];
} }
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
D[k] = castOp(WT(v0[k]*w[0] + v1[k]*w[1] + v2[k]*w[2] + v3[k]*w[3])); D[k] = castOp(WT(v0[k]*w[0] + v1[k]*w[1] + v2[k]*w[2] + v3[k]*w[3]));
} }
} }
...@@ -4064,16 +4062,16 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -4064,16 +4062,16 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy,
typedef typename CastOp::rtype T; typedef typename CastOp::rtype T;
typedef typename CastOp::type1 WT; typedef typename CastOp::type1 WT;
Size ssize = _src.size(), dsize = _dst.size(); Size ssize = _src.size(), dsize = _dst.size();
int cn = _src.channels(); const int cn = _src.channels();
const AT* wtab = (const AT*)_wtab; const AT* wtab = (const AT*)_wtab;
const T* S0 = _src.ptr<T>(); const T* S0 = _src.ptr<T>();
size_t sstep = _src.step/sizeof(S0[0]); size_t sstep = _src.step/sizeof(S0[0]);
Scalar_<T> cval(saturate_cast<T>(_borderValue[0]), T cval[CV_CN_MAX];
saturate_cast<T>(_borderValue[1]),
saturate_cast<T>(_borderValue[2]),
saturate_cast<T>(_borderValue[3]));
int dx, dy;
CastOp castOp; CastOp castOp;
for(int k = 0; k < cn; k++ )
cval[k] = saturate_cast<T>(_borderValue[k & 3]);
int borderType1 = borderType != BORDER_TRANSPARENT ? borderType : BORDER_REFLECT_101; int borderType1 = borderType != BORDER_TRANSPARENT ? borderType : BORDER_REFLECT_101;
unsigned width1 = std::max(ssize.width-3, 0), height1 = std::max(ssize.height-3, 0); unsigned width1 = std::max(ssize.width-3, 0), height1 = std::max(ssize.height-3, 0);
...@@ -4084,21 +4082,20 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -4084,21 +4082,20 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy,
dsize.height = 1; dsize.height = 1;
} }
for( dy = 0; dy < dsize.height; dy++ ) for(int dy = 0; dy < dsize.height; dy++ )
{ {
T* D = _dst.ptr<T>(dy); T* D = _dst.ptr<T>(dy);
const short* XY = _xy.ptr<short>(dy); const short* XY = _xy.ptr<short>(dy);
const ushort* FXY = _fxy.ptr<ushort>(dy); const ushort* FXY = _fxy.ptr<ushort>(dy);
for( dx = 0; dx < dsize.width; dx++, D += cn ) for(int dx = 0; dx < dsize.width; dx++, D += cn )
{ {
int sx = XY[dx*2]-1, sy = XY[dx*2+1]-1; int sx = XY[dx*2]-1, sy = XY[dx*2+1]-1;
const AT* w = wtab + FXY[dx]*16; const AT* w = wtab + FXY[dx]*16;
int i, k;
if( (unsigned)sx < width1 && (unsigned)sy < height1 ) if( (unsigned)sx < width1 && (unsigned)sy < height1 )
{ {
const T* S = S0 + sy*sstep + sx*cn; const T* S = S0 + sy*sstep + sx*cn;
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
{ {
WT sum = S[0]*w[0] + S[cn]*w[1] + S[cn*2]*w[2] + S[cn*3]*w[3]; WT sum = S[0]*w[0] + S[cn]*w[1] + S[cn*2]*w[2] + S[cn*3]*w[3];
S += sstep; S += sstep;
...@@ -4123,21 +4120,21 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -4123,21 +4120,21 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy,
(sx >= ssize.width || sx+4 <= 0 || (sx >= ssize.width || sx+4 <= 0 ||
sy >= ssize.height || sy+4 <= 0)) sy >= ssize.height || sy+4 <= 0))
{ {
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
D[k] = cval[k]; D[k] = cval[k];
continue; continue;
} }
for( i = 0; i < 4; i++ ) for(int i = 0; i < 4; i++ )
{ {
x[i] = borderInterpolate(sx + i, ssize.width, borderType1)*cn; x[i] = borderInterpolate(sx + i, ssize.width, borderType1)*cn;
y[i] = borderInterpolate(sy + i, ssize.height, borderType1); y[i] = borderInterpolate(sy + i, ssize.height, borderType1);
} }
for( k = 0; k < cn; k++, S0++, w -= 16 ) for(int k = 0; k < cn; k++, S0++, w -= 16 )
{ {
WT cv = cval[k], sum = cv*ONE; WT cv = cval[k], sum = cv*ONE;
for( i = 0; i < 4; i++, w += 4 ) for(int i = 0; i < 4; i++, w += 4 )
{ {
int yi = y[i]; int yi = y[i];
const T* S = S0 + yi*sstep; const T* S = S0 + yi*sstep;
...@@ -4169,16 +4166,16 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -4169,16 +4166,16 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy,
typedef typename CastOp::rtype T; typedef typename CastOp::rtype T;
typedef typename CastOp::type1 WT; typedef typename CastOp::type1 WT;
Size ssize = _src.size(), dsize = _dst.size(); Size ssize = _src.size(), dsize = _dst.size();
int cn = _src.channels(); const int cn = _src.channels();
const AT* wtab = (const AT*)_wtab; const AT* wtab = (const AT*)_wtab;
const T* S0 = _src.ptr<T>(); const T* S0 = _src.ptr<T>();
size_t sstep = _src.step/sizeof(S0[0]); size_t sstep = _src.step/sizeof(S0[0]);
Scalar_<T> cval(saturate_cast<T>(_borderValue[0]), T cval[CV_CN_MAX];
saturate_cast<T>(_borderValue[1]),
saturate_cast<T>(_borderValue[2]),
saturate_cast<T>(_borderValue[3]));
int dx, dy;
CastOp castOp; CastOp castOp;
for(int k = 0; k < cn; k++ )
cval[k] = saturate_cast<T>(_borderValue[k & 3]);
int borderType1 = borderType != BORDER_TRANSPARENT ? borderType : BORDER_REFLECT_101; int borderType1 = borderType != BORDER_TRANSPARENT ? borderType : BORDER_REFLECT_101;
unsigned width1 = std::max(ssize.width-7, 0), height1 = std::max(ssize.height-7, 0); unsigned width1 = std::max(ssize.width-7, 0), height1 = std::max(ssize.height-7, 0);
...@@ -4189,21 +4186,20 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -4189,21 +4186,20 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy,
dsize.height = 1; dsize.height = 1;
} }
for( dy = 0; dy < dsize.height; dy++ ) for(int dy = 0; dy < dsize.height; dy++ )
{ {
T* D = _dst.ptr<T>(dy); T* D = _dst.ptr<T>(dy);
const short* XY = _xy.ptr<short>(dy); const short* XY = _xy.ptr<short>(dy);
const ushort* FXY = _fxy.ptr<ushort>(dy); const ushort* FXY = _fxy.ptr<ushort>(dy);
for( dx = 0; dx < dsize.width; dx++, D += cn ) for(int dx = 0; dx < dsize.width; dx++, D += cn )
{ {
int sx = XY[dx*2]-3, sy = XY[dx*2+1]-3; int sx = XY[dx*2]-3, sy = XY[dx*2+1]-3;
const AT* w = wtab + FXY[dx]*64; const AT* w = wtab + FXY[dx]*64;
const T* S = S0 + sy*sstep + sx*cn; const T* S = S0 + sy*sstep + sx*cn;
int i, k;
if( (unsigned)sx < width1 && (unsigned)sy < height1 ) if( (unsigned)sx < width1 && (unsigned)sy < height1 )
{ {
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
{ {
WT sum = 0; WT sum = 0;
for( int r = 0; r < 8; r++, S += sstep, w += 8 ) for( int r = 0; r < 8; r++, S += sstep, w += 8 )
...@@ -4226,21 +4222,21 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, ...@@ -4226,21 +4222,21 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy,
(sx >= ssize.width || sx+8 <= 0 || (sx >= ssize.width || sx+8 <= 0 ||
sy >= ssize.height || sy+8 <= 0)) sy >= ssize.height || sy+8 <= 0))
{ {
for( k = 0; k < cn; k++ ) for(int k = 0; k < cn; k++ )
D[k] = cval[k]; D[k] = cval[k];
continue; continue;
} }
for( i = 0; i < 8; i++ ) for(int i = 0; i < 8; i++ )
{ {
x[i] = borderInterpolate(sx + i, ssize.width, borderType1)*cn; x[i] = borderInterpolate(sx + i, ssize.width, borderType1)*cn;
y[i] = borderInterpolate(sy + i, ssize.height, borderType1); y[i] = borderInterpolate(sy + i, ssize.height, borderType1);
} }
for( k = 0; k < cn; k++, S0++, w -= 64 ) for(int k = 0; k < cn; k++, S0++, w -= 64 )
{ {
WT cv = cval[k], sum = cv*ONE; WT cv = cval[k], sum = cv*ONE;
for( i = 0; i < 8; i++, w += 8 ) for(int i = 0; i < 8; i++, w += 8 )
{ {
int yi = y[i]; int yi = y[i];
const T* S1 = S0 + yi*sstep; const T* S1 = S0 + yi*sstep;
......
...@@ -1686,22 +1686,33 @@ TEST(Resize, Area_half) ...@@ -1686,22 +1686,33 @@ TEST(Resize, Area_half)
TEST(Imgproc_Warp, multichannel) TEST(Imgproc_Warp, multichannel)
{ {
static const int inter_types[] = {INTER_NEAREST, INTER_AREA, INTER_CUBIC,
INTER_LANCZOS4, INTER_LINEAR};
static const int inter_n = sizeof(inter_types) / sizeof(int);
static const int border_types[] = {BORDER_CONSTANT, BORDER_DEFAULT,
BORDER_REFLECT, BORDER_REPLICATE,
BORDER_WRAP, BORDER_WRAP};
static const int border_n = sizeof(border_types) / sizeof(int);
RNG& rng = theRNG(); RNG& rng = theRNG();
for( int iter = 0; iter < 30; iter++ ) for( int iter = 0; iter < 100; iter++ )
{ {
int inter = inter_types[rng.uniform(0, inter_n)];
int border = border_types[rng.uniform(0, border_n)];
int width = rng.uniform(3, 333); int width = rng.uniform(3, 333);
int height = rng.uniform(3, 333); int height = rng.uniform(3, 333);
int cn = rng.uniform(1, 10); int cn = rng.uniform(1, 15);
Mat src(height, width, CV_8UC(cn)), dst; Mat src(height, width, CV_8UC(cn)), dst;
//randu(src, 0, 256); //randu(src, 0, 256);
src.setTo(0.); src.setTo(0.);
Mat rot = getRotationMatrix2D(Point2f(0.f, 0.f), 1, 1); Mat rot = getRotationMatrix2D(Point2f(0.f, 0.f), 1.0, 1.0);
warpAffine(src, dst, rot, src.size()); warpAffine(src, dst, rot, src.size(), inter, border);
ASSERT_EQ(0.0, norm(dst, NORM_INF)); ASSERT_EQ(0.0, norm(dst, NORM_INF));
Mat rot2 = Mat::eye(3, 3, rot.type()); Mat rot2 = Mat::eye(3, 3, rot.type());
rot.copyTo(rot2.rowRange(0, 2)); rot.copyTo(rot2.rowRange(0, 2));
warpPerspective(src, dst, rot2, src.size()); warpPerspective(src, dst, rot2, src.size(), inter, border);
ASSERT_EQ(0.0, norm(dst, NORM_INF)); ASSERT_EQ(0.0, norm(dst, NORM_INF));
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment