c++ - 显示 opencv 矩阵时出现内存错误

标签 c++ opencv heap-memory

我创建了一个使用序列化 Opencv 矩阵的类。它工作正常并且 Matrix 被反序列化。如果我尝试使用 imshow 方法在类的方法中显示它,它将工作得很好,显示无误。但是,我将参数引用从我的主函数传递给 Matrix 指针,以便进一步处理该矩阵。当我尝试在主体中显示它时,我最终遇到了段错误。 奇怪的是,如果我尝试在类方法和 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() 以释放分配,仍然是同样的问题。

最佳答案

你的矩阵初始化有问题...具体在这里:

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

那个就是这个构造函数

Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)

documentation 中以下是关于 *data 参数的内容

data Pointer to the user data. Matrix constructors that take data and step parameters do not allocate matrix data. Instead, they just initialize the matrix header that points to the specified data, which means that no data is copied. This operation is very efficient and can be used to process external data using OpenCV functions. The external data is not automatically deallocated, so you should take care of it.

这意味着一旦它超出范围(函数退出),您创建的字符串(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 有足够的空间来接收所有内容解码字节数。要进行此检查,只需确保:

// 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. 注意数据从有符号到无符号的转换/复制,反之亦然 :) 我认为现在它已正确完成,但这可能会在以后成为问题。

关于c++ - 显示 opencv 矩阵时出现内存错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51106101/

相关文章:

c++ - 从 C++ 访问 QML WebView

c++ - 为什么静态成员指针在 ELF 部分为零?

C++ Apache 模块 : Fails on `_ZNSs4_Rep20_S_empty_rep_storageE`

macos - OpenCV - 地球移动器的距离问题,ic​​vInitEMD()

python - 从 PyCharm IDE 运行 Django 项目时出现 "ImportError: No module named cv2"

python - 使用 numpy 进行图像翻译

c++ - 在我的项目中包含 Eigen 将标准 int 重新定义为 Eigen::DenseIndex - 如何使用普通 int?

java - 数组索引超出java堆范围

c++ - 动态二维数组 : int (*ptr)[4] = new int[7][4];

c++ - 我怎么知道我上次的指示