views:

151

answers:

5

I'm trying to use OpenCV to find the RGB values of a pixel in an image. so far I've tried the following:

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];

But in all of the above, I get the same error:

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

The last hex number (0x0...48) never changes. I looks like this can be caused by writing further than the bounds of an array. So I've run each of the examples in isolation without any other code at all, and still get the same error. What is causing this error and how can I fix it?

Extra info: Windows 7, MSVC 2010 Express, OpenCV 2.1

--UPDATE--

I've realised the above code is more compicated than it needs to be, so I took the snippet provided by karlphillip (thanks!) as a base and used a similar method. I'm still getting an error, and this time in an even stranger place:

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

The error occurs on the second line, and is still an Access Violation. There is no code executed before this to do with OpenCV, just some variable initializations. 'test.png' is just a 7*7 pixel 'X' I made in paint to test this out, using a .jpg has hte saem result.

To make sure I hadn't installed OpenCV improperly, I used this code (copied from below) in isolation:

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] << " "; 
    }
}

This didn't return any errors, but I did get some possibly strange results, here are the first few lines of console output:

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

Negative RGB values? Is this to be expected, or is even this not working. If it is normal, then the image I'm loading ('test.png') must be the problem. But, what am I doing wrong if a simple request for the number of channels causes an access violation?

A: 

Try simplyfing the expression a little.
Get a pointer the image data, then calculate a pointer to the start of that row, then a pointer to the pixel, then the R,G,B values

Martin Beckett
+1  A: 

Without knowing the size of the image and how you are looping through it to read its pixels, its impossible to tell what you are doing wrong. Most probably you are trying to read beyond the image boundaries (therefore, access violation).

Anyway, you could add debugs to your code and pinpoint the exact line that triggers this error.

This is how I usually do to iterate through the pixels of an image:

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] << " "; 
}
karlphillip
Thanks for the code, it made me realise that my method was far more complicated than it needed to be, and inspired me to actually figure out what it does. I tried to use a modified version of (int) img->imageData[i] to find the RGB values, but I still ran into a Access Violation. So to see whether I had possibly screwed up the installation, I copy/pasted your code and it works (no errors) but with possibly strange results. I've updated the question with more info
JBenson
@JBenson Sure, no problem. Don't forget to upvote if it helped you somehow.
karlphillip
I would, but I've only got 8 rep )-: I'll put it on my todo list once I finally get to 15. Note: answer was a tossup between you and YeenFei, but since he/she has less rep I figure he needs it more :-)
JBenson
A: 

As Martin says, precalculate things like your base addresses and offsets so you can more easily see what is going on. This is very important with pointer arithmetic (e.g. if img->ImgData is not a pointer to a byte-sized data type, your pointer arithmetic will be entirely wrong. Indeed, you appear to be indexing the same array (img->imageData) as both a pointer to uchar and a pointer to float...what is it?)

Also, check the inputs - Are you using a 24bpp or 32bpp test image? Is 'img' non-null? Are x,y coming in within the pixel-width and pixel-height ranges? Is widthStep sane, and expressed in terms of bytes? Stick lots of debugging ASSERTs in your code and you'll eliminate the possibility of a lot of simple errors occurring.

Jason Williams
+1  A: 

The problem probably caused by

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

if the function failed, variable slice will be NULL, and any further dereferencing will leads to access violation.

Since opencv's dll may be installed on different path than your running application, it is advisable to provide "absolute file path" when calling opencv's function.

Try copy your sample image to c:\, and change your code into IplImage *slice = cvLoadImage("c:\\test.png");, I'd bet it will work like magic :)

Edit:

For your odd pixel values, it might caused by uninitialized memory contents

YeenFei
You, good sir/madam, are my hero! Works like a charm :-) On a side-note, what are/is "uninitialized memory contents"?
JBenson
the API cvCreateImage only responsible for allocating chunk of memory to be used as image buffer. Since there is no hint on what value should the pixels start with, they are left in their uninitialize/previous/undetermined state.
YeenFei
Ah, that makes sense. I'm still running in to this problem, is there a fix for this? Perhaps some function that allocates the first pixel to the start of hte memory?
JBenson
you can use cvZero() to set all pixels into 0.
YeenFei
A: 

I have created a super safe, automatic garbage collection, very fast, IplImage wrapper using boost::shared_ptr.

The image structure is called blImage and is available at: http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/

There you can download my blImageAPI and start having fun with opencv instead of sweating about pixel access.

Good luck and have fun creating image algorithms

Enzo