raf*_*010 0 c++ opencv smart-pointers c++11
我编写了一个自定义类来存储图像,并最终基于这些图像计算校准,但是在存储图像的方式上遇到了问题。我有两个重载函数可以执行此操作,一个函数使用读取文件中的图像,另一个函数cv::imread使用Snapshot用于保存数据的中间数据结构。使用函数的cv::imread效果很好,但是使用自定义数据结构的函数却不能。我现在尝试存储三个图像,问题是当我将图像推入矢量时,第二个图像的数据被复制到第一个图像中。
这是工作功能:
bool CalibClass::AddImage(const std::string& snapshotPath) {
cv::Mat img = cv::imread(snapshotPath);
// _snapshots is a private member declared as a std::vector<cv::Mat>
_snapshots.push_back(img);
return true;
}
Run Code Online (Sandbox Code Playgroud)
这是不起作用的功能:
bool CalibClass::AddImage(const ImageSet& snapshot) {
RGBImage *rgb_image_ptr = snapshot.GetRGBImage();
std::vector<unsigned char> img_data(rgb_image_ptr->GetData());
cv::Mat img(rgb_image_ptr->GetHeight(), rgb_image_ptr->GetWidth(), CV_8UC3, img_data.data());
_snapshots.push_back(img);
return true;
}
Run Code Online (Sandbox Code Playgroud)
在ImageSet类存储图像作为std::unique_ptr<RGBImage>。在RGBImage类存储的图像数据作为std::vector<unsigned char>。
这是将图像从中加载到类中的方式main:
cv::Mat img1 = cv::imread("img1.png");
cv::Mat img2 = cv::imread("img2.png");
cv::Mat img3 = cv::imread("img3.png");
int length = img1.total() * img1.elemSize();
std::vector<unsigned char> data1;
std::vector<unsigned char> data2;
std::vector<unsigned char> data3;
for (int i = 0; i < length; i++) {
data1.push_back(img1.data[i]);
}
for (int i = 0; i < length; i++) {
data2.push_back(img2.data[i]);
}
for (int i = 0; i < length; i++) {
data3.push_back(img3.data[i]);
}
CalibClass calib_test;
std::unique_ptr<RGBImage> rgb_image_ptr1(new RGBImage(img1.rows, img1.cols, data1));
ImageSet new_snap1(rgb_image_ptr1, nullptr, 0);
calib_test.AddImage(new_snap1);
std::unique_ptr<RGBImage> rgb_image_ptr2(new RGBImage(img2.rows, img2.cols, data2));
ImageSet new_snap2(rgb_image_ptr2, nullptr, 0);
calib_test.AddImage(new_snap2);
std::unique_ptr<RGBImage> rgb_image_ptr3(new RGBImage(img3.rows, img3.cols, data3));
ImageSet new_snap3(rgb_image_ptr3, nullptr, 0);
calib_test.AddImage(new_snap3);
Run Code Online (Sandbox Code Playgroud)
当我在函数中放置一个断点并检查的内容时_snapshots,第一个元素是第二个图像,第二个和第三个元素是第三个图像。当我在所有AddImage()调用之后都设置一个断点时,的内容_snapshots将第二个图像作为第一个元素,将第三个图像作为第二个元素,而第三个元素将cv::Mat包含无效数据。
两种方法存储图像的方式不同的原因是什么?解决该问题的方法是什么?
这些症状听起来很像是在进行浅表复制,这意味着第二种方法中的不确定行为,因为cv::Mat向量中的生存时间更长img_data。让我看看是否可以找到您使用的构造函数的文档。
在这里找到它。是的,它做了一个浅表副本(添加了强调):
带有数据和步骤参数的矩阵构造函数不分配矩阵数据。相反,他们只是初始化指向指定数据的矩阵头,这意味着没有数据被复制。
因此,当第二种方法将图像压入时_snapshots,该图像的数据将存储在局部变量中img_data。然后函数结束,使该数据无效。因此,当您查看数据时,您将获得未定义的行为。
为了解决这个问题,您需要确保复制了数据。您还希望确保在某些时候释放数据以避免内存泄漏。一种方法是定义一个类,该类由cv::Mat和组成,用于存储数据,也许是std::vector<unsigned char>。(使用后一个成员而不是局部变量img_data。)起始点可能如下:
class MatWrapper {
public:
explicit MatWrapper(const RGBImage & rgb_image) :
data(rgb_image.GetData()),
image(rgb_image.GetHeight(), rgb_image.GetWidth(), CV_8UC3, data.data())
{}
private:
std::vector<unsigned char> data; // Declaration order matters!
cv::Mat image;
};
Run Code Online (Sandbox Code Playgroud)