From 6407093463fe30fc8596a48dfae4dd8289ba228f Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Mon, 13 Jun 2011 20:56:27 +0000 Subject: [PATCH] extended Mat::setTo() to support multi-channel arrays; fixed bug #1095 --- modules/core/include/opencv2/core/core.hpp | 5 +- modules/core/src/arithm.cpp | 14 +-- modules/core/src/copy.cpp | 150 ++++++++++------------------- modules/core/src/precomp.hpp | 13 +++ modules/imgproc/src/thresh.cpp | 2 +- 5 files changed, 68 insertions(+), 116 deletions(-) diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index 35ec8bc..da050da 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -1649,7 +1649,7 @@ public: //! sets every matrix element to s Mat& operator = (const Scalar& s); //! sets some of the matrix elements to s, according to the mask - Mat& setTo(const Scalar& s, InputArray mask=noArray()); + Mat& setTo(InputArray value, InputArray mask=noArray()); //! creates alternative matrix header for the same data, with different // number of channels and/or different number of rows. see cvReshape. Mat reshape(int _cn, int _rows=0) const; @@ -4200,9 +4200,6 @@ class CV_EXPORTS CommandLineParser bool has(const std::string& keys) const; template - _Tp analizeValue(const std::string& str); - - template static _Tp getData(const std::string& str) { _Tp res; diff --git a/modules/core/src/arithm.cpp b/modules/core/src/arithm.cpp index b155e7a..fdb2707 100644 --- a/modules/core/src/arithm.cpp +++ b/modules/core/src/arithm.cpp @@ -946,18 +946,7 @@ static void not8u( const uchar* src1, size_t step1, * logical operations * \****************************************************************************************/ -static inline bool checkScalar(const Mat& sc, int atype, int sckind, int akind) -{ - if( sc.dims > 2 || (sc.cols != 1 && sc.rows != 1) || !sc.isContinuous() ) - return false; - int cn = CV_MAT_CN(atype); - if( akind == _InputArray::MATX && sckind != _InputArray::MATX ) - return false; - return sc.size() == Size(1, 1) || sc.size() == Size(1, cn) || sc.size() == Size(cn, 1) || - (sc.size() == Size(1, 4) && sc.type() == CV_64F && cn <= 4); -} - -static void convertAndUnrollScalar( const Mat& sc, int buftype, uchar* scbuf, size_t blocksize ) +void convertAndUnrollScalar( const Mat& sc, int buftype, uchar* scbuf, size_t blocksize ) { int scn = (int)sc.total(), cn = CV_MAT_CN(buftype); size_t esz = CV_ELEM_SIZE(buftype); @@ -972,7 +961,6 @@ static void convertAndUnrollScalar( const Mat& sc, int buftype, uchar* scbuf, si } for( size_t i = esz; i < blocksize*esz; i++ ) scbuf[i] = scbuf[i - esz]; - } void binary_op(InputArray _src1, InputArray _src2, OutputArray _dst, diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index c801a67..e33177d 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -95,71 +95,25 @@ copyMaskGeneric(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep } } -template static void -setMask_(T value, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size) -{ - for( ; size.height--; mask += mstep, _dst += dstep ) - { - T* dst = (T*)_dst; - int x = 0; - for( ; x <= size.width - 4; x += 4 ) - { - if( mask[x] ) - dst[x] = value; - if( mask[x+1] ) - dst[x+1] = value; - if( mask[x+2] ) - dst[x+2] = value; - if( mask[x+3] ) - dst[x+3] = value; - } - for( ; x < size.width; x++ ) - if( mask[x] ) - dst[x] = value; - } -} - -static void -setMaskGeneric(const uchar* value, size_t, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size, void* _esz) -{ - size_t k, esz = *(size_t*)_esz; - for( ; size.height--; mask += mstep, _dst += dstep ) - { - uchar* dst = _dst; - int x = 0; - for( ; x < size.width; x++, dst += esz ) - { - if( !mask[x] ) - continue; - for( k = 0; k < esz; k++ ) - dst[k] = value[k]; - } - } -} -#define DEF_COPY_SET_MASK(suffix, type) \ +#define DEF_COPY_MASK(suffix, type) \ static void copyMask##suffix(const uchar* src, size_t sstep, const uchar* mask, size_t mstep, \ uchar* dst, size_t dstep, Size size, void*) \ { \ copyMask_(src, sstep, mask, mstep, dst, dstep, size); \ -} \ -static void setMask##suffix( const uchar* src, size_t, const uchar* mask, size_t mstep, \ - uchar* dst, size_t dstep, Size size, void*) \ -{ \ - setMask_(*(const type*)src, mask, mstep, dst, dstep, size); \ } -DEF_COPY_SET_MASK(8u, uchar); -DEF_COPY_SET_MASK(16u, ushort); -DEF_COPY_SET_MASK(8uC3, Vec3b); -DEF_COPY_SET_MASK(32s, int); -DEF_COPY_SET_MASK(16uC3, Vec3s); -DEF_COPY_SET_MASK(32sC2, Vec2i); -DEF_COPY_SET_MASK(32sC3, Vec3i); -DEF_COPY_SET_MASK(32sC4, Vec4i); -DEF_COPY_SET_MASK(32sC6, Vec6i); -DEF_COPY_SET_MASK(32sC8, Vec8i); +DEF_COPY_MASK(8u, uchar); +DEF_COPY_MASK(16u, ushort); +DEF_COPY_MASK(8uC3, Vec3b); +DEF_COPY_MASK(32s, int); +DEF_COPY_MASK(16uC3, Vec3s); +DEF_COPY_MASK(32sC2, Vec2i); +DEF_COPY_MASK(32sC3, Vec3i); +DEF_COPY_MASK(32sC4, Vec4i); +DEF_COPY_MASK(32sC6, Vec6i); +DEF_COPY_MASK(32sC8, Vec8i); BinaryFunc copyMaskTab[] = { @@ -181,27 +135,6 @@ BinaryFunc copyMaskTab[] = 0, 0, 0, 0, 0, 0, 0, copyMask32sC8 }; - -BinaryFunc setMaskTab[] = -{ - 0, - setMask8u, - setMask16u, - setMask8uC3, - setMask32s, - 0, - setMask16uC3, - 0, - setMask32sC2, - 0, 0, 0, - setMask32sC3, - 0, 0, 0, - setMask32sC4, - 0, 0, 0, 0, 0, 0, 0, - setMask32sC6, - 0, 0, 0, 0, 0, 0, 0, - setMask32sC8 -}; BinaryFunc getCopyMaskFunc(size_t esz) { @@ -236,7 +169,11 @@ void Mat::copyTo( OutputArray _dst ) const const uchar* sptr = data; uchar* dptr = dst.data; - Size sz = getContinuousSize(*this, dst, (int)elemSize()); + // to handle the copying 1xn matrix => nx1 std vector. + Size sz = size() == dst.size() ? + getContinuousSize(*this, dst, (int)elemSize()) : + getContinuousSize(*this, (int)elemSize()); + for( ; sz.height--; sptr += step, dptr += dst.step ) memcpy( dptr, sptr, sz.width ); } @@ -333,26 +270,43 @@ Mat& Mat::operator = (const Scalar& s) return *this; } -Mat& Mat::setTo(const Scalar& s, InputArray _mask) + +Mat& Mat::setTo(InputArray _value, InputArray _mask) { - Mat mask = _mask.getMat(); - if( !mask.data ) - *this = s; - else + if( !data ) + return *this; + + Mat value = _value.getMat(), mask = _mask.getMat(); + + CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::MAT )); + CV_Assert( mask.empty() || mask.type() == CV_8U ); + + size_t esz = elemSize(); + BinaryFunc copymask = getCopyMaskFunc(esz); + + const Mat* arrays[] = { this, !mask.empty() ? &mask : 0, 0 }; + uchar* ptrs[2]={0,0}; + NAryMatIterator it(arrays, ptrs); + int total = (int)it.size, blockSize0 = std::min(total, (int)((BLOCK_SIZE + esz-1)/esz)); + AutoBuffer _scbuf(blockSize0*esz + 32); + uchar* scbuf = alignPtr((uchar*)_scbuf, (int)sizeof(double)); + convertAndUnrollScalar( value, type(), scbuf, blockSize0 ); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) { - CV_Assert( channels() <= 4 && mask.type() == CV_8U ); - size_t esz = elemSize(); - BinaryFunc func = esz <= 32 ? setMaskTab[esz] : setMaskGeneric; - double buf[4]; - scalarToRawData(s, buf, type(), 0); - - const Mat* arrays[] = { this, &mask, 0 }; - uchar* ptrs[2]; - NAryMatIterator it(arrays, ptrs); - Size sz((int)it.size, 1); - - for( size_t i = 0; i < it.nplanes; i++, ++it ) - func((const uchar*)buf, 0, ptrs[1], 0, ptrs[0], 0, sz, &esz); + for( int j = 0; j < total; j += blockSize0 ) + { + Size sz(std::min(blockSize0, total - j), 1); + size_t blockSize = sz.width*esz; + if( ptrs[1] ) + { + copymask(scbuf, 0, ptrs[1], 0, ptrs[0], 0, sz, &esz); + ptrs[1] += sz.width; + } + else + memcpy(ptrs[0], scbuf, blockSize); + ptrs[0] += blockSize; + } } return *this; } @@ -566,7 +520,7 @@ cvSet( void* arr, CvScalar value, const void* maskarr ) if( !maskarr ) m = value; else - m.setTo(value, cv::cvarrToMat(maskarr)); + m.setTo(cv::Scalar(value), cv::cvarrToMat(maskarr)); } CV_IMPL void diff --git a/modules/core/src/precomp.hpp b/modules/core/src/precomp.hpp index fb3eba3..14a3437 100644 --- a/modules/core/src/precomp.hpp +++ b/modules/core/src/precomp.hpp @@ -194,6 +194,19 @@ static inline IppiSize ippiSize(Size _sz) { IppiSize sz = { _sz.wid #define IF_IPP(then_call, else_call) else_call #endif +inline bool checkScalar(const Mat& sc, int atype, int sckind, int akind) +{ + if( sc.dims > 2 || (sc.cols != 1 && sc.rows != 1) || !sc.isContinuous() ) + return false; + int cn = CV_MAT_CN(atype); + if( akind == _InputArray::MATX && sckind != _InputArray::MATX ) + return false; + return sc.size() == Size(1, 1) || sc.size() == Size(1, cn) || sc.size() == Size(cn, 1) || + (sc.size() == Size(1, 4) && sc.type() == CV_64F && cn <= 4); +} + +void convertAndUnrollScalar( const Mat& sc, int buftype, uchar* scbuf, size_t blocksize ); + } #endif /*_CXCORE_INTERNAL_H_*/ diff --git a/modules/imgproc/src/thresh.cpp b/modules/imgproc/src/thresh.cpp index 78f7807..4579c8e 100644 --- a/modules/imgproc/src/thresh.cpp +++ b/modules/imgproc/src/thresh.cpp @@ -531,7 +531,7 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m int v = type == THRESH_BINARY ? (ithresh >= 255 ? 0 : imaxval) : type == THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) : type == THRESH_TRUNC ? imaxval : 0; - dst = Scalar::all(v); + dst.setTo(v); } else src.copyTo(dst); -- 2.7.4