#include "precomp.hpp" #include #include using namespace cv; namespace cvtest { Size randomSize(RNG& rng, double maxSizeLog) { double width_log = rng.uniform(0., maxSizeLog); double height_log = rng.uniform(0., maxSizeLog - width_log); if( (unsigned)rng % 2 != 0 ) std::swap(width_log, height_log); Size sz; sz.width = cvRound(exp(width_log)); sz.height = cvRound(exp(height_log)); return sz; } void randomSize(RNG& rng, int minDims, int maxDims, double maxSizeLog, vector& sz) { int i, dims = rng.uniform(minDims, maxDims+1); sz.resize(dims); for( i = 0; i < dims; i++ ) { double v = rng.uniform(0., maxSizeLog); maxSizeLog -= v; sz[i] = cvRound(exp(v)); } for( i = 0; i < dims; i++ ) { int j = rng.uniform(0, dims); int k = rng.uniform(0, dims); std::swap(sz[j], sz[k]); } } int randomType(RNG& rng, int typeMask, int minChannels, int maxChannels) { int channels = rng.uniform(minChannels, maxChannels+1); int depth = 0; CV_Assert((typeMask & TYPE_MASK_ALL) != 0); for(;;) { depth = rng.uniform(CV_8U, CV_64F+1); if( ((1 << depth) & typeMask) != 0 ) break; } return CV_MAKETYPE(depth, channels); } double getMinVal(int depth) { 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; } double getMaxVal(int depth) { 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, Scalar gamma, Mat& c, int ctype, bool calcAbs) { Mat a = _a, b = _b; if( a.empty() || alpha == 0 ) { // both alpha and beta can be 0, but at least one of a and b must be non-empty array, // otherwise we do not know the size of the output (and may be type of the output, when ctype<0) CV_Assert( !a.empty() || !b.empty() ); if( !b.empty() ) { a = b; alpha = beta; b = Mat(); beta = 0; } } if( b.empty() || beta == 0 ) { b = Mat(); beta = 0; } else CV_Assert(a.size == b.size); if( ctype < 0 ) ctype = a.depth(); ctype = CV_MAKETYPE(CV_MAT_DEPTH(ctype), a.channels()); c.create(a.dims, &a.size[0], ctype); const Mat *arrays[3]; Mat planes[3], buf[3]; arrays[0] = &a; arrays[1] = b.empty() ? 0 : &b; arrays[2] = &c; NAryMatIterator it(arrays, planes, 3); int i, nplanes = it.nplanes, cn=a.channels(); size_t total = planes[0].total(), maxsize = std::min((size_t)12*12*std::max(12/cn, 1), total); CV_Assert(planes[0].rows == 1); buf[0].create(1, (int)maxsize, CV_64FC(cn)); if(!b.empty()) buf[1].create(1, maxsize, CV_64FC(cn)); buf[2].create(1, maxsize, CV_64FC(cn)); scalarToRawData(gamma, buf[2].data, CV_64FC(cn), (int)(maxsize*cn)); for( i = 0; i < nplanes; i++, ++it) { for( size_t j = 0; j < total; j += maxsize ) { size_t j2 = min(j + maxsize, total); Mat apart0 = planes[0].colRange((int)j, (int)j2); Mat cpart0 = planes[2].colRange((int)j, (int)j2); Mat apart = buf[0].colRange(0, (int)(j2 - j)); apart0.convertTo(apart, apart.type(), alpha); size_t k, n = (j2 - j)*cn; double* aptr = (double*)apart.data; const double* gptr = (const double*)buf[2].data; if( b.empty() ) { for( k = 0; k < n; k++ ) aptr[k] += gptr[k]; } else { Mat bpart0 = planes[1].colRange((int)j, (int)j2); Mat bpart = buf[1].colRange(0, (int)(j2 - j)); bpart0.convertTo(bpart, bpart.type(), beta); const double* bptr = (const double*)bpart.data; for( k = 0; k < n; k++ ) aptr[k] += bptr[k] + gptr[k]; } if( calcAbs ) for( k = 0; k < n; k++ ) aptr[k] = fabs(aptr[k]); apart.convertTo(cpart0, cpart0.type(), 1, 0); } } } template inline void convert_(const _Tp1* src, _Tp2* dst, size_t total, double alpha, double beta) { size_t i; if( alpha == 1 && beta == 0 ) for( i = 0; i < total; i++ ) dst[i] = saturate_cast<_Tp2>(src[i]); else if( beta == 0 ) for( i = 0; i < total; i++ ) dst[i] = saturate_cast<_Tp2>(src[i]*alpha); else for( i = 0; i < total; i++ ) dst[i] = saturate_cast<_Tp2>(src[i]*alpha + beta); } template inline void convertTo(const _Tp* src, void* dst, int dtype, size_t total, double alpha, double beta) { switch( CV_MAT_DEPTH(dtype) ) { case CV_8U: convert_(src, (uchar*)dst, total, alpha, beta); break; case CV_8S: convert_(src, (schar*)dst, total, alpha, beta); break; case CV_16U: convert_(src, (ushort*)dst, total, alpha, beta); break; case CV_16S: convert_(src, (short*)dst, total, alpha, beta); break; case CV_32S: convert_(src, (int*)dst, total, alpha, beta); break; case CV_32F: convert_(src, (float*)dst, total, alpha, beta); break; case CV_64F: convert_(src, (double*)dst, total, alpha, beta); break; default: CV_Assert(0); } } void convert(const Mat& src, Mat& dst, int dtype, double alpha, double beta) { dtype = CV_MAKETYPE(CV_MAT_DEPTH(dtype), src.channels()); dst.create(src.dims, &src.size[0], dtype); if( alpha == 0 ) { set( dst, Scalar::all(beta) ); return; } if( dtype == src.type() && alpha == 1 && beta == 0 ) { copy( src, dst ); return; } const Mat *arrays[]={&src, &dst}; Mat planes[2]; NAryMatIterator it(arrays, planes, 2); size_t total = planes[0].total()*planes[0].channels(); int i, nplanes = it.nplanes; for( i = 0; i < nplanes; i++, ++it) { const uchar* sptr = planes[0].data; uchar* dptr = planes[1].data; switch( src.depth() ) { case CV_8U: convertTo((const uchar*)sptr, dptr, dtype, total, alpha, beta); break; case CV_8S: convertTo((const schar*)sptr, dptr, dtype, total, alpha, beta); break; case CV_16U: convertTo((const ushort*)sptr, dptr, dtype, total, alpha, beta); break; case CV_16S: convertTo((const short*)sptr, dptr, dtype, total, alpha, beta); break; case CV_32S: convertTo((const int*)sptr, dptr, dtype, total, alpha, beta); break; case CV_32F: convertTo((const float*)sptr, dptr, dtype, total, alpha, beta); break; case CV_64F: convertTo((const double*)sptr, dptr, dtype, total, alpha, beta); break; } } } void copy(const Mat& src, Mat& dst, const Mat& mask, bool invertMask) { dst.create(src.dims, &src.size[0], src.type()); if(mask.empty()) { const Mat* arrays[] = {&src, &dst}; Mat planes[2]; NAryMatIterator it(arrays, planes, 2); int i, nplanes = it.nplanes; size_t planeSize = planes[0].total()*src.elemSize(); for( i = 0; i < nplanes; i++, ++it ) memcpy(planes[1].data, planes[0].data, planeSize); return; } CV_Assert( src.size == mask.size && mask.type() == CV_8U ); const Mat *arrays[3]={&src, &dst, &mask}; Mat planes[3]; NAryMatIterator it(arrays, planes, 3); size_t j, k, elemSize = src.elemSize(), total = planes[0].total(); int i, nplanes = it.nplanes; for( i = 0; i < nplanes; i++, ++it) { const uchar* sptr = planes[0].data; uchar* dptr = planes[1].data; const uchar* mptr = planes[2].data; for( j = 0; j < total; j++, sptr += elemSize, dptr += elemSize ) { if( (mptr[j] != 0) ^ invertMask ) for( k = 0; k < elemSize; k++ ) dptr[k] = sptr[k]; } } } void set(Mat& dst, const Scalar& gamma, const Mat& mask) { double buf[12]; scalarToRawData(gamma, &buf, dst.type(), dst.channels()); const uchar* gptr = (const uchar*)&buf[0]; if(mask.empty()) { const Mat* arrays[] = {&dst}; Mat plane; NAryMatIterator it(arrays, &plane, 1); int i, nplanes = it.nplanes; size_t j, k, elemSize = dst.elemSize(), planeSize = plane.total()*elemSize; for( k = 1; k < elemSize; k++ ) if( gptr[k] != gptr[0] ) break; bool uniform = k >= elemSize; for( i = 0; i < nplanes; i++, ++it ) { uchar* dptr = plane.data; if( uniform ) memset( dptr, gptr[0], planeSize ); else if( i == 0 ) { for( j = 0; j < planeSize; j += elemSize, dptr += elemSize ) for( k = 0; k < elemSize; k++ ) dptr[k] = gptr[k]; } else memcpy(dptr, dst.data, planeSize); } return; } CV_Assert( dst.size == mask.size && mask.type() == CV_8U ); const Mat *arrays[2]={&dst, &mask}; Mat planes[2]; NAryMatIterator it(arrays, planes, 2); size_t j, k, elemSize = dst.elemSize(), total = planes[0].total(); int i, nplanes = it.nplanes; for( i = 0; i < nplanes; i++, ++it) { uchar* dptr = planes[0].data; const uchar* mptr = planes[1].data; for( j = 0; j < total; j++, dptr += elemSize ) { if( mptr[j] ) for( k = 0; k < elemSize; k++ ) dptr[k] = gptr[k]; } } } 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; } bool cmpEps(const Mat& src1, const Mat& src2, int int_maxdiff, int flt_maxulp, vector* loc); 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; } }