【问题标题】:Cannot access IplImage data无法访问 IplImage 数据
【发布时间】:2013-01-31 15:51:32
【问题描述】:

我一直在尝试比较 IplImage 对象中的数据内容。

我有以下:

   IplImage img1 = IplImage(cv::imread("C:\\TestIm\\barrier_snapshot1.png"),            
                                                   CV_LOAD_IMAGE_GRAYSCALE);
   for (int i=0; i < img1.widthStep * img1.height; i++) {
       cout << img1.imageData[i] << endl;
   }

但是当我尝试打印它时,它会导致异常,我什至无法捕获它来打印消息并查看我做错了什么。我的图像是灰度的,我相信如果我不使用 cvCreateImage() 可以吗?我知道这将是一些愚蠢的或与数组访问相关的事情,我似乎无法从 IplImage 文档中轻松获得。

*我为什么要在我的设计中混合使用 C 和 C++ 代码? *

很遗憾,我别无选择!我正在开发一个具有改进的运动检测应用程序的项目。我的遗留应用程序源代码使用大量的 BOOST 和 OpenCV 东西。特别是,它使用 IplImage*(我讨厌它,让生活变得困难并导致内存泄漏)来存储图像掩码之类的东西。我了解如果我长期保存 IplImage*,我将遇到非法引用和访问冲突。所以我保存了 IplImage* 指向的实际内容的副本。举例:

// getLongHistory() returns IplImage*
IplImage history_long = *(motionHistory.getLongHistory()); 

共有 6 个使用 IplImage* 制作的蒙版图像。此时此刻,我在谴责决定在 IplImage* 中这样做的程序员。当我尝试加载这些蒙版图像时会出现问题,我就是这样做的:

// Passing pointer to the address of the mask stored (alive in the memory)
motionHistory.setLongHistory(&(matcher.getCurrentSceneObject().getLongHistory()));

我认为 IplImage 对象的深拷贝和浅拷贝存在问题。我相信将其保存为 IplImage* 中的 cv::Mat 并从 cv::Mat 中将其加载为 IplImage* 可能会减轻负担,因为我怀疑它可能在高级功能下执行 SOMETHING 所以相应地完成数据和 ROI 的复制。但是,作为一个新手,我可以假设任何事情。请帮忙!

更新

在我的代码中,我过去是这样做的:

/* I store all my mask images in a vector of pairs made of <int, IplImage>
 * __MASK_LONG__ etc. are predefined intergers
 * getMaskLong() etc. methods return IplImage* to the respective mask images.
 */

  myImages.clear(); // To make sure that I have no extra stuff
  myImages.push_back(std::make_pair<int, IplImage>(_MASK_LONG_, maskHistory.getMaskLong()));
  myImages.push_back(std::make_pair<int, IplImage>(_MASK_SHORT_, maskHistory.getMaskShort()));

但是,在得到建议并进行了一些基本的 R&A 之后,我现在这样做是为了防止浅拷贝:

  myImages.clear(); 
  myImages.push_back(std::make_pair<int, IplImage>(_MASK_LONG_, *cvCloneImage(maskHistory.getMaskLong())));
  myImages.push_back(std::make_pair<int, IplImage>(_MASK_SHORT_, *cvCloneImage(maskHistory.getMaskShort())));

我可以确认这是可行的,因为我可以看到 OpenCV 窗口上加载了最新的蒙版图像!而且我很确定在任何编程任务中至少进行 2/3 次深度复制是多么重要。所以感谢你让我走上正轨。但是现在我遇到了在实施这些更改时想到的问题 - 内存分配失败。并且遇到了消息:

OpenCV Error: Insufficient memory (Failed to allocate 3686404 bytes) in OutOfMemoryError, 
file /home/naresh/OpenCV-2.4.0/modules/core/src/alloc.cpp, line 52

如果我对 C/C++ 有足够的了解,首先我犯了将它们混合在一起的罪行(我别无选择!这是一个遗留应用程序!)。其次,存在不匹配,即 alloc.cpp 文件中对 malloc/free 的调用不正确(产生问题的地方)。或者可能只是堆已损坏或已满。我是不是很傻?

【问题讨论】:

  • 你有什么理由不使用 C++ API 而不是 C API?使用 cv::Mat 而不是 IplImage 让您的生活变得更加轻松。
  • @IanMedeiros 我知道有人会为此责骂我!!!不幸的是,是的,我愿意!请查看我更新的问题描述!!!
  • 说真的,我完全可以理解渴望避免矩阵的深拷贝,但是使用返回指向 IplImages 的指针的方法会因访问冲突和内存泄漏而尖叫。 cv::Mat 复制构造函数、赋值运算符和析构函数的实现方式已经避免了数据的深拷贝。如果有任何计划长时间处理此代码,我会认真考虑进行一些重构。
  • 让我烦恼的另一件事是您能够构造一个接收 cv::Mat 作为参数的 IplImage。
  • @IanMedeiros Ian 也烦我!但无论如何它都有效!我现在有更多的问题。查看更新!

标签: c++ c pointers opencv iplimage


【解决方案1】:

不要混合OpenCV的C接口和C++接口。

理想情况下,您可以通过专门使用 C++ 接口来解决问题,如下所示:

cv::Mat gray = cv::imread("C:\\TestIm\\barrier_snapshot1.png", CV_LOAD_IMAGE_GRAYSCALE);

cv::Mat_<uchar>::iterator it = gray.begin<uchar>();
cv::Mat_<uchar>::iterator end = gray.end<uchar>();
for (; it != end; ++it)
{
    cout << *it << endl;        
}

或者:

cv::Mat gray = cv::imread("C:\\TestIm\\barrier_snapshot1.png", CV_LOAD_IMAGE_GRAYSCALE);

for (int i = 0; i < gray.cols; i++)
{
    for (int j = 0; j < gray.rows; j++)
    {
        cout << gray[gray.cols * j + i] << endl;
    }
}

是的,cv::imread() 也可以将输入图像加载为灰度。但是如果你真的需要坚持使用 C 接口,那么放弃cv::imread() 并改用cvLoadImage()。有几篇文章解释了如何做到这一点,请使用搜索框

如果您决定继续混合接口(请不要),check this thread 因为它解释了如何将IplImage* 转换为cv::Mat

【讨论】:

  • 谢谢你……我知道我的问题可能是一个非常古老但在 C/C++ 中最令人恐惧的问题之一,我有点想通了;深浅复制。问题是我有一个非常大的图像处理(运动检测)应用程序,它使用 Boost 和 OpenCV 库。为处理运动检测算法而编写的遗留代码大量使用 IplImage*。请检查我的问题描述,因为我已经对其进行了一些更新,以让用户知道我在哪里遇到了问题......我非常感谢你的帮助,我投票支持你:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-12
相关资源
最近更新 更多