【OpenCV】看看clone和copyTo的源码

结论:

clone代码: mat.inl.hpp

直接调用了copyTo函数,新建了一个临时变量m,返回赋值(地址的头+尺寸)给开发者定义的变量

inline
Mat Mat::clone() const
{
    Mat m;
    copyTo(m);
    return m;
}

copyTo代码:

 /** @brief Copies the matrix to another one.

    The method copies the matrix data to another matrix. Before copying the data, the method invokes :
    @code
        m.create(this->size(), this->type());
    @endcode
    so that the destination matrix is reallocated if needed. While m.copyTo(m); works flawlessly, the
    function does not handle the case of a partial overlap between the source and the destination
    matrices.

    When the operation mask is specified, if the Mat::create call shown above reallocates the matrix,
    the newly allocated matrix is initialized with all zeros before copying the data.
    @param m Destination matrix. If it does not have a proper size or type before the operation, it is
    reallocated.
     */
    void copyTo( OutputArray m ) const;

copyTo详细实现: copy.cpp

void Mat::copyTo( OutputArray _dst ) const
{
    CV_INSTRUMENT_REGION()

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

//GPU版本的Mat转化

 // ................

//维度小于等于2的copyTo
//    ..............

//正常的copyTo

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

可以看到,首先先create了一个同样大小的区块,再利用内存拷贝赋值,关键看看create函数对于一个已经开辟空间Mat的处理

create函数详细实现: 

 

void Mat::create(int d, const int* _sizes, int _type)
{
    int i;
    CV_Assert(0 <= d && d <= CV_MAX_DIM && _sizes);
    _type = CV_MAT_TYPE(_type);

    if( data && (d == dims || (d == 1 && dims <= 2)) && _type == type() )
    {
        if( d == 2 && rows == _sizes[0] && cols == _sizes[1] )
            return;
        for( i = 0; i < d; i++ )
            if( size[i] != _sizes[i] )
                break;
        if( i == d && (d > 1 || size[1] == 1))
            return;
    }

    int _sizes_backup[CV_MAX_DIM]; // #5991
    if (_sizes == (this->size.p))
    {
        for(i = 0; i < d; i++ )
            _sizes_backup[i] = _sizes[i];
        _sizes = _sizes_backup;
    }

    release();
    if( d == 0 )
        return;
    flags = (_type & CV_MAT_TYPE_MASK) | MAGIC_VAL;
    setSize(*this, d, _sizes, 0, true);

    if( total() > 0 )
    {
        MatAllocator *a = allocator, *a0 = getDefaultAllocator();
#ifdef HAVE_TGPU
        if( !a || a == tegra::getAllocator() )
            a = tegra::getAllocator(d, _sizes, _type);
#endif
        if(!a)
            a = a0;
        CV_TRY
        {
            u = a->allocate(dims, size, _type, 0, step.p, 0, USAGE_DEFAULT);
            CV_Assert(u != 0);
        }
        CV_CATCH_ALL
        {
            if(a != a0)
                u = a0->allocate(dims, size, _type, 0, step.p, 0, USAGE_DEFAULT);
            CV_Assert(u != 0);
        }
        CV_Assert( step[dims-1] == (size_t)CV_ELEM_SIZE(flags) );
    }

    addref();
    finalizeHdr(*this);
}

可以看到关键的代码:如果尺寸一致,直接return了

if( dims <= 2 && rows == _rows && cols == _cols && type() == _type && data )
        return;

结论:

1.clone直接调用了copyTo函数,会新建一个临时变量来存储Mat继而再赋值给目标值

2.copyTo如果目标Mat和被复制的Mat的尺寸和类型一致,不会重新开辟空间,直接内存拷贝

所以自然是copyTo更快了……

 

 

测试代码:

#include<opencv2/opencv.hpp>
#include<string>
#include<iostream>
#include<chrono>
using namespace cv;
using namespace std;
using namespace std::chrono;



	
int main() {
	cv::Mat frame = imread("XXX.png", -1);
	cv::Mat cloneMat = frame.clone();
	cv::Mat copyToMat;
	frame.copyTo(copyToMat);
	auto start = steady_clock::now();
	for (int i = 0; i<10000; ++i)
		frame.copyTo(copyToMat);

	auto end = steady_clock::now();
	auto tt = duration_cast<microseconds>(end - start);
	cout << "copyTo 10000次用时:" << tt.count() / 1000 << " 毫秒" << std::endl;;


	start = steady_clock::now();
	for (int i = 0; i<10000; ++i)
		cloneMat = frame.clone();
	end = steady_clock::now();
	tt = duration_cast<microseconds>(end - start);
	cout << "clone 10000次用时:" << tt.count() / 1000 << " 毫秒" << std::endl;

	system("pause");
}

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱铭德

五毛也是爱٩(●´৺`●)૭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值