Skip to content

Commit f413667

Browse files
committed
Merge pull request opencv#9551 from ChristofKaufmann:MultiChannelMask
2 parents 3358b89 + 7ec59fc commit f413667

File tree

4 files changed

+61
-28
lines changed

4 files changed

+61
-28
lines changed

modules/core/include/opencv2/core/mat.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,8 +1192,8 @@ class CV_EXPORTS Mat
11921192
/** @overload
11931193
@param m Destination matrix. If it does not have a proper size or type before the operation, it is
11941194
reallocated.
1195-
@param mask Operation mask. Its non-zero elements indicate which matrix elements need to be copied.
1196-
The mask has to be of type CV_8U and can have 1 or multiple channels.
1195+
@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix
1196+
elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels.
11971197
*/
11981198
void copyTo( OutputArray m, InputArray mask ) const;
11991199

@@ -1229,7 +1229,8 @@ class CV_EXPORTS Mat
12291229
12301230
This is an advanced variant of the Mat::operator=(const Scalar& s) operator.
12311231
@param value Assigned scalar converted to the actual array type.
1232-
@param mask Operation mask of the same size as \*this.
1232+
@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix
1233+
elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels
12331234
*/
12341235
Mat& setTo(InputArray value, InputArray mask=noArray());
12351236

modules/core/src/copy.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ static bool ipp_copyTo(const Mat &src, Mat &dst, const Mat &mask)
336336
#ifdef HAVE_IPP_IW
337337
CV_INSTRUMENT_REGION_IPP()
338338

339-
if(mask.channels() > 1 && mask.depth() != CV_8U)
339+
if(mask.channels() > 1 || mask.depth() != CV_8U)
340340
return false;
341341

342342
if (src.dims <= 2)
@@ -512,20 +512,23 @@ Mat& Mat::setTo(InputArray _value, InputArray _mask)
512512
Mat value = _value.getMat(), mask = _mask.getMat();
513513

514514
CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::MAT ));
515-
CV_Assert( mask.empty() || (mask.type() == CV_8U && size == mask.size) );
515+
int cn = channels(), mcn = mask.channels();
516+
CV_Assert( mask.empty() || (mask.depth() == CV_8U && (mcn == 1 || mcn == cn) && size == mask.size) );
516517

517518
CV_IPP_RUN_FAST(ipp_Mat_setTo_Mat(*this, value, mask), *this)
518519

519-
size_t esz = elemSize();
520+
size_t esz = mcn > 1 ? elemSize1() : elemSize();
520521
BinaryFunc copymask = getCopyMaskFunc(esz);
521522

522523
const Mat* arrays[] = { this, !mask.empty() ? &mask : 0, 0 };
523524
uchar* ptrs[2]={0,0};
524525
NAryMatIterator it(arrays, ptrs);
525-
int totalsz = (int)it.size, blockSize0 = std::min(totalsz, (int)((BLOCK_SIZE + esz-1)/esz));
526+
int totalsz = (int)it.size*mcn;
527+
int blockSize0 = std::min(totalsz, (int)((BLOCK_SIZE + esz-1)/esz));
528+
blockSize0 -= blockSize0 % mcn; // must be divisible without remainder for unrolling and advancing
526529
AutoBuffer<uchar> _scbuf(blockSize0*esz + 32);
527530
uchar* scbuf = alignPtr((uchar*)_scbuf, (int)sizeof(double));
528-
convertAndUnrollScalar( value, type(), scbuf, blockSize0 );
531+
convertAndUnrollScalar( value, type(), scbuf, blockSize0/mcn );
529532

530533
for( size_t i = 0; i < it.nplanes; i++, ++it )
531534
{

modules/core/test/test_arithm.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "test_precomp.hpp"
1+
#include "test_precomp.hpp"
22
#include <cmath>
33

44
using namespace cv;
@@ -15,7 +15,7 @@ const int ARITHM_MAX_SIZE_LOG = 10;
1515

1616
struct BaseElemWiseOp
1717
{
18-
enum { FIX_ALPHA=1, FIX_BETA=2, FIX_GAMMA=4, REAL_GAMMA=8, SUPPORT_MASK=16, SCALAR_OUTPUT=32 };
18+
enum { FIX_ALPHA=1, FIX_BETA=2, FIX_GAMMA=4, REAL_GAMMA=8, SUPPORT_MASK=16, SCALAR_OUTPUT=32, SUPPORT_MULTICHANNELMASK=64 };
1919
BaseElemWiseOp(int _ninputs, int _flags, double _alpha, double _beta,
2020
Scalar _gamma=Scalar::all(0), int _context=1)
2121
: ninputs(_ninputs), flags(_flags), alpha(_alpha), beta(_beta), gamma(_gamma), context(_context) {}
@@ -467,7 +467,7 @@ struct CmpSOp : public BaseElemWiseOp
467467

468468
struct CopyOp : public BaseElemWiseOp
469469
{
470-
CopyOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) { }
470+
CopyOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SUPPORT_MULTICHANNELMASK, 1, 1, Scalar::all(0)) { }
471471
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
472472
{
473473
src[0].copyTo(dst, mask);
@@ -489,7 +489,7 @@ struct CopyOp : public BaseElemWiseOp
489489

490490
struct SetOp : public BaseElemWiseOp
491491
{
492-
SetOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {}
492+
SetOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+SUPPORT_MASK+SUPPORT_MULTICHANNELMASK, 1, 1, Scalar::all(0)) {}
493493
void op(const vector<Mat>&, Mat& dst, const Mat& mask)
494494
{
495495
dst.setTo(gamma, mask);
@@ -1394,7 +1394,8 @@ TEST_P(ElemWiseTest, accuracy)
13941394
op->getRandomSize(rng, size);
13951395
int type = op->getRandomType(rng);
13961396
int depth = CV_MAT_DEPTH(type);
1397-
bool haveMask = (op->flags & cvtest::BaseElemWiseOp::SUPPORT_MASK) != 0 && rng.uniform(0, 4) == 0;
1397+
bool haveMask = ((op->flags & cvtest::BaseElemWiseOp::SUPPORT_MASK) != 0
1398+
|| (op->flags & cvtest::BaseElemWiseOp::SUPPORT_MULTICHANNELMASK) != 0) && rng.uniform(0, 4) == 0;
13981399

13991400
double minval=0, maxval=0;
14001401
op->getValueRange(depth, minval, maxval);
@@ -1403,8 +1404,12 @@ TEST_P(ElemWiseTest, accuracy)
14031404
for( i = 0; i < ninputs; i++ )
14041405
src[i] = cvtest::randomMat(rng, size, type, minval, maxval, true);
14051406
Mat dst0, dst, mask;
1406-
if( haveMask )
1407-
mask = cvtest::randomMat(rng, size, CV_8U, 0, 2, true);
1407+
if( haveMask ) {
1408+
bool multiChannelMask = (op->flags & cvtest::BaseElemWiseOp::SUPPORT_MULTICHANNELMASK) != 0
1409+
&& rng.uniform(0, 2) == 0;
1410+
int masktype = CV_8UC(multiChannelMask ? CV_MAT_CN(type) : 1);
1411+
mask = cvtest::randomMat(rng, size, masktype, 0, 2, true);
1412+
}
14081413

14091414
if( (haveMask || ninputs == 0) && !(op->flags & cvtest::BaseElemWiseOp::SCALAR_OUTPUT))
14101415
{

modules/ts/src/ts_func.cpp

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -353,26 +353,38 @@ void copy(const Mat& src, Mat& dst, const Mat& mask, bool invertMask)
353353
return;
354354
}
355355

356-
CV_Assert( src.size == mask.size && mask.type() == CV_8U );
356+
int mcn = mask.channels();
357+
CV_Assert( src.size == mask.size && mask.depth() == CV_8U
358+
&& (mcn == 1 || mcn == src.channels()) );
357359

358360
const Mat *arrays[]={&src, &dst, &mask, 0};
359361
Mat planes[3];
360362

361363
NAryMatIterator it(arrays, planes);
362-
size_t j, k, elemSize = src.elemSize(), total = planes[0].total();
364+
size_t j, k, elemSize = src.elemSize(), maskElemSize = mask.elemSize(), total = planes[0].total();
363365
size_t i, nplanes = it.nplanes;
366+
size_t elemSize1 = src.elemSize1();
364367

365368
for( i = 0; i < nplanes; i++, ++it)
366369
{
367370
const uchar* sptr = planes[0].ptr();
368371
uchar* dptr = planes[1].ptr();
369372
const uchar* mptr = planes[2].ptr();
370-
371-
for( j = 0; j < total; j++, sptr += elemSize, dptr += elemSize )
373+
for( j = 0; j < total; j++, sptr += elemSize, dptr += elemSize, mptr += maskElemSize )
372374
{
373-
if( (mptr[j] != 0) ^ invertMask )
374-
for( k = 0; k < elemSize; k++ )
375-
dptr[k] = sptr[k];
375+
if( mcn == 1)
376+
{
377+
if( (mptr[0] != 0) ^ invertMask )
378+
for( k = 0; k < elemSize; k++ )
379+
dptr[k] = sptr[k];
380+
}
381+
else
382+
{
383+
for( int c = 0; c < mcn; c++ )
384+
if( (mptr[c] != 0) ^ invertMask )
385+
for( k = 0; k < elemSize1; k++ )
386+
dptr[k + c * elemSize1] = sptr[k + c * elemSize1];
387+
}
376388
}
377389
}
378390
}
@@ -414,25 +426,37 @@ void set(Mat& dst, const Scalar& gamma, const Mat& mask)
414426
return;
415427
}
416428

417-
CV_Assert( dst.size == mask.size && mask.type() == CV_8U );
429+
int cn = dst.channels(), mcn = mask.channels();
430+
CV_Assert( dst.size == mask.size && (mcn == 1 || mcn == cn) );
418431

419432
const Mat *arrays[]={&dst, &mask, 0};
420433
Mat planes[2];
421434

422435
NAryMatIterator it(arrays, planes);
423-
size_t j, k, elemSize = dst.elemSize(), total = planes[0].total();
436+
size_t j, k, elemSize = dst.elemSize(), maskElemSize = mask.elemSize(), total = planes[0].total();
424437
size_t i, nplanes = it.nplanes;
438+
size_t elemSize1 = dst.elemSize1();
425439

426440
for( i = 0; i < nplanes; i++, ++it)
427441
{
428442
uchar* dptr = planes[0].ptr();
429443
const uchar* mptr = planes[1].ptr();
430444

431-
for( j = 0; j < total; j++, dptr += elemSize )
445+
for( j = 0; j < total; j++, dptr += elemSize, mptr += maskElemSize )
432446
{
433-
if( mptr[j] )
434-
for( k = 0; k < elemSize; k++ )
435-
dptr[k] = gptr[k];
447+
if( mcn == 1)
448+
{
449+
if( mptr[0] )
450+
for( k = 0; k < elemSize; k++ )
451+
dptr[k] = gptr[k];
452+
}
453+
else
454+
{
455+
for( int c = 0; c < mcn; c++ )
456+
if( mptr[c] )
457+
for( k = 0; k < elemSize1; k++ )
458+
dptr[k + c * elemSize1] = gptr[k + c * elemSize1];
459+
}
436460
}
437461
}
438462
}

0 commit comments

Comments
 (0)