From d2c2c07ad24e6336fcdf83c6e535453e36cfd3c0 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 11 Jan 2011 11:55:58 +0000 Subject: [PATCH] updated the new arithmetic tests --- modules/core/test/test_arithm.cpp | 68 +- .../gtest/include/opencv2/gtest/gtestcv.hpp | 29 +- modules/gtest/src/gtestcv.cpp | 1114 ++++++++++++++++- 3 files changed, 1168 insertions(+), 43 deletions(-) diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index 6ad486ff16..adcb8625ae 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -1,25 +1,61 @@ #include "precomp.hpp" +#include using namespace cv; +using namespace std; + +const int ARITHM_NTESTS = 1000; +const int ARITHM_RNG_SEED = -1; +const int ARITHM_MAX_NDIMS = 4; +const int ARITHM_MAX_SIZE_LOG = 10; +const int ARITHM_MAX_CHANNELS = 4; + +static void getArithmValueRange(int depth, double& minval, double& maxval) +{ + minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.; + maxval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? 1000000 : 1000.; +} + +static double getArithmMaxErr(int depth) +{ + return depth < CV_32F ? 0 : 4; +} TEST(ArithmTest, add) { - typedef uchar _Tp; - - Mat A(30,30,DataType<_Tp>::type), B(A.size(), A.type()), C0, C; - RNG rng(-1); - rng.fill(A, RNG::UNIFORM, Scalar::all(0), Scalar::all(256)); - rng.fill(B, RNG::UNIFORM, Scalar::all(0), Scalar::all(256)); - C0.create(A.size(), A.type()); - int i, j, cols = A.cols*A.channels(); - for(i = 0; i < A.rows; i++) + int testIdx = 0; + RNG rng(ARITHM_RNG_SEED); + for( testIdx = 0; testIdx < ARITHM_NTESTS; testIdx++ ) { - const _Tp* aptr = A.ptr<_Tp>(i); - const _Tp* bptr = B.ptr<_Tp>(i); - _Tp* cptr = C0.ptr<_Tp>(i); - for(j = 0; j < cols; j++) - cptr[j] = saturate_cast<_Tp>(aptr[j] + bptr[j]); + double minval, maxval; + vector size; + cvtest::randomSize(rng, 2, ARITHM_MAX_NDIMS, ARITHM_MAX_SIZE_LOG, size); + int type = cvtest::randomType(rng, cvtest::TYPE_MASK_ALL, 1, ARITHM_MAX_CHANNELS); + int depth = CV_MAT_DEPTH(type); + bool haveMask = rng.uniform(0, 4) == 0; + + getArithmValueRange(depth, minval, maxval); + Mat src1 = cvtest::randomMat(rng, size, type, minval, maxval, true); + Mat src2 = cvtest::randomMat(rng, size, type, minval, maxval, true); + Mat dst0 = cvtest::randomMat(rng, size, type, minval, maxval, false); + Mat dst = cvtest::randomMat(rng, size, type, minval, maxval, true); + Mat mask; + if( haveMask ) + { + mask = cvtest::randomMat(rng, size, CV_8U, 0, 2, true); + cvtest::copy(dst0, dst); + cvtest::add(src1, 1, src2, 1, Scalar::all(0), dst0, dst.type()); + cvtest::copy(dst, dst0, mask, true); + add(src1, src2, dst, mask); + } + else + { + cvtest::add(src1, 1, src2, 1, Scalar::all(0), dst0, dst.type()); + add(src1, src2, dst); + } + + double maxErr = getArithmMaxErr(depth); + vector pos; + ASSERT_TRUE(cvtest::cmpEps(dst0, dst, maxErr, &pos)) << "position: " << Mat(pos); } - add(A, B, C); - EXPECT_EQ(norm(C, C0, NORM_INF), 0); } diff --git a/modules/gtest/include/opencv2/gtest/gtestcv.hpp b/modules/gtest/include/opencv2/gtest/gtestcv.hpp index 8ec387da97..2da7febea1 100644 --- a/modules/gtest/include/opencv2/gtest/gtestcv.hpp +++ b/modules/gtest/include/opencv2/gtest/gtestcv.hpp @@ -27,29 +27,38 @@ enum TYPE_MASK_ALL = (TYPE_MASK_64F<<1)-1, TYPE_MASK_ALL_BUT_8S = TYPE_MASK_ALL & ~TYPE_MASK_8S }; + +CV_EXPORTS double getMinVal(int depth); +CV_EXPORTS double getMaxVal(int depth); CV_EXPORTS Size randomSize(RNG& rng, double maxSizeLog); CV_EXPORTS void randomSize(RNG& rng, int minDims, int maxDims, double maxSizeLog, vector& sz); CV_EXPORTS int randomType(RNG& rng, int typeMask, int minChannels, int maxChannels); -CV_EXPORTS Mat randomMat(RNG& rng, Size size, int type, bool useRoi); -CV_EXPORTS Mat randomMat(RNG& rng, const vector& size, int type, bool useRoi); +CV_EXPORTS Mat randomMat(RNG& rng, Size size, int type, double minVal, double maxVal, bool useRoi); +CV_EXPORTS Mat randomMat(RNG& rng, const vector& size, int type, double minVal, double maxVal, bool useRoi); CV_EXPORTS void add(const Mat& a, double alpha, const Mat& b, double beta, - Scalar gamma, Mat& c, int ctype, bool calcAbs); -CV_EXPORTS void convert(const Mat& src, Mat& dst, int dtype, double alpha, double beta); -CV_EXPORTS void copy(const Mat& src, Mat& dst, const Mat& mask=Mat()); + Scalar gamma, Mat& c, int ctype, bool calcAbs=false); +CV_EXPORTS void convert(const Mat& src, Mat& dst, int dtype, double alpha=1, double beta=0); +CV_EXPORTS void copy(const Mat& src, Mat& dst, const Mat& mask=Mat(), bool invertMask=false); CV_EXPORTS void set(Mat& dst, const Scalar& gamma, const Mat& mask=Mat()); -CV_EXPORTS void minMaxFilter(const Mat& a, Mat& maxresult, const Mat& minresult, const Mat& kernel, Point anchor); -CV_EXPORTS void filter2D(const Mat& src, Mat& dst, int ddepth, const Mat& kernel, Point anchor, double delta, int borderType); -CV_EXPORTS void copyMakeBorder(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int borderType, Scalar borderValue); +CV_EXPORTS void erode(const Mat& src, Mat& dst, const Mat& _kernel, Point anchor=Point(-1,-1), + int borderType=IPL_BORDER_CONSTANT, const Scalar& borderValue=Scalar()); +CV_EXPORTS void dilate(const Mat& src, Mat& dst, const Mat& _kernel, Point anchor=Point(-1,-1), + int borderType=IPL_BORDER_CONSTANT, const Scalar& borderValue=Scalar()); +CV_EXPORTS void filter2D(const Mat& src, Mat& dst, int ddepth, const Mat& kernel, + Point anchor, double delta, int borderType, + const Scalar& borderValue=Scalar()); +CV_EXPORTS void copyMakeBorder(const Mat& src, Mat& dst, int top, int bottom, int left, int right, + int borderType, const Scalar& borderValue=Scalar()); CV_EXPORTS void minMaxLoc(const Mat& src, double* maxval, double* minval, vector* maxloc, vector* minloc, const Mat& mask=Mat()); CV_EXPORTS double norm(const Mat& src, int normType, const Mat& mask=Mat()); CV_EXPORTS double norm(const Mat& src1, const Mat& src2, int normType, const Mat& mask=Mat()); -CV_EXPORTS bool cmpEps(const Mat& src1, const Mat& src2, double maxDiff, vector* loc); +CV_EXPORTS bool cmpEps(const Mat& src1, const Mat& src2, int maxDiff, vector* loc); CV_EXPORTS void logicOp(const Mat& src1, const Mat& src2, Mat& dst, char c); CV_EXPORTS void logicOp(const Mat& src, const Scalar& s, Mat& dst, char c); CV_EXPORTS void compare(const Mat& src1, const Mat& src2, Mat& dst, int cmpop); -CV_EXPORTS void compare(const Mat& src, const Scalar& s, Mat& dst, int cmpop); +CV_EXPORTS void compare(const Mat& src, double s, Mat& dst, int cmpop); CV_EXPORTS void gemm(const Mat& src1, const Mat& src2, double alpha, const Mat& src3, double beta, Mat& dst, int flags); CV_EXPORTS void crosscorr(const Mat& src1, const Mat& src2, Mat& dst, int dtype); diff --git a/modules/gtest/src/gtestcv.cpp b/modules/gtest/src/gtestcv.cpp index 6a434bbdc5..25082ca1af 100644 --- a/modules/gtest/src/gtestcv.cpp +++ b/modules/gtest/src/gtestcv.cpp @@ -1,4 +1,6 @@ #include "precomp.hpp" +#include +#include using namespace cv; @@ -49,14 +51,65 @@ int randomType(RNG& rng, int typeMask, int minChannels, int maxChannels) return CV_MAKETYPE(depth, channels); } -Mat randomMat(RNG& rng, Size size, int type, bool useRoi) +double getMinVal(int depth) { - return Mat(); + double val = depth == CV_8U ? 0 : depth == CV_8S ? SCHAR_MIN : depth == CV_16U ? 0 : + depth == CV_16S ? SHRT_MIN : depth == CV_32S ? INT_MIN : + depth == CV_32F ? -FLT_MAX : depth == CV_64F ? -DBL_MAX : -1; + CV_Assert(val != -1); + return val; } -Mat randomMat(RNG& rng, const vector& size, int type, bool useRoi) +double getMaxVal(int depth) { - return Mat(); + double val = depth == CV_8U ? UCHAR_MAX : depth == CV_8S ? SCHAR_MAX : depth == CV_16U ? USHRT_MAX : + depth == CV_16S ? SHRT_MAX : depth == CV_32S ? INT_MAX : + depth == CV_32F ? FLT_MAX : depth == CV_64F ? DBL_MAX : -1; + CV_Assert(val != -1); + return val; +} + +Mat randomMat(RNG& rng, Size size, int type, double minVal, double maxVal, bool useRoi) +{ + Size size0 = size; + if( useRoi ) + { + size0.width += std::max(rng.uniform(0, 10) - 5, 0); + size0.height += std::max(rng.uniform(0, 10) - 5, 0); + } + + Mat m(size0, type); + + rng.fill(m, RNG::UNIFORM, Scalar::all(minVal), Scalar::all(maxVal)); + if( size0 == size ) + return m; + return m(Rect((size0.width-size.width)/2, (size0.height-size.height)/2, size.width, size.height)); +} + +Mat randomMat(RNG& rng, const vector& size, int type, double minVal, double maxVal, bool useRoi) +{ + int i, dims = (int)size.size(); + vector size0(dims); + vector r(dims); + bool eqsize = true; + for( i = 0; i < dims; i++ ) + { + size0[i] = size[i]; + r[i] = Range::all(); + if( useRoi ) + { + size0[i] += std::max(rng.uniform(0, 5) - 2, 0); + r[i] = Range((size0[i] - size[i])/2, (size0[i] - size[i])/2 + size[i]); + } + eqsize = eqsize && size[i] == size0[i]; + } + + Mat m(dims, &size0[0], type); + + rng.fill(m, RNG::UNIFORM, Scalar::all(minVal), Scalar::all(maxVal)); + if( eqsize ) + return m; + return m(&r[0]); } void add(const Mat& _a, double alpha, const Mat& _b, double beta, @@ -244,7 +297,7 @@ void convert(const Mat& src, Mat& dst, int dtype, double alpha, double beta) } -void copy(const Mat& src, Mat& dst, const Mat& mask) +void copy(const Mat& src, Mat& dst, const Mat& mask, bool invertMask) { dst.create(src.dims, &src.size[0], src.type()); @@ -279,7 +332,7 @@ void copy(const Mat& src, Mat& dst, const Mat& mask) for( j = 0; j < total; j++, sptr += elemSize, dptr += elemSize ) { - if( mptr[j] ) + if( (mptr[j] != 0) ^ invertMask ) for( k = 0; k < elemSize; k++ ) dptr[k] = sptr[k]; } @@ -345,19 +398,1046 @@ void set(Mat& dst, const Scalar& gamma, const Mat& mask) } } } + + +template static void +erode_(const Mat& src, Mat& dst, const vector& ofsvec) +{ + int width = src.cols*src.channels(), n = (int)ofsvec.size(); + const int* ofs = &ofsvec[0]; + + for( int y = 0; y < dst.rows; y++ ) + { + const _Tp* sptr = src.ptr<_Tp>(y); + _Tp* dptr = dst.ptr<_Tp>(y); + + for( int x = 0; x < width; x++ ) + { + _Tp result = sptr[x + ofs[0]]; + for( int i = 1; i < n; i++ ) + result = std::min(result, sptr[x + ofs[i]]); + dptr[x] = result; + } + } +} + + +template static void +dilate_(const Mat& src, Mat& dst, const vector& ofsvec) +{ + int width = src.cols*src.channels(), n = (int)ofsvec.size(); + const int* ofs = &ofsvec[0]; + + for( int y = 0; y < dst.rows; y++ ) + { + const _Tp* sptr = src.ptr<_Tp>(y); + _Tp* dptr = dst.ptr<_Tp>(y); + + for( int x = 0; x < width; x++ ) + { + _Tp result = sptr[x + ofs[0]]; + for( int i = 1; i < n; i++ ) + result = std::max(result, sptr[x + ofs[i]]); + dptr[x] = result; + } + } +} + + +void erode(const Mat& _src, Mat& dst, const Mat& _kernel, Point anchor, + int borderType, const Scalar& _borderValue) +{ + Mat kernel = _kernel, src; + Scalar borderValue = _borderValue; + if( kernel.empty() ) + kernel = Mat::ones(3, 3, CV_8U); + else + { + CV_Assert( kernel.type() == CV_8U ); + } + if( anchor == Point(-1,-1) ) + anchor = Point(kernel.cols/2, kernel.rows/2); + if( borderType == IPL_BORDER_CONSTANT ) + borderValue = getMaxVal(src.depth()); + copyMakeBorder(_src, src, anchor.y, kernel.rows - anchor.y - 1, + anchor.x, kernel.cols - anchor.y - 1, + borderType, borderValue); + dst.create( _src.size(), src.type() ); + + vector ofs; + int step = (int)(src.step/src.elemSize1()), cn = src.channels(); + for( int i = 0; i < kernel.rows; i++ ) + for( int j = 0; j < kernel.cols; j++ ) + if( kernel.at(i, j) != 0 ) + ofs.push_back(i*step + j*cn); + if( ofs.empty() ) + ofs.push_back(anchor.y*step + anchor.x*cn); + + switch( src.depth() ) + { + case CV_8U: + erode_(src, dst, ofs); + break; + case CV_8S: + erode_(src, dst, ofs); + break; + case CV_16U: + erode_(src, dst, ofs); + break; + case CV_16S: + erode_(src, dst, ofs); + break; + case CV_32S: + erode_(src, dst, ofs); + break; + case CV_32F: + erode_(src, dst, ofs); + break; + case CV_64F: + erode_(src, dst, ofs); + break; + default: + CV_Assert(0); + } +} + +void dilate(const Mat& _src, Mat& dst, const Mat& _kernel, Point anchor, + int borderType, const Scalar& _borderValue) +{ + Mat kernel = _kernel, src; + Scalar borderValue = _borderValue; + if( kernel.empty() ) + kernel = Mat::ones(3, 3, CV_8U); + else + { + CV_Assert( kernel.type() == CV_8U ); + } + if( anchor == Point(-1,-1) ) + anchor = Point(kernel.cols/2, kernel.rows/2); + if( borderType == IPL_BORDER_CONSTANT ) + borderValue = getMinVal(src.depth()); + copyMakeBorder(_src, src, anchor.y, kernel.rows - anchor.y - 1, + anchor.x, kernel.cols - anchor.y - 1, + borderType, borderValue); + dst.create( _src.size(), src.type() ); + + vector ofs; + int step = (int)(src.step/src.elemSize1()), cn = src.channels(); + for( int i = 0; i < kernel.rows; i++ ) + for( int j = 0; j < kernel.cols; j++ ) + if( kernel.at(i, j) != 0 ) + ofs.push_back(i*step + j*cn); + if( ofs.empty() ) + ofs.push_back(anchor.y*step + anchor.x*cn); + + switch( src.depth() ) + { + case CV_8U: + dilate_(src, dst, ofs); + break; + case CV_8S: + dilate_(src, dst, ofs); + break; + case CV_16U: + dilate_(src, dst, ofs); + break; + case CV_16S: + dilate_(src, dst, ofs); + break; + case CV_32S: + dilate_(src, dst, ofs); + break; + case CV_32F: + dilate_(src, dst, ofs); + break; + case CV_64F: + dilate_(src, dst, ofs); + break; + default: + CV_Assert(0); + } +} + + +template static void +filter2D_(const Mat& src, Mat& dst, const vector& ofsvec, const vector& coeffvec) +{ + const int* ofs = &ofsvec[0]; + const double* coeff = &coeffvec[0]; + int width = dst.cols*dst.channels(), ncoeffs = (int)ofsvec.size(); + + for( int y = 0; y < dst.rows; y++ ) + { + const _Tp* sptr = src.ptr<_Tp>(y); + double* dptr = dst.ptr(y); + + for( int x = 0; x < width; x++ ) + { + double s = 0; + for( int i = 0; i < ncoeffs; i++ ) + s += sptr[ofs[i]]*coeff[i]; + dptr[x] = s; + } + } +} + + +void filter2D(const Mat& _src, Mat& dst, int ddepth, const Mat& _kernel, + Point anchor, double delta, int borderType, const Scalar& _borderValue) +{ + Mat kernel = _kernel, src, _dst; + Scalar borderValue = _borderValue; + CV_Assert( kernel.type() == CV_32F || kernel.type() == CV_64F ); + if( anchor == Point(-1,-1) ) + anchor = Point(kernel.cols/2, kernel.rows/2); + if( borderType == IPL_BORDER_CONSTANT ) + borderValue = getMinVal(src.depth()); + copyMakeBorder(_src, src, anchor.y, kernel.rows - anchor.y - 1, + anchor.x, kernel.cols - anchor.y - 1, + borderType, borderValue); + _dst.create( _src.size(), CV_MAKETYPE(CV_64F, src.channels()) ); + + vector ofs; + vector coeff(kernel.rows*kernel.cols); + Mat cmat(kernel.rows, kernel.cols, CV_64F, &coeff[0]); + convert(kernel, cmat, cmat.type()); + int step = (int)(src.step/src.elemSize1()), cn = src.channels(); + for( int i = 0; i < kernel.rows; i++ ) + for( int j = 0; j < kernel.cols; j++ ) + ofs.push_back(i*step + j*cn); + + switch( src.depth() ) + { + case CV_8U: + filter2D_(src, _dst, ofs, coeff); + break; + case CV_8S: + filter2D_(src, _dst, ofs, coeff); + break; + case CV_16U: + filter2D_(src, _dst, ofs, coeff); + break; + case CV_16S: + filter2D_(src, _dst, ofs, coeff); + break; + case CV_32S: + filter2D_(src, _dst, ofs, coeff); + break; + case CV_32F: + filter2D_(src, _dst, ofs, coeff); + break; + case CV_64F: + filter2D_(src, _dst, ofs, coeff); + break; + default: + CV_Assert(0); + } + + convert(_dst, dst, ddepth, 1, delta); +} + + +static int borderInterpolate( int p, int len, int borderType ) +{ + if( (unsigned)p < (unsigned)len ) + ; + else if( borderType == IPL_BORDER_REPLICATE ) + p = p < 0 ? 0 : len - 1; + else if( borderType == IPL_BORDER_REFLECT || borderType == IPL_BORDER_REFLECT_101 ) + { + int delta = borderType == IPL_BORDER_REFLECT_101; + if( len == 1 ) + return 0; + do + { + if( p < 0 ) + p = -p - 1 + delta; + else + p = len - 1 - (p - len) - delta; + } + while( (unsigned)p >= (unsigned)len ); + } + else if( borderType == IPL_BORDER_WRAP ) + { + if( p < 0 ) + p -= ((p-len+1)/len)*len; + if( p >= len ) + p %= len; + } + else if( borderType == IPL_BORDER_CONSTANT ) + p = -1; + else + CV_Error( CV_StsBadArg, "Unknown/unsupported border type" ); + return p; +} + + +void copyMakeBorder(const Mat& src, Mat& dst, int top, int bottom, int left, int right, + int borderType, const Scalar& borderValue) +{ + dst.create(src.rows + top + bottom, src.cols + left + right, src.type()); + int i, j, k, esz = (int)src.elemSize(); + int width = src.cols*esz, width1 = dst.cols*esz; + + if( borderType == IPL_BORDER_CONSTANT ) + { + vector valvec((src.cols + left + right)*esz); + uchar* val = &valvec[0]; + scalarToRawData(borderValue, val, src.type(), (src.cols + left + right)*src.channels()); + + left *= esz; + right *= esz; + for( i = 0; i < src.rows; i++ ) + { + const uchar* sptr = src.ptr(i); + uchar* dptr = dst.ptr(i + top) + left; + for( j = 0; j < left; j++ ) + dptr[j - left] = val[j]; + if( dptr != sptr ) + for( j = 0; j < width; j++ ) + dptr[j] = sptr[j]; + for( j = 0; j < right; j++ ) + dptr[j + width] = val[j]; + } + + for( i = 0; i < top; i++ ) + { + uchar* dptr = dst.ptr(i); + for( j = 0; j < width1; j++ ) + dptr[j] = val[j]; + } + + for( i = 0; i < bottom; i++ ) + { + uchar* dptr = dst.ptr(i + top + src.rows); + for( j = 0; j < width1; j++ ) + dptr[j] = val[j]; + } + } + else + { + vector tabvec((left + right)*esz); + int* ltab = &tabvec[0]; + int* rtab = &tabvec[left*esz]; + for( i = 0; i < left; i++ ) + { + j = borderInterpolate(i - left, src.cols, borderType)*esz; + for( k = 0; k < esz; k++ ) + ltab[i*esz + k] = j + k; + } + for( i = 0; i < right; i++ ) + { + j = borderInterpolate(src.cols + i, src.cols, borderType)*esz; + for( k = 0; k < esz; k++ ) + rtab[i*esz + k] = j + k; + } + + left *= esz; + right *= esz; + for( i = 0; i < src.rows; i++ ) + { + const uchar* sptr = src.ptr(i); + uchar* dptr = dst.ptr(i + top); + + for( j = 0; j < left; j++ ) + dptr[j] = sptr[ltab[j]]; + if( dptr + left != sptr ) + { + for( j = 0; j < width; j++ ) + dptr[j + left] = sptr[j]; + } + for( j = 0; j < right; j++ ) + dptr[j + left + width] = sptr[rtab[j]]; + } + + for( i = 0; i < top; i++ ) + { + j = borderInterpolate(i - top, src.rows, borderType); + const uchar* sptr = dst.ptr(j + top); + uchar* dptr = dst.ptr(i); + + for( k = 0; k < width1; k++ ) + dptr[k] = sptr[k]; + } + + for( i = 0; i < bottom; i++ ) + { + j = borderInterpolate(i + src.rows, src.rows, borderType); + const uchar* sptr = dst.ptr(j + top); + uchar* dptr = dst.ptr(i + top + src.rows); + + for( k = 0; k < width1; k++ ) + dptr[k] = sptr[k]; + } + } +} + + +template static void +minMaxLoc_(const _Tp* src, size_t total, size_t startidx, + double* _maxval, double* _minval, + size_t* _minpos, size_t* _maxpos, + const uchar* mask) +{ + _Tp maxval = saturate_cast<_Tp>(*_maxval), minval = saturate_cast<_Tp>(*_minval); + size_t minpos = *_minpos, maxpos = *_maxpos; + + if( !mask ) + { + for( size_t i = 0; i < total; i++ ) + { + _Tp val = src[i]; + if( minval > val ) + { + minval = val; + minpos = startidx + i; + } + if( maxval < val ) + { + maxval = val; + maxpos = startidx + i; + } + } + } + else + { + for( size_t i = 0; i < total; i++ ) + { + _Tp val = src[i]; + if( minval > val && mask[i] ) + { + minval = val; + minpos = startidx + i; + } + if( maxval < val && mask[i] ) + { + maxval = val; + maxpos = startidx + i; + } + } + } + + *_maxval = maxval; + *_minval = minval; + *_maxpos = maxpos; + *_minpos = minpos; +} + + +static void setpos( const Mat& mtx, vector& pos, size_t idx ) +{ + pos.resize(mtx.dims); + for( int i = mtx.dims-1; i >= 0; i-- ) + { + int sz = mtx.size[i]*(i == mtx.dims-1 ? mtx.channels() : 1); + pos[i] = idx % sz; + idx /= sz; + } +} + +void minMaxLoc(const Mat& src, double* _maxval, double* _minval, + vector* _maxloc, vector* _minloc, + const Mat& mask) +{ + CV_Assert( src.channels() == 1 ); + const Mat *arrays[2]={&src, &mask}; + Mat planes[2]; + + NAryMatIterator it(arrays, planes, 2); + size_t startidx = 1, total = planes[0].total(); + int i, nplanes = it.nplanes, depth = src.depth(); + double maxval = depth < CV_32F ? INT_MIN : depth == CV_32F ? -FLT_MAX : -DBL_MAX; + double minval = depth < CV_32F ? INT_MAX : depth == CV_32F ? FLT_MAX : DBL_MAX; + size_t maxidx = 0, minidx = 0; + + for( i = 0; i < nplanes; i++, ++it, startidx += total ) + { + const uchar* sptr = planes[0].data; + const uchar* mptr = planes[1].data; + + switch( depth ) + { + case CV_8U: + minMaxLoc_((const uchar*)sptr, total, startidx, + &maxval, &minval, &maxidx, &minidx, mptr); + break; + case CV_8S: + minMaxLoc_((const schar*)sptr, total, startidx, + &maxval, &minval, &maxidx, &minidx, mptr); + break; + case CV_16U: + minMaxLoc_((const ushort*)sptr, total, startidx, + &maxval, &minval, &maxidx, &minidx, mptr); + break; + case CV_16S: + minMaxLoc_((const short*)sptr, total, startidx, + &maxval, &minval, &maxidx, &minidx, mptr); + break; + case CV_32S: + minMaxLoc_((const int*)sptr, total, startidx, + &maxval, &minval, &maxidx, &minidx, mptr); + break; + case CV_32F: + minMaxLoc_((const float*)sptr, total, startidx, + &maxval, &minval, &maxidx, &minidx, mptr); + break; + case CV_64F: + minMaxLoc_((const double*)sptr, total, startidx, + &maxval, &minval, &maxidx, &minidx, mptr); + break; + default: + CV_Assert(0); + } + } + + if( _maxval ) + *_maxval = maxval; + if( _minval ) + *_minval = minval; + if( _maxloc ) + setpos( src, *_maxloc, maxidx ); + if( _minloc ) + setpos( src, *_minloc, minidx ); +} + + +template static double +norm_(const _Tp* src, size_t total, int normType, double startval, const uchar* mask) +{ + size_t i; + double result = startval; + + if( normType == NORM_INF ) + { + if( !mask ) + for( i = 0; i < total; i++ ) + result = std::max(result, (double)std::abs(src[i])); + else + for( i = 0; i < total; i++ ) + if( mask[i] ) + result = std::max(result, (double)std::abs(src[i])); + } + else if( normType == NORM_L1 ) + { + if( !mask ) + for( i = 0; i < total; i++ ) + result += std::abs(src[i]); + else + for( i = 0; i < total; i++ ) + if( mask[i] ) + result += std::abs(src[i]); + } + else + { + if( !mask ) + for( i = 0; i < total; i++ ) + { + double v = src[i]; + result += v*v; + } + else + for( i = 0; i < total; i++ ) + if( mask[i] ) + { + double v = src[i]; + result += v*v; + } + } + return result; +} + + +template static double +norm_(const _Tp* src1, const _Tp* src2, size_t total, int normType, double startval, const uchar* mask) +{ + size_t i; + double result = startval; + + if( normType == NORM_INF ) + { + if( !mask ) + for( i = 0; i < total; i++ ) + result = std::max(result, (double)std::abs(src1[i] - src2[i])); + else + for( i = 0; i < total; i++ ) + if( mask[i] ) + result = std::max(result, (double)std::abs(src1[i] - src2[i])); + } + else if( normType == NORM_L1 ) + { + if( !mask ) + for( i = 0; i < total; i++ ) + result += std::abs(src1[i] - src2[i]); + else + for( i = 0; i < total; i++ ) + if( mask[i] ) + result += std::abs(src1[i] - src2[i]); + } + else + { + if( !mask ) + for( i = 0; i < total; i++ ) + { + double v = src1[i] - src2[i]; + result += v*v; + } + else + for( i = 0; i < total; i++ ) + if( mask[i] ) + { + double v = src1[i] - src2[i]; + result += v*v; + } + } + return result; +} + + +double norm(const Mat& src, int normType, const Mat& mask) +{ + CV_Assert( mask.empty() || (src.size == mask.size && mask.type() == CV_8U) ); + CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 ); + const Mat *arrays[2]={&src, &mask}; + Mat planes[2]; + + NAryMatIterator it(arrays, planes, 2); + size_t total = planes[0].total()*planes[0].channels(); + int i, nplanes = it.nplanes, depth = src.depth(); + double result = 0; + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr = planes[0].data; + const uchar* mptr = planes[1].data; + + switch( depth ) + { + case CV_8U: + result = norm_((const uchar*)sptr, total, normType, result, mptr); + break; + case CV_8S: + result = norm_((const schar*)sptr, total, normType, result, mptr); + break; + case CV_16U: + result = norm_((const ushort*)sptr, total, normType, result, mptr); + break; + case CV_16S: + result = norm_((const short*)sptr, total, normType, result, mptr); + break; + case CV_32S: + result = norm_((const int*)sptr, total, normType, result, mptr); + break; + case CV_32F: + result = norm_((const float*)sptr, total, normType, result, mptr); + break; + case CV_64F: + result = norm_((const double*)sptr, total, normType, result, mptr); + break; + default: + CV_Error(CV_StsUnsupportedFormat, ""); + }; + } + if( normType == NORM_L2 ) + result = sqrt(result); + return result; +} + +double norm(const Mat& src1, const Mat& src2, int normType, const Mat& mask) +{ + CV_Assert( src1.type() == src2.type() && src1.size == src2.size ); + CV_Assert( mask.empty() || (src1.size == mask.size && mask.type() == CV_8U) ); + CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 ); + const Mat *arrays[3]={&src1, &src2, &mask}; + Mat planes[3]; + + NAryMatIterator it(arrays, planes, 3); + size_t total = planes[0].total()*planes[0].channels(); + int i, nplanes = it.nplanes, depth = src1.depth(); + double result = 0; + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr1 = planes[0].data; + const uchar* sptr2 = planes[1].data; + const uchar* mptr = planes[2].data; + + switch( depth ) + { + case CV_8U: + result = norm_((const uchar*)sptr1, (const uchar*)sptr2, total, normType, result, mptr); + break; + case CV_8S: + result = norm_((const schar*)sptr1, (const schar*)sptr2, total, normType, result, mptr); + break; + case CV_16U: + result = norm_((const ushort*)sptr1, (const ushort*)sptr2, total, normType, result, mptr); + break; + case CV_16S: + result = norm_((const short*)sptr1, (const short*)sptr2, total, normType, result, mptr); + break; + case CV_32S: + result = norm_((const int*)sptr1, (const int*)sptr2, total, normType, result, mptr); + break; + case CV_32F: + result = norm_((const float*)sptr1, (const float*)sptr2, total, normType, result, mptr); + break; + case CV_64F: + result = norm_((const double*)sptr1, (const double*)sptr2, total, normType, result, mptr); + break; + default: + CV_Error(CV_StsUnsupportedFormat, ""); + }; + } + if( normType == NORM_L2 ) + result = sqrt(result); + return result; +} -/*void minMaxFilter(const Mat& a, Mat& maxresult, const Mat& minresult, const Mat& kernel, Point anchor); -void filter2D(const Mat& src, Mat& dst, int ddepth, const Mat& kernel, Point anchor, double delta, int borderType); -void copyMakeBorder(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int borderType, Scalar borderValue); -void minMaxLoc(const Mat& src, double* maxval, double* minval, - vector* maxloc, vector* minloc, const Mat& mask=Mat()); -double norm(const Mat& src, int normType, const Mat& mask=Mat()); -double norm(const Mat& src1, const Mat& src2, int normType, const Mat& mask=Mat()); bool cmpEps(const Mat& src1, const Mat& src2, int int_maxdiff, int flt_maxulp, vector* loc); -void logicOp(const Mat& src1, const Mat& src2, Mat& dst, char c); -void logicOp(const Mat& src, const Scalar& s, Mat& dst, char c); -void compare(const Mat& src1, const Mat& src2, Mat& dst, int cmpop); -void compare(const Mat& src, const Scalar& s, Mat& dst, int cmpop);*/ + +static void +logicOp_(const uchar* src1, const uchar* src2, uchar* dst, size_t total, char c) +{ + size_t i; + if( c == '&' ) + for( i = 0; i < total; i++ ) + dst[i] = src1[i] & src2[i]; + else if( c == '|' ) + for( i = 0; i < total; i++ ) + dst[i] = src1[i] | src2[i]; + else + for( i = 0; i < total; i++ ) + dst[i] = src1[i] ^ src2[i]; +} + +static void +logicOpS_(const uchar* src, const uchar* scalar, uchar* dst, size_t total, char c) +{ + const size_t blockSize = 96; + size_t i, j; + if( c == '&' ) + for( i = 0; i < total; i += blockSize, dst += blockSize, src += blockSize ) + { + size_t sz = std::min(total - i, blockSize); + for( j = 0; j < sz; j++ ) + dst[j] = src[j] & scalar[j]; + } + else if( c == '|' ) + for( i = 0; i < total; i += blockSize, dst += blockSize, src += blockSize ) + { + size_t sz = std::min(total - i, blockSize); + for( j = 0; j < sz; j++ ) + dst[j] = src[j] | scalar[j]; + } + else if( c == '^' ) + { + for( i = 0; i < total; i += blockSize, dst += blockSize, src += blockSize ) + { + size_t sz = std::min(total - i, blockSize); + for( j = 0; j < sz; j++ ) + dst[j] = src[j] ^ scalar[j]; + } + } + else + for( i = 0; i < total; i++ ) + dst[i] = ~src[i]; +} + +void logicOp( const Mat& src1, const Mat& src2, Mat& dst, char op ) +{ + CV_Assert( op == '&' || op == '|' || op == '^' ); + CV_Assert( src1.type() == src2.type() && src1.size == src2.size ); + dst.create( src1.dims, &src1.size[0], src1.type() ); + const Mat *arrays[3]={&src1, &src2, &dst}; + Mat planes[3]; + + NAryMatIterator it(arrays, planes, 3); + size_t total = planes[0].total()*planes[0].elemSize(); + int i, nplanes = it.nplanes; + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr1 = planes[0].data; + const uchar* sptr2 = planes[1].data; + uchar* dptr = planes[2].data; + + logicOp_(sptr1, sptr2, dptr, total, op); + } +} + + +void logicOp(const Mat& src, const Scalar& s, Mat& dst, char op) +{ + CV_Assert( op == '&' || op == '|' || op == '^' ); + dst.create( src.dims, &src.size[0], src.type() ); + const Mat *arrays[2]={&src, &dst}; + Mat planes[2]; + + NAryMatIterator it(arrays, planes, 2); + size_t total = planes[0].total()*planes[0].elemSize(); + int i, nplanes = it.nplanes; + double buf[12]; + scalarToRawData(s, buf, src.type(), 12); + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr = planes[0].data; + uchar* dptr = planes[1].data; + + logicOpS_(sptr, (uchar*)&buf[0], dptr, total, op); + } +} + + +template static void +compare_(const _Tp* src1, const _Tp* src2, uchar* dst, size_t total, int cmpop) +{ + size_t i; + switch( cmpop ) + { + case CMP_LT: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] < src2[i] ? 255 : 0; + break; + case CMP_LE: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] <= src2[i] ? 255 : 0; + break; + case CMP_EQ: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] == src2[i] ? 255 : 0; + break; + case CMP_NE: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] != src2[i] ? 255 : 0; + break; + case CMP_GE: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] >= src2[i] ? 255 : 0; + break; + case CMP_GT: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] > src2[i] ? 255 : 0; + break; + default: + CV_Error(CV_StsBadArg, "Unknown comparison operation"); + } +} + + +template static void +compareS_(const _Tp* src1, _WTp value, uchar* dst, size_t total, int cmpop) +{ + size_t i; + switch( cmpop ) + { + case CMP_LT: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] < value ? 255 : 0; + break; + case CMP_LE: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] <= value ? 255 : 0; + break; + case CMP_EQ: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] == value ? 255 : 0; + break; + case CMP_NE: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] != value ? 255 : 0; + break; + case CMP_GE: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] >= value ? 255 : 0; + break; + case CMP_GT: + for( i = 0; i < total; i++ ) + dst[i] = src1[i] > value ? 255 : 0; + break; + default: + CV_Error(CV_StsBadArg, "Unknown comparison operation"); + } +} + + +void compare(const Mat& src1, const Mat& src2, Mat& dst, int cmpop) +{ + CV_Assert( src1.type() == src2.type() && src1.channels() == 1 && src1.size == src2.size ); + dst.create( src1.dims, &src1.size[0], CV_8U ); + const Mat *arrays[3]={&src1, &src2, &dst}; + Mat planes[3]; + + NAryMatIterator it(arrays, planes, 3); + size_t total = planes[0].total()*planes[0].elemSize(); + int i, nplanes = it.nplanes, depth = src1.depth(); + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr1 = planes[0].data; + const uchar* sptr2 = planes[1].data; + uchar* dptr = planes[2].data; + + switch( depth ) + { + case CV_8U: + compare_((const uchar*)sptr1, (const uchar*)sptr2, dptr, total, cmpop); + break; + case CV_8S: + compare_((const schar*)sptr1, (const schar*)sptr2, dptr, total, cmpop); + break; + case CV_16U: + compare_((const ushort*)sptr1, (const ushort*)sptr2, dptr, total, cmpop); + break; + case CV_16S: + compare_((const short*)sptr1, (const short*)sptr2, dptr, total, cmpop); + break; + case CV_32S: + compare_((const int*)sptr1, (const int*)sptr2, dptr, total, cmpop); + break; + case CV_32F: + compare_((const float*)sptr1, (const float*)sptr2, dptr, total, cmpop); + break; + case CV_64F: + compare_((const double*)sptr1, (const double*)sptr2, dptr, total, cmpop); + break; + default: + CV_Error(CV_StsUnsupportedFormat, ""); + } + } +} + +void compare(const Mat& src, double value, Mat& dst, int cmpop) +{ + CV_Assert( src.channels() == 1 ); + dst.create( src.dims, &src.size[0], CV_8U ); + const Mat *arrays[2]={&src, &dst}; + Mat planes[2]; + + NAryMatIterator it(arrays, planes, 2); + size_t total = planes[0].total()*planes[0].elemSize(); + int i, nplanes = it.nplanes, depth = src.depth(); + int ivalue = saturate_cast(value); + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr = planes[0].data; + uchar* dptr = planes[1].data; + + switch( depth ) + { + case CV_8U: + compareS_((const uchar*)sptr, ivalue, dptr, total, cmpop); + break; + case CV_8S: + compareS_((const schar*)sptr, ivalue, dptr, total, cmpop); + break; + case CV_16U: + compareS_((const ushort*)sptr, ivalue, dptr, total, cmpop); + break; + case CV_16S: + compareS_((const short*)sptr, ivalue, dptr, total, cmpop); + break; + case CV_32S: + compareS_((const int*)sptr, ivalue, dptr, total, cmpop); + break; + case CV_32F: + compareS_((const float*)sptr, value, dptr, total, cmpop); + break; + case CV_64F: + compareS_((const double*)sptr, value, dptr, total, cmpop); + break; + default: + CV_Error(CV_StsUnsupportedFormat, ""); + } + } +} + + +template static bool +cmpEpsInt_(const _Tp* src1, const _Tp* src2, int imaxdiff, size_t total, size_t startidx, size_t& idx) +{ + size_t i; + for( i = 0; i < total; i++ ) + if( std::abs(src1[i] - src2[i]) > imaxdiff ) + { + idx = i + startidx; + return false; + } + return true; +} + + +template static bool +cmpEpsFlt_(const _Tp* src1, const _Tp* src2, size_t total, int imaxdiff, size_t startidx, size_t& idx) +{ + const _Tp C = ((_Tp)1 << (sizeof(_Tp)*8-1)) - 1; + size_t i; + for( i = 0; i < total; i++ ) + { + _Tp a = src1[i], b = src2[i]; + if( a < 0 ) a ^= C; if( b < 0 ) b ^= C; + _Tp d = std::abs(a - b); + if( d > imaxdiff ) + { + idx = i + startidx; + return false; + } + } + return true; +} + + +bool cmpEps(const Mat& src1, const Mat& src2, int imaxDiff, vector* loc) +{ + CV_Assert( src1.type() == src2.type() && src1.size == src2.size ); + const Mat *arrays[2]={&src1, &src2}; + Mat planes[2]; + + NAryMatIterator it(arrays, planes, 2); + size_t total = planes[0].total()*planes[0].channels(); + int i, nplanes = it.nplanes, depth = src1.depth(); + size_t startidx = 0, idx = -1; + bool ok = true; + + for( i = 0; i < nplanes; i++, ++it, startidx += total ) + { + const uchar* sptr1 = planes[0].data; + const uchar* sptr2 = planes[1].data; + + switch( depth ) + { + case CV_8U: + ok = cmpEpsInt_((const uchar*)sptr1, (const uchar*)sptr2, total, imaxDiff, startidx, idx); + break; + case CV_8S: + ok = cmpEpsInt_((const schar*)sptr1, (const schar*)sptr2, total, imaxDiff, startidx, idx); + break; + case CV_16U: + ok = cmpEpsInt_((const ushort*)sptr1, (const ushort*)sptr2, total, imaxDiff, startidx, idx); + break; + case CV_16S: + ok = cmpEpsInt_((const short*)sptr1, (const short*)sptr2, total, imaxDiff, startidx, idx); + break; + case CV_32S: + ok = cmpEpsInt_((const int*)sptr1, (const int*)sptr2, total, imaxDiff, startidx, idx); + break; + case CV_32F: + ok = cmpEpsFlt_((const int*)sptr1, (const int*)sptr2, total, imaxDiff, startidx, idx); + break; + case CV_64F: + ok = cmpEpsFlt_((const int64*)sptr1, (const int64*)sptr2, total, imaxDiff, startidx, idx); + break; + default: + CV_Error(CV_StsUnsupportedFormat, ""); + } + if(!ok) + break; + } + if(!ok && loc) + setpos(src1, *loc, idx); + return ok; +} }