用mask掩码处理图片,Mat::copyTo函数第一个用于输出的传入参数不能是原图片

来源:互联网 发布:破获特大网络售假药案 编辑:程序博客网 时间:2024/04/28 07:22

例如src.copyTo(src,mask)是绝对不能成功的。原本只想把理由粗略说一下,但是后来想一想看一看源代码还是有好处的,于是去源代码里面看了看,怎么知道由于本人的过于才疏学浅,就这么一看就看了我好几个小时(包括看了恒大对山东的0:0),虽然还不是非常清楚,还是贴上来简单说说吧:


void Mat::copyTo( OutputArray _dst, InputArray _mask ) const{    Mat mask = _mask.getMat();    if( !mask.data )    {        copyTo(_dst);        return;    }    int cn = channels(), mcn = mask.channels();    CV_Assert( mask.depth() == CV_8U && (mcn == 1 || mcn == cn) );    bool colorMask = mcn > 1;    size_t esz = colorMask ? elemSize1() : elemSize();    BinaryFunc copymask = getCopyMaskFunc(esz);    uchar* data0 = _dst.getMat().data;    _dst.create( dims, size, type() );    Mat dst = _dst.getMat();    if( dst.data != data0 ) // do not leave dst uninitialized        dst = Scalar(0);    if( dims <= 2 )    {        Size sz = getContinuousSize(*this, dst, mask, mcn);        copymask(data, step, mask.data, mask.step, dst.data, dst.step, sz, &esz);        return;    }    const Mat* arrays[] = { this, &dst, &mask, 0 };    uchar* ptrs[3];    NAryMatIterator it(arrays, ptrs);    Size sz((int)(it.size*mcn), 1);    for( size_t i = 0; i < it.nplanes; i++, ++it )        copymask(ptrs[0], 0, ptrs[2], 0, ptrs[1], 0, sz, &esz);}


重点是这里:

copymask(data, step, mask.data, mask.step, dst.data, dst.step, sz, &esz);

于是现在需要返回去找copymask了(不得不说qtcreator真是一个比较完美的IDE):


BinaryFunc copymask = getCopyMaskFunc(esz);

于是:


BinaryFunc getCopyMaskFunc(size_t esz){    return esz <= 32 && copyMaskTab[esz] ? copyMaskTab[esz] : copyMaskGeneric;}

得出:


BinaryFunc copyMaskTab[] ={    0,    copyMask8u,    copyMask16u,    copyMask8uC3,    copyMask32s,    0,    copyMask16uC3,    0,    copyMask32sC2,    0, 0, 0,    copyMask32sC3,    0, 0, 0,    copyMask32sC4,    0, 0, 0, 0, 0, 0, 0,    copyMask32sC6,    0, 0, 0, 0, 0, 0, 0,    copyMask32sC8};

重点来了,我搞了好久才发现原来copyMaskXXX(例如copyMask16uC3)是这样被定义以及使用的,这让我受益匪浅!!!:


#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_<type>(src, sstep, mask, mstep, dst, dstep, size); \}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);

利用这样的宏定义!好帅啊~!!(估计计算机学院的同学们可能会笑我没见过世面~~)


因此,分析到这里,我们应该知道,我们真正需要分析的是这个函数:


template<typename T> static voidcopyMask_(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size){    for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep )    {        const T* src = (const T*)_src;        T* dst = (T*)_dst;        int x = 0;         #if CV_ENABLE_UNROLLED        for( ; x <= size.width - 4; x += 4 )        {            if( mask[x] )                dst[x] = src[x];            if( mask[x+1] )                dst[x+1] = src[x+1];            if( mask[x+2] )                dst[x+2] = src[x+2];            if( mask[x+3] )                dst[x+3] = src[x+3];        }        #endif        for( ; x < size.width; x++ )            if( mask[x] )                dst[x] = src[x];    }}

从这个函数里面我们能看到,这个函数会检测mask中相应位置是否为0,如果不为0是会把输入Mat相应位置的值直接复制到输出中的,但是,如果mask中相应位置为0呢,遇到为0的位置,copyMask函数并不会把相应的输出设置为0,而是不理它,让它维持原值,因此,如果我们Mat::copyTo的传入参数为源图像,那么mask中相应不为0的部分会原封不动输出,而相应为0的地方也会保持不变地输出!因此,这样使用并不能成功。


这些小打小闹且浪费时间的源代码分析虽然是有益的,但是对学习视觉分析个人认为没有太大必要,我还是得赶紧搞搞真正的算法才行。

原创粉丝点击