#include "precomp.hpp"
+#include <float.h>
+#include <limits.h>
using namespace cv;
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<int>& 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<int>& size, int type, double minVal, double maxVal, bool useRoi)
+{
+ int i, dims = (int)size.size();
+ vector<int> size0(dims);
+ vector<Range> 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,
}
-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());
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];
}
}
}
}
+
+
+template<typename _Tp> static void
+erode_(const Mat& src, Mat& dst, const vector<int>& 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<typename _Tp> static void
+dilate_(const Mat& src, Mat& dst, const vector<int>& 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<int> 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<uchar>(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_<uchar>(src, dst, ofs);
+ break;
+ case CV_8S:
+ erode_<schar>(src, dst, ofs);
+ break;
+ case CV_16U:
+ erode_<ushort>(src, dst, ofs);
+ break;
+ case CV_16S:
+ erode_<short>(src, dst, ofs);
+ break;
+ case CV_32S:
+ erode_<int>(src, dst, ofs);
+ break;
+ case CV_32F:
+ erode_<float>(src, dst, ofs);
+ break;
+ case CV_64F:
+ erode_<double>(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<int> 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<uchar>(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_<uchar>(src, dst, ofs);
+ break;
+ case CV_8S:
+ dilate_<schar>(src, dst, ofs);
+ break;
+ case CV_16U:
+ dilate_<ushort>(src, dst, ofs);
+ break;
+ case CV_16S:
+ dilate_<short>(src, dst, ofs);
+ break;
+ case CV_32S:
+ dilate_<int>(src, dst, ofs);
+ break;
+ case CV_32F:
+ dilate_<float>(src, dst, ofs);
+ break;
+ case CV_64F:
+ dilate_<double>(src, dst, ofs);
+ break;
+ default:
+ CV_Assert(0);
+ }
+}
+
+
+template<typename _Tp> static void
+filter2D_(const Mat& src, Mat& dst, const vector<int>& ofsvec, const vector<double>& 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<double>(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<int> ofs;
+ vector<double> 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_<uchar>(src, _dst, ofs, coeff);
+ break;
+ case CV_8S:
+ filter2D_<schar>(src, _dst, ofs, coeff);
+ break;
+ case CV_16U:
+ filter2D_<ushort>(src, _dst, ofs, coeff);
+ break;
+ case CV_16S:
+ filter2D_<short>(src, _dst, ofs, coeff);
+ break;
+ case CV_32S:
+ filter2D_<int>(src, _dst, ofs, coeff);
+ break;
+ case CV_32F:
+ filter2D_<float>(src, _dst, ofs, coeff);
+ break;
+ case CV_64F:
+ filter2D_<double>(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<uchar> 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<int> 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<typename _Tp> 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<int>& 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<int>* _maxloc, vector<int>* _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<typename _Tp> 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<typename _Tp> 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<int>* maxloc, vector<int>* 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<int>* 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<typename _Tp> 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<typename _Tp, typename _WTp> 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<int>(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<typename _Tp> 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<typename _Tp> 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<int>* 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;
+}
}