[英]why does changing pointer to data with cv::Mat (opencv) have problems with cv::filter2D?
我想遷移到使用opencv自定義成像探測器數據。 數據集可能非常龐大(有時是數千幀的數百幀),我使用boost內存映射加載它們。 在測試行為時,我創建一個適當大小的cv :: mat(對於單個幀)並將指針更改為我正在查看的幀的數據。 這適用於顯示數據(cv :: imshow)或應用顏色映射,但是當我使用類似cv :: filter2D的東西時失敗。 如果我克隆數據或使用一些副本,它可以工作,但我不想開始復制/克隆,因為我認為這會降低性能(也許我錯了)。
那么 - 我做錯了什么? 為什么cv :: filter2D不在這里工作,有更好的方法嗎?
在運行時(現在使用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
僅當filter2D與從內存映射數組構造的矩陣一起使用時才會發生這種情況。
我使用未注釋的克隆版本運行程序,並使用以下代碼替換循環中的std :: cout行:
std::cout<<"Is it continuous: " << img.isContinuous() << std::endl;
而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();
}
基於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();
}
所以看起來你正在修改data
字段而不更新任何其他data
字段。 (請參閱公共屬性 。)具體而言, dataend
, datalimit
和datastart
屬性標識為
locateROI和adjustROI中使用的輔助字段
locateROI
是您的錯誤消息中給出的方法。
正確的方法是使用cv::Mat
數據*構造函數 。 如文檔中所述,
采用數據和步驟參數的矩陣構造函數不分配矩陣數據。 相反,它們只是初始化指向指定數據的矩陣標頭,這意味着不會復制任何數據。 此操作非常有效,可用於使用OpenCV函數處理外部數據。
這確保正確創建所有標題數據而無需不必要的復制。
另請注意,在使用這些構造函數時,您應該清理自己的數據:
外部數據不會自動解除分配,因此您應該對其進行處理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.