显示OpenCV矩阵时出现内存错误

时间:2018-06-29 16:36:27

标签: c++ opencv heap-memory

我制作了一个使用序列化Opencv矩阵的类。它工作正常,并且Matrix已反序列化。如果我尝试使用imshow方法在类的方法中显示它,它将很好地工作,并且显示没有错误。但是,我正在将参数引用从我的主函数传递给Matrix指针,以便进一步处理此矩阵。当我尝试将其主要显示时,我遇到了分段错误。 怪异的部分是,如果我尝试在class方法和Main方法中都显示矩阵,则最终会出现两个窗口正常运行的情况(有时会出现分段错误,但大多数情况下它运行良好)。 如果我从方法中删除显示代码,在出现分割错误之前,我什至无法显示一帧。

我尝试使用shared_ptr,将指针传递给指针而不是引用,甚至只是返回值。 我的代码有点凌乱,但它的主要目的是测试。

这是该方法的代码:

void VideoConsumer::getVideoFrame(cv::Mat* &mat) {
    Message msg = _consumer->poll();
    mat = NULL;
    if(!msg) {
        cerr << "No message received" << endl;
        return;
    }
    if(msg.get_error()) {
        if(!msg.is_eof()) {
            cerr << "[+] Received error notification: " << msg.get_error() << endl;
        }
        return;
    }

    Document document;
    string jsonPayload = "";
    for(auto i=msg.get_payload().begin(); i != msg.get_payload().end();i++) {
        jsonPayload += *i;
    }


    document.Parse(jsonPayload.c_str());
    if(document.HasMember("rows") && document.HasMember("cols") && document.HasMember("data")) {
        int rows = document["rows"].GetInt();
        int cols = document["cols"].GetInt();
        int type = document["type"].GetInt();
        string data = document["data"].GetString();
        std::vector<BYTE> decodedBytes = base64_decode(data);

        stringstream ss;
        for(int i=0;i< decodedBytes.size(); i++) {
            ss << decodedBytes[i];
        }
        string decoded_data = ss.str();
        cout << "Constructed string" << endl;
        mat = new cv::Mat(rows,cols,type,(void *)decoded_data.data());
        /*cv::imshow("test",*mat);
        while(cv::waitKey(10) != 27)*/ //This is where it is displayed
        return;
    } else {
        return;
    }  

}

以及主代码:

 ...
if(parser.has("stream")) {
      VideoConsumer consumer("localhost:9092","video-stream-topic","testId2");
      consumer.setConsumer();

      while(1) {
        Mat *frame = NULL;
        consumer.getVideoFrame(frame);
        if(frame == NULL) {
          cout << "Null frame" << endl; 
          continue;
        }
        if(!frame->empty() && frame->rows > 0 && frame->cols > 0) {
          imshow("Test",*frame);
          waitKey(10);
          frame->release();
        }

      }
    }

我完全没有想法,尝试过我在研究中知道或发现的每件事。

编辑:添加了frame-> release()以释放分配,仍然是同样的问题。

1 个答案:

答案 0 :(得分:2)

您的矩阵初始化中有一个问题...具体在这里:

mat = new cv::Mat(rows,cols,type,(void *)decoded_data.data());

就是那个构造函数

  

垫子(整数行,整数列,整数类型,无效*数据,size_t步= AUTO_STEP)

documentation中,有关* data参数的内容如下

  

数据指向用户数据的指针。接受数据和   步骤参数不分配矩阵数据。相反,他们只是   初始化指向指定数据的矩阵头,   表示没有数据被复制。此操作非常有效,可以   用于使用OpenCV函数处理外部数据。外部   数据不会自动释放,因此您应该注意这一点。

这意味着,一旦超出范围(函数退出),您创建的字符串(decoded_data)将退出,数据将被该字符串释放,然后您的cv :: Mat将引用不再有效的数据...

您始终可以使用

之类的东西来初始化矩阵。
cv::Mat(rows,cols,type)

,然后使用类似std :: memcpy之类的东西将数据复制到mat.data成员。实际上,AFAIK不需要将字节传递给字符串,然后传递给mat,后者先转换为void,再传递给uchar。...

尝试类似的东西:

mat  = cv::Mat(rows,cols,type);
std::memcpy(&decodedBytes[0], mat.data, decodedBytes.size());

对于此解决方案而言,这只是一个小警告,您需要检查decodedBytes是否不为空,并且mat.data是否有足够的空间来容纳decodedBytes的所有内容。要执行此检查,只需确保:

// size in bytes to copy  ==  size of the allocated data of mat in bytes
decodedBytes.size() == (mat.elemSize() * mat.rows * mat.cols)

还有几句话可能现在不是问题,但稍后可能会咬你:

  1. 请勿使用cv :: Mat指针... cv :: Mat的行为已经像是智能指针。
  2. 当心从符号到取消符号以及反之亦然的数据转换/复制:)我认为现在正确完成了,但是以后可能会成为问题。