我正在尝试使用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')必定是问题所在。但是,如果对通道数的简单请求导致访问冲突,我做错了什么?
答案 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,而不是出汗关于像素访问。
祝你好运,并享受创建图像算法的乐趣