OpenCV深拷贝效率对比

使用成员变量 作为CopyTo 的目标Mat

通过其他char* data 构造的Mat,需要考虑使用copyTo 或者clone。因为Mat只是浅拷贝,指向的数据还是原来的数据,如果原来的数据被释放了,那么Mat就会指向一个无效的数据,导致内存错误。这里主要对比OpenCV中不同深拷贝方式的效率。
clone 和 copyTo 的区别。

  • clone 会重新分配内存,然后拷贝数据
  • copyTo 是否申请新的内存空间,取决于dst矩阵头中的大小信息是否与src一至,若一致则只深拷贝并不申请新的空间,否则先申请空间后再进行拷贝。

在视频帧处理中,大部分情况下,视频帧的大小都是不会变化的,所以可以考虑使用成员变量作为copyTo的目标Mat,这样可以减少内存的分配和释放,提高效率。
例如:

// 此处的 ptr指向了真正的数据,这里必须拷贝一份数据,否则ptr指向的数据会被释放
cv::Mat frame;
frame = cv::Mat(m_format.height * 3/2, m_format.width, CV_8UC1, ptr, pitch);
cv::Mat newFrame = frame.clone();

可以改为:

// 使用成员变量作为copyTo的目标Mat
cv::Mat(m_format.height * 3/2, m_format.width, CV_8UC1, ptr, pitch).copyTo(m_newFrame);

耗时对比:

frame2              = frame.clone() : 516us
frameCopyToGlobal   = frame.clone() : 706us
frame.copyTo(frameCopyToGlobal)     : 155us
frame.copyTo(frame3)                : 566us

frameCopyToGlobal = frame.clone() 这种写法耗时最长,是因为除了clone 之外,还需要把上一次frameCopyToGlobal中的数据先释放掉,然后再重新分配内存,再拷贝数据。
frame.copyTo(frameCopyToGlobal) 这种写法耗时最短,因为frameCopyToGlobal已经分配了内存,只需要拷贝数据即可。

使用成员变量作为resize, cvtColor的目标Mat

这一类的函数,都会调用_dst.create(dsize, src.type());生成一个_dst,当_dst是成员变量并且大小和类型和 src相同时,可以减少内存的分配和释放,提高效率。同时也避免了临时变量的生成,拷贝,释放的过程。

void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
                 double inv_scale_x, double inv_scale_y, int interpolation )
{
    CV_INSTRUMENT_REGION();

    Size ssize = _src.size();

    CV_Assert( !ssize.empty() );
    if( dsize.empty() )
    {
        CV_Assert(inv_scale_x > 0); CV_Assert(inv_scale_y > 0);
        dsize = Size(saturate_cast<int>(ssize.width*inv_scale_x),
                     saturate_cast<int>(ssize.height*inv_scale_y));
        CV_Assert( !dsize.empty() );
    }
    else
    {
        inv_scale_x = (double)dsize.width/ssize.width;
        inv_scale_y = (double)dsize.height/ssize.height;
        CV_Assert(inv_scale_x > 0); CV_Assert(inv_scale_y > 0);
    }

    if (interpolation == INTER_LINEAR_EXACT && (_src.depth() == CV_32F || _src.depth() == CV_64F))
        interpolation = INTER_LINEAR; // If depth isn't supported fallback to generic resize

    CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat() && _src.cols() > 10 && _src.rows() > 10,
               ocl_resize(_src, _dst, dsize, inv_scale_x, inv_scale_y, interpolation))

    // Fake reference to source. Resolves issue 13577 in case of src == dst.
    UMat srcUMat;
    if (_src.isUMat())
        srcUMat = _src.getUMat();

    Mat src = _src.getMat();
    _dst.create(dsize, src.type());
    Mat dst = _dst.getMat();

    if (dsize == ssize)
    {
        // Source and destination are of same size. Use simple copy.
        src.copyTo(dst);
        return;
    }

    hal::resize(src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows, inv_scale_x, inv_scale_y, interpolation);
}

操作720P resieze到1080P 在release 重复100次的测试结果:

resizeToLocalFrame : 940us            resizeToToGlobal: 521us
resizeToLocalFrame : 972us            resizeToToGlobal: 541us
resizeToLocalFrame : 977us            resizeToToGlobal: 537us
resizeToLocalFrame : 995us            resizeToToGlobal: 560us
resizeToLocalFrame : 993us            resizeToToGlobal: 552us
resizeToLocalFrame : 977us            resizeToToGlobal: 540us
resizeToLocalFrame : 963us            resizeToToGlobal: 551us

cvtColor的测试结果

cvtColorframe2 : 446us            cvtColorToGlobal: 119us
cvtColorframe2 : 436us            cvtColorToGlobal: 115us
cvtColorframe2 : 464us            cvtColorToGlobal: 117us
cvtColorframe2 : 461us            cvtColorToGlobal: 122us
cvtColorframe2 : 440us            cvtColorToGlobal: 122us

在取子图时,使用copyTo 构造新的Mat

这种情况一般出现在跨语言调用,比如C#的Mat 传入c++的算法SDK中,或者需要网络传输帧的时候。如果直接不拷贝可能造成读取的图片花屏。

cv::Mat frame = src(cv::Rect(0,,0,100,100));
cv::Mat newFrame(100,100, frame.type(), frame.data);            // x
newFrame(100,100, frame.type(), frame.data).copyTo(newFrame)    // √
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值