简体   繁体   English

为什么用cv :: Mat(opencv)改变指向数据的指针有cv :: filter2D的问题?

[英]why does changing pointer to data with cv::Mat (opencv) have problems with cv::filter2D?

I want to migrate to using opencv for custom imaging detector data. 我想迁移到使用opencv自定义成像探测器数据。 Datasets can be quite huge (sometime 100's of thousands of frames), and I load them with the boost memory mapping. 数据集可能非常庞大(有时是数千帧的数百帧),我使用boost内存映射加载它们。 When testing out behavior, I create a cv::mat of appropriate size (for a single frame) and change the pointer to data of the frame I am looking at. 在测试行为时,我创建一个适当大小的cv :: mat(对于单个帧)并将指针更改为我正在查看的帧的数据。 This works fine for displaying the data (cv::imshow) or applying a color map, but fails when I use something like cv::filter2D. 这适用于显示数据(cv :: imshow)或应用颜色映射,但是当我使用类似cv :: filter2D的东西时失败。 If I clone the data or use some copy, it works, but I don't want to start copying/cloning because I think this will slow performance (maybe I'm wrong). 如果我克隆数据或使用一些副本,它可以工作,但我不想开始复制/克隆,因为我认为这会降低性能(也许我错了)。

So - what am I doing wrong? 那么 - 我做错了什么? Why doesn't cv::filter2D work here, and is there a better way? 为什么cv :: filter2D不在这里工作,有更好的方法吗?

While running (using Windows 10 right now) I get the following in the terminal: 在运行时(现在使用Windows 10)我在终端中获得以下内容:

OpenCV(4.0.1) Error: Assertion failed (data == datastart + ofs.y*step[0] + ofs.x*esz) in cv::Mat::locateROI, file c:\build\master_winpack-build-win64-vc15\opencv\modules\core\src\matrix.cpp, line 767
OpenCV: terminate handler is called! The last OpenCV error is:
OpenCV(4.0.1) Error: Assertion failed (data == datastart + ofs.y*step[0] + ofs.x*esz) in cv::Mat::locateROI, file c:\build\master_winpack-build-win64-vc15\opencv\modules\core\src\matrix.cpp, line 767

This only happens when filter2D is used with a matrix constructed from the memory mapped array. 仅当filter2D与从内存映射数组构造的矩阵一起使用时才会发生这种情况。

I ran the program with the clone version un-commented and replaced the std::cout line in the loop with: 我使用未注释的克隆版本运行程序,并使用以下代码替换循环中的std :: cout行:

  std::cout<<"Is it continuous: " << img.isContinuous() << std::endl;

And the cv::Mat are indeed continuous. 而cv :: Mat确实是连续的。

#include <QCoreApplication>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>


#include<iostream>
#include <boost/iostreams/device/mapped_file.hpp>


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    boost::iostreams::mapped_file_source mem_ifile;

    mem_ifile.open(std::string("someimage.raw"));
    std::cout<<"file size: "<<mem_ifile.size()/(396*266*sizeof (float))<<std::endl;
    cv::Mat adjMap;
    cv::Mat img(266,396,CV_32FC1);
    cv::Mat falseColorsMap;
    cv::Mat b_hist;
    cv::Mat kernel;
    cv::Mat filsMap;
    kernel = cv::Mat::ones( 2, 2,CV_32FC1)/double(4.0);
    cv::namedWindow("image", cv::WINDOW_NORMAL);
    cv::namedWindow("false color", cv::WINDOW_NORMAL);
    cv::namedWindow("filtered", cv::WINDOW_NORMAL);

    for(unsigned long long i = 0;i< mem_ifile.size()/(396*266*sizeof (float)); i++)
    {
        img.data = (reinterpret_cast<uchar *>(const_cast<char *>(mem_ifile.data()))+(i*396*266*sizeof (float)));
        cv::convertScaleAbs(img, adjMap, 255 / 500.0);
        applyColorMap(adjMap, falseColorsMap, cv::COLORMAP_JET);

// PROBLEM HERE - FIRST TWO WORK, LAST ONE DOESN'T
        //cv::filter2D(adjMap,filsMap,-1,kernel);           // works
        //cv::filter2D(img.clone(),filsMap,-1,kernel);      // works
        cv::filter2D(img,filsMap,-1,kernel);                // doesn't work


        std::cout<<"mean of adjmap: " << cv::mean(adjMap) << std::endl;
        cv::imshow("image", adjMap);
        cv::imshow("false color",falseColorsMap);
        cv::imshow("filtered", filsMap);
        cv::waitKey(20);
    }
    mem_ifile.close();
    return a.exec();
}

Working code based on Beaker's suggestion: 基于Beaker建议的工作代码:


#include <QCoreApplication>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>

#include<iostream>
#include <boost/iostreams/device/mapped_file.hpp>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    boost::iostreams::mapped_file_source mem_ifile;

    mem_ifile.open(std::string("/home/hugh/Documents/APS2017April/Ti7_nr2_e_x36000.raw"));
    std::cout<<"file size: "<<mem_ifile.size()/(396*266*sizeof (float))<<std::endl;
    cv::Mat adjMap;
    cv::Mat *img;
    cv::Mat falseColorsMap;
    cv::Mat b_hist;
    cv::Mat kernel;
    cv::Mat filsMap;
    kernel = cv::Mat::ones( 2, 2,CV_32FC1)/double(4.0);
    cv::namedWindow("image", cv::WINDOW_NORMAL);
    cv::namedWindow("false color", cv::WINDOW_NORMAL);
    cv::namedWindow("filtered", cv::WINDOW_NORMAL);

    for(unsigned long long i = 0;i< mem_ifile.size()/(396*266*sizeof (float)); i++)
    {
        //img.data = (reinterpret_cast<uchar *>(const_cast<char *>(mem_ifile.data()))+(i*396*266*sizeof (float)));
        img = new cv::Mat(266,396,CV_32FC1,(reinterpret_cast<uchar *>(const_cast<char *>(mem_ifile.data()))+(i*396*266*sizeof (float))));

        cv::convertScaleAbs(*img, adjMap, 255 / 500.0);
        applyColorMap(adjMap, falseColorsMap, cv::COLORMAP_JET);

        //cv::filter2D(adjMap,filsMap,-1,kernel);           // works
        //cv::filter2D(img->clone(),filsMap,-1,kernel);      // works
        cv::filter2D(*img,filsMap,-1,kernel);                // works

        std::cout<<"Is it continuous: " << img->isContinuous() << std::endl;
        cv::imshow("image", adjMap);
        cv::imshow("false color",falseColorsMap);
        cv::imshow("filtered", filsMap);
        cv::waitKey(20);
        delete img;
    }
    mem_ifile.close();
    return a.exec();
}

So it looks like you're modifying the data field without updating any of the others. 所以看起来你正在修改data字段而不更新任何其他data字段。 (See Public Attributes .) Specifically, the dataend , datalimit and datastart attributes are identified as (请参阅公共属性 。)具体而言, dataenddatalimitdatastart属性标识为

helper fields used in locateROI and adjustROI locateROI和adjustROI中使用的辅助字段

locateROI being the method given in your error message. locateROI是您的错误消息中给出的方法。

The proper way to do this is to use the cv::Mat data* contructor . 正确的方法是使用cv::Mat 数据*构造函数 As noted in the documentation, 如文档中所述,

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. 此操作非常有效,可用于使用OpenCV函数处理外部数据。

This assures that all of the header data is properly created without unnecessary copying. 这确保正确创建所有标题数据而无需不必要的复制。

Also note that when using these constructors, you should clean up your own data: 另请注意,在使用这些构造函数时,您应该清理自己的数据:

The external data is not automatically deallocated, so you should take care of it. 外部数据不会自动解除分配,因此您应该对其进行处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM