OpenCV中对Mat类型的操作,具有很多技巧,下面列几个函数:
1)在逐步访问Mat类型数据时,一次可以访问多个元素(减少循环次数)
template<typename T, typename DT, typename WT> static void
cvtScaleAbs_( const T* src, size_t sstep,
DT* dst, size_t dstep, Size size,
WT scale, WT shift )
{
sstep /= sizeof(src[0]);
dstep /= sizeof(dst[0]);
for( ; size.height--; src += sstep, dst += dstep )
{
int x = 0;
#if CV_ENABLE_UNROLLED
for( ; x <= size.width - 4; x += 4 )
{
DT t0, t1;
t0 = saturate_cast<DT>(std::abs(src[x]*scale + shift));
t1 = saturate_cast<DT>(std::abs(src[x+1]*scale + shift));
dst[x] = t0; dst[x+1] = t1;
t0 = saturate_cast<DT>(std::abs(src[x+2]*scale + shift));
t1 = saturate_cast<DT>(std::abs(src[x+3]*scale + shift));
dst[x+2] = t0; dst[x+3] = t1;
}
#endif
for( ; x < size.width; x++ )
dst[x] = saturate_cast<DT>(std::abs(src[x]*scale + shift));
}
}
template<typename T> static void
copyMask_(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];
}
}
2)在确定目标类型和源类型后,可以逐行复制数据
void Mat::copyTo( OutputArray _dst ) const
{
int dtype = _dst.type();
if( _dst.fixedType() && dtype != type() )
{
CV_Assert( channels() == CV_MAT_CN(dtype) );
convertTo( _dst, dtype );
return;
}
if( empty() )
{
_dst.release();
return;
}
if( dims <= 2 )
{
_dst.create( rows, cols, type() );
Mat dst = _dst.getMat();
if( data == dst.data )
return;
if( rows > 0 && cols > 0 )
{
const uchar* sptr = data;
uchar* dptr = dst.data;
Size sz = getContinuousSize(*this, dst);
size_t len = sz.width*elemSize();
for( ; sz.height--; sptr += step, dptr += dst.step )
memcpy( dptr, sptr, len );
}
return;
}
_dst.create( dims, size, type() );
Mat dst = _dst.getMat();
if( data == dst.data )
return;
if( total() != 0 )
{
const Mat* arrays[] = { this, &dst };
uchar* ptrs[2];
NAryMatIterator it(arrays, ptrs, 2);
size_t sz = it.size*elemSize();
for( size_t i = 0; i < it.nplanes; i++, ++it )
memcpy(ptrs[1], ptrs[0], sz);
}
}
void repeat(InputArray _src, int ny, int nx, OutputArray _dst)
{
Mat src = _src.getMat();
CV_Assert( src.dims <= 2 );
CV_Assert( ny > 0 && nx > 0 );
_dst.create(src.rows*ny, src.cols*nx, src.type());
Mat dst = _dst.getMat();
Size ssize = src.size(), dsize = dst.size();
int esz = (int)src.elemSize();
int x, y;
ssize.width *= esz; dsize.width *= esz;
//源数据复制到目标数据区域
for( y = 0; y < ssize.height; y++ )
{
for( x = 0; x < dsize.width; x += ssize.width )
memcpy( dst.data + y*dst.step + x, src.data + y*src.step, ssize.width );
}
// 填充 ssize.height-dsize.height区域
for( ; y < dsize.height; y++ )
memcpy( dst.data + y*dst.step, dst.data + (y - ssize.height)*dst.step, dsize.width );
}