C++ cv::Mat从外部原始指针数据中释放自身
有没有办法从外部数据指针创建C++ cv::Mat从外部原始指针数据中释放自身,c++,opencv,C++,Opencv,有没有办法从外部数据指针创建cv::Mat,但让该对象负责删除数据 i、 例如,我有一个函数从void*指针创建cv::Mat cv::Mat createMat() { void *data = (...); cv::Mat data_m(rows, cols, CV_8UC1, data); return data_m; } 我希望我返回的cv::Mat负责发布数据。我如何才能做到这一点?您使用的智能指针实际上拥有数据。您希望将此所有权转移到另一个智能指针,即cv::Mat
cv::Mat
,但让该对象负责删除数据
i、 例如,我有一个函数从void*
指针创建cv::Mat
cv::Mat createMat() {
void *data = (...);
cv::Mat data_m(rows, cols, CV_8UC1, data);
return data_m;
}
我希望我返回的
cv::Mat
负责发布数据。我如何才能做到这一点?您使用的智能指针实际上拥有数据。您希望将此所有权转移到另一个智能指针,即cv::Mat
(cv::Mat
是一种智能指针)。这是不可能的,因为C++智能指针与cv::Mat
继承并编写自己的析构函数,则与OpenCV不兼容,因为它们不返回派生类型。
我建议将您的cv::Mat
作为类的属性,并保留一个std::shared_ptr
或其他智能指针来管理基础void*
的生命周期。
只需使用std::shared\u ptr::get()
并确保它们具有相同的生存期,即在同一类中。我提出了一个类似于的解决方案。但是,不能使用
std::shared\u ptr::get()
初始化Mat
,因为它需要void*
,而不是const void*
实际上,您继承了cv::Mat
,并保留了数据的共享\u ptr
。一旦内存超出范围,这将释放内存
#include <opencv2\opencv.hpp>
#include <memory>
using namespace cv;
using namespace std;
struct SelfDeallocMat : cv::Mat
{
shared_ptr<void> pdata;
SelfDeallocMat(int rows, int cols, int type, void* data, size_t step = 0U)
: Mat(rows, cols, type, data, step), pdata(data) {};
};
int main()
{
uchar* pdata = new uchar[3];
pdata[0] = 1;
pdata[1] = 2;
pdata[2] = 3;
for (int i = 0; i < 3; ++i) {cout << int(pdata[i]) << " "; }
cout << endl;
{
SelfDeallocMat m(1, 3, CV_8UC1, (void*)pdata);
cout << m << endl;
}
// Some garbage values
for (int i = 0; i < 3; ++i) { cout << int(pdata[i]) << " "; }
cout << endl;
return 0;
}
我看到了两种解决方案,可以在不必派生到cv::Mat的情况下实现您想要的功能 最简单的方法是调用
std::vector
std::vector<what_type_you_want> data = {a,b,c,d,thank_you_cpp_eleven_for_the_initializer_list};
// If you are a memory size maniac.
data.shrink_to_fit();
cv::Mat data_m(rows,cols,type_with_or_without_channels,data.data()/*you don't need to do a reinterpret_cast<void*> it work as is*/,data.size()/*not needed*/);
你为什么要这么做?是谁创建数据来放松它不是更好吗?我认为不是。Mat只释放它拥有的数据。你为什么一开始就想要这种行为?是不是最好将数据复制到mat中,然后释放
数据
,我想拥有这些数据,但不想让用户负责在简历中释放这些数据:Mat@Miki我想避免不成功地复制数据这是一个有趣的解决方案,这就是我最后要做的。非常感谢。
std::vector<what_type_you_want> data = {a,b,c,d,thank_you_cpp_eleven_for_the_initializer_list};
// If you are a memory size maniac.
data.shrink_to_fit();
cv::Mat data_m(rows,cols,type_with_or_without_channels,data.data()/*you don't need to do a reinterpret_cast<void*> it work as is*/,data.size()/*not needed*/);
#include <opencv2/core.hpp>
#include <iostream>
#include <cstdlib>
namespace
{
class MyMatAllocator : public cv::MatAllocator
{
public:
cv::UMatData* allocate(int dims, const int* sizes, int type,
void* data0, size_t* step, int /*flags*/, cv::UMatUsageFlags /*usageFlags*/) const
{
std::cout<<"I am call"<<std::endl;
size_t total = CV_ELEM_SIZE(type);
for( int i = dims-1; i >= 0; i-- )
{
if( step )
{
if( data0 && step[i] != CV_AUTOSTEP )
{
CV_Assert(total <= step[i]);
total = step[i];
}
else
step[i] = total;
}
total *= sizes[i];
}
uchar* data = data0 ? (uchar*)data0 : (uchar*)cv::fastMalloc(total);
cv::UMatData* u = new cv::UMatData(this);
u->data = u->origdata = data;
u->size = total;
// if(data0)
// u->flags |= cv::UMatData::USER_ALLOCATED;
return u;
}
bool allocate(cv::UMatData* u, int /*accessFlags*/, cv::UMatUsageFlags /*usageFlags*/) const
{
if(!u) return false;
return true;
}
void deallocate(cv::UMatData* u) const
{
if(!u)
return;
CV_Assert(u->urefcount == 0);
CV_Assert(u->refcount == 0);
// if( !(u->flags & cv::UMatData::USER_ALLOCATED) )
// {
std::cout<<"deallocation"<<std::endl;
cv::fastFree(u->origdata);
u->origdata = 0;
// }
delete u;
}
};
void create(cv::Mat& obj,int d, const int* _sizes, int _type,void* p)
{
int i;
CV_Assert(0 <= d && d <= CV_MAX_DIM && _sizes);
_type = CV_MAT_TYPE(_type);
if( obj.data && (d == obj.dims || (d == 1 && obj.dims <= 2)) && _type == obj.type() )
{
if( d == 2 && obj.rows == _sizes[0] && obj.cols == _sizes[1] )
return;
for( i = 0; i < d; i++ )
if( obj.size[i] != _sizes[i] )
break;
if( i == d && (d > 1 || obj.size[1] == 1))
return;
}
obj.release();
if( d == 0 )
return;
obj.flags = (_type & CV_MAT_TYPE_MASK) | cv::Mat::MAGIC_VAL;
// setSize(*this, d, _sizes, 0, true);
CV_Assert( 0 <= d && d <= CV_MAX_DIM );
if( obj.dims != d )
{
if( obj.step.p != obj.step.buf )
{
cv::fastFree(obj.step.p);
obj.step.p = obj.step.buf;
obj.size.p = &obj.rows;
}
if( d > 2 )
{
obj.step.p = (size_t*)cv::fastMalloc(d*sizeof(obj.step.p[0]) + (d+1)*sizeof(obj.size.p[0]));
obj.size.p = (int*)(obj.step.p + d) + 1;
obj.size.p[-1] = d;
obj.rows = obj.cols = -1;
}
}
obj.dims = d;
if( !_sizes )
return;
size_t esz = CV_ELEM_SIZE(obj.flags), esz1 = CV_ELEM_SIZE1(obj.flags), total = esz;
for( i = d-1; i >= 0; i-- )
{
int s = _sizes[i];
CV_Assert( s >= 0 );
obj.size.p[i] = s;
obj.step.p[i] = total;
int64 total1 = (int64)total*s;
if( (uint64)total1 != (size_t)total1 )
CV_Error( CV_StsOutOfRange, "The total matrix size does not fit to \"size_t\" type" );
total = (size_t)total1;
}
if( d == 1 )
{
obj.dims = 2;
obj.cols = 1;
obj.step[1] = esz;
}
if( obj.total() > 0 )
{
cv::MatAllocator *a = new MyMatAllocator();
obj.u = a->allocate(obj.dims, obj.size.p, _type, p, obj.step.p, 0, cv::USAGE_DEFAULT);
CV_Assert(obj.u != 0);
CV_Assert( obj.step[obj.dims-1] == (size_t)CV_ELEM_SIZE(obj.flags) );
}
obj.addref();
int j;
for( i = 0; i < obj.dims; i++ )
{
if( obj.size[i] > 1 )
break;
}
for( j = obj.dims-1; j > i; j-- )
{
if( obj.step[j]*obj.size[j] < obj.step[j-1] )
break;
}
uint64 t = (uint64)obj.step[0]*obj.size[0];
if( j <= i && t == (size_t)t )
obj.flags |= cv::Mat::CONTINUOUS_FLAG;
else
obj.flags &= ~cv::Mat::CONTINUOUS_FLAG;
d = obj.dims;
if( d > 2 )
obj.rows = obj.cols = -1;
if(obj.u)
obj.datastart = obj.data = obj.u->data;
if( obj.data )
{
obj.datalimit = obj.datastart + obj.size[0]*obj.step[0];
if( obj.size[0] > 0 )
{
obj.dataend = obj.ptr() + obj.size[d-1]*obj.step[d-1];
for( int i = 0; i < d-1; i++ )
obj.dataend += (obj.size[i] - 1)*obj.step[i];
}
else
obj.dataend = obj.datalimit;
}
else
obj.dataend = obj.datalimit = 0;
}
void create(cv::Mat& obj, const int& rows,const int& cols, int _type,void* p)
{
const int sizes[2] = {rows,cols};
create(obj,2,sizes,_type,p);
}
}
int main(int argc,char* argv[])
{
uchar* toto = new uchar[10];
std::iota(toto,toto+10,1);
cv::Mat a;
create(a,1,10,CV_8UC1,toto);
return EXIT_SUCCESS
}