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 ); }