views:

7912

answers:

7

I need to convert an 8-bit IplImage to a 32-bits IplImage. Using documentation from all over the web I've tried the following things:

// general code
img2 = cvCreateImage(cvSize(img->width, img->height), 32, 3);
int height    = img->height;
int width     = img->width;
int channels  = img->nChannels;
int step1     = img->widthStep;
int step2     = img2->widthStep;
int depth1    = img->depth;
int depth2    = img2->depth;
uchar *data1   = (uchar *)img->imageData;
uchar *data2   = (uchar *)img2->imageData;

for(h=0;h<height;h++) for(w=0;w<width;w++) for(c=0;c<channels;c++) {
   // attempt code...
}

// attempt one
// result: white image, two red spots which appear in the original image too.
// this is the closest result, what's going wrong?!
// see: http://files.dazjorz.com/cache/conversion.png
((float*)data2+h*step2+w*channels+c)[0] = data1[h*step1+w*channels+c];

// attempt two
// when I change float to unsigned long in both previous examples, I get a black screen.

// attempt three
// result: seemingly random data to the top of the screen.
data2[h*step2+w*channels*3+c] = data1[h*step1+w*channels+c];
data2[h*step2+w*channels*3+c+1] = 0x00;
data2[h*step2+w*channels*3+c+2] = 0x00;

// and then some other things. Nothing did what I wanted. I couldn't get an output
// image which looked the same as the input image.

As you see I don't really know what I'm doing. I'd love to find out, but I'd love it more if I could get this done correctly. Thanks for any help I get!

+2  A: 

Perhaps this link can help you?

Edit In response to the second edit of the OP and the comment

Have you tried

float value = 0.5

instead of

float value = 0x0000001;

I thought the range for a float color value goes from 0.0 to 1.0, where 1.0 is white.

Stefan Schmidt
There's some interesting information on that page, pieces of code which explain what I've already tried. The results are the same, however. Please see the following link for an example of what goes wrong all the time:http://files.dazjorz.com/cache/conversion.png
dazjorz
whoa, yeah, that's a good one, you're right! So that gives the following clue: for the red spots, R is 1.0 and GB are 0.0, and for the white, all three are 1.0. So while converting, the RGB values should be converted from 0 to 255 to 0.0 to 1.0. Changing value to b / 255 makes the image black+red.
dazjorz
Got it! int b = ((uchar *)(img->imageData + h*img->widthStep))[w*img->nChannels + 0]; // B ((float *)(img2->imageData + h*img2->widthStep))[w*img2->nChannels + 0] = ((float)b) / 255.0;
dazjorz
+1  A: 

Floating point colors go from 0.0 to 1.0, and uchars go from 0 to 255. The following code fixes it:

// h is height, w is width, c is current channel (0 to 2)
int b = ((uchar *)(img->imageData + h*img->widthStep))[w*img->nChannels + c];
((float *)(img2->imageData + h*img2->widthStep))[w*img2->nChannels + c] = ((float)b) / 255.0;

Many, many thanks to Stefan Schmidt for helping me fix this!

dazjorz
+4  A: 

The function you are looking for is cvConvertScale(). It automagically does any type conversion for you. You just have to specify that you want to scale by a factor of 1/255 (which maps the range [0...255] to [0...1]).

Example:

IplImage *im8 = cvLoadImage(argv[1]);
IplImage *im32 = cvCreateImage(cvSize(im8->width, im8->height), 32, 3);

cvConvertScale(im8, im32, 1/255.);
Martin
I tried that, but it didn't accept either the output or the input scale. Or maybe I just used it incorrectly.
dazjorz
It is important that you pass a double as scaling factor (which is why there is '.' behind the 255). 1/255 would evaluate as integer division and lead to a scaling factor of 0. What exactly is your code that didn't work with cvConvertScale() ?
Martin
I wish I could put more upvotes, i upvoted your comment and your answer as well. I've been struggling on this for at least 8 hours goddammit!
Eric
A: 

Hi, I was just wondering why you proceed the scale factor 1/255 with a dot

(what is the difference between cvConvertScale(im8, im32, 1/255.) and cvConvertScale(im8, im32, 1/255) ?)

Regards

A: 

If you do not put the dot (.), some compilers will understand is as an int division, giving you a int result (zero in this case).

A: 

Great answer! Thanks..

horeshb
+1  A: 

You can create an IplImage wrapper using boost::shared_ptr and template-metaprogramming. I have done that, and I get automatic garbage collection, together with automatic image conversions from one depth to another, or from one-channel to multi-channel images.

I have called the API blImageAPI and it can be found here: http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/

It is very fast, and make code very readable, (good for maintaining algorithms)

It is also can be used instead of IplImage in opencv algorithms without changing anything.

Good luck and have fun writing algorithms!!!

Enzo