C ++,使用OpenCV访问冲突来获取像素的RGB值

时间:2010-10-03 21:09:20

标签: c++ image opencv

我正在尝试使用OpenCV来查找图像中像素的RGB值。到目前为止,我尝试了以下内容:

int blue = ((uchar *)(img->imageData + y*img->widthStep))[x*img->nChannels + 0];
int green = ((uchar *)(img->imageData + y*img->widthStep))[x*img->nChannels + 1];
int red = ((uchar *)(img->imageData + y*img->widthStep))[x*img->nChannels + 2];

int blue = ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0];
int green = ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1];
int red = ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2];

CvPoint pt = {5,5};
uchar* temp_ptr = &((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3];
int blue = temp_ptr[0];
int green = temp_ptr[1];
int red = temp_ptr[2];

但是在上述所有情况中,我得到了同样的错误:

Unhandled exception at 0x00f5104f in test.exe: 0xC0000005: Access violation reading location: 0x00000048

最后一个十六进制数(0x0...48)永远不会改变。我看起来这可能是由于写入比数组的边界更远。所以我在没有任何其他代码的情况下单独运行每个示例,仍然会得到相同的错误。导致此错误的原因是什么?如何解决?

额外信息:Windows 7,MSVC 2010 Express,OpenCV 2.1

--UPDATE--

我已经意识到上面的代码比它需要的更复杂,所以我把karlphillip提供的片段(谢谢!)作为基础并使用了类似的方法。我仍然收到错误,这次是在一个更奇怪的地方:

IplImage *slice = cvLoadImage("test.png");
int bpp = slice ->nChannels;

第二行发生错误,仍然是访问冲突。在此之前没有执行与OpenCV相关的代码,只是一些变量初始化。 'test.png'只是一个7 * 7像素'X'我在绘画中用来测试它,使用.jpg有hte saem结果。

为了确保我没有正确安装OpenCV,我使用了这段代码(从下面复制):

int main ()
{
    IplImage* pRGBImg = cvCreateImage(cvSize(5,5),IPL_DEPTH_8U,3);

    int width = pRGBImg->width; 
    int height = pRGBImg->height;
    int bpp = pRGBImg->nChannels; 

    cvNamedWindow("Image view", 1);
    cvShowImage("Image view", pRGBImg);
    cvWaitKey(0);
    cvDestroyWindow("Image view");

    for (int i=0; i < width*height*bpp; i+=bpp) 
    {
      if (!(i % (width*bpp))) // print empty line for better readability
          std::cout << std::endl;

      std::cout << std::dec << "R:" << (int) pRGBImg->imageData[i] <<  
                              " G:" << (int) pRGBImg->imageData[i+1] <<  
                              " B:" << (int) pRGBImg->imageData[i+2] << " "; 
    }
}

这没有返回任何错误,但我确实得到了一些可能奇怪的结果,这里是控制台输出的前几行:

R:13 G:-16 B:-83
R:-70: G:13 B:-16
R:-83 G:-70 B: 13

负RGB值?这是预期的,或者甚至是不起作用。如果这是正常的,那么我正在加载的图像('test.png')必定是问题所在。但是,如果对通道数的简单请求导致访问冲突,我做错了什么?

5 个答案:

答案 0 :(得分:2)

如果不知道图像的大小以及如何循环读取像素,就无法分辨出你做错了什么。很可能你试图超越图像边界(因此,访问冲突)。

无论如何,您可以在代码中添加调试并精确定位触发此错误的确切行。

这是我通常迭代图像像素的方法:

IplImage* pRGBImg = cvLoadImage(input_file.c_str(), CV_LOAD_IMAGE_UNCHANGED); 
int width = pRGBImg->width; 
int height = pRGBImg->height;
int bpp = pRGBImg->nChannels; 
for (int i=0; i < width*height*bpp; i+=bpp) 
{
  if (!(i % (width*bpp))) // print empty line for better readability
      std::cout << std::endl;

  std::cout << std::dec << "R:" << (int) pRGBImg->imageData[i] <<  
                          " G:" << (int) pRGBImg->imageData[i+1] <<  
                          " B:" << (int) pRGBImg->imageData[i+2] << " "; 
}

答案 1 :(得分:1)

问题可能是由

引起的
IplImage *slice = cvLoadImage("test.png");

如果函数失败,变量slice将为NULL,任何进一步的解除引用都将导致访问冲突。

由于opencv的dll可能安装在与正在运行的应用程序不同的路径上,因此建议在调用opencv函数时提供“绝对文件路径”。

尝试将您的示例图片复制到c:\,并将您的代码更改为IplImage *slice = cvLoadImage("c:\\test.png");,我敢打赌它会像魔法一样工作:)

修改

对于您的奇数像素值,可能是由未初始化的内存内容引起的

答案 2 :(得分:0)

尝试简单地表达一下。
获取指针图像数据,然后计算指向该行开始的指针,然后指向像素的指针,然后是R,G,B值

答案 3 :(得分:0)

正如马丁所说,预先计算你的基地址和抵消等内容,这样你就可以更容易地看到发生了什么。这对于指针算法非常重要(例如,如果img-&gt; ImgData不是指向字节大小的数据类型的指针,那么你的指针算法将完全错误。实际上,你似乎正在索引相同的数组(img-&gt; imageData)作为指向uchar的指针和指向float的指针......它是什么?)

另外,检查输入 - 您使用的是24bpp或32bpp的测试图像吗? 'img'是非空的吗? x,y是否在像素宽度和像素高度范围内? widthStep是否合理,并以字节表示?在代码中粘贴大量调试ASSERT,你将消除发生大量简单错误的可能性。

答案 4 :(得分:0)

我使用boost :: shared_ptr创建了一个超级安全的自动垃圾收集,速度非常快,IplImage包装。

图像结构称为blImage,可在以下位置获得: http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/

在那里你可以下载我的blImageAPI并开始玩opencv,而不是出汗关于像素访问。

祝你好运,并享受创建图像算法的乐趣