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< /COD> < /P> < P>所有OpenCV函数都期望<代码> CV::MAT::数据< /代码>是空洞*,所以你不能改变它。如果从
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
}