How to convert an 8-bit OpenCV IplImage* to a 32-bit IplImage*?
Asked Answered
C

6

12

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!

Coercive answered 27/12, 2008 at 0:2 Comment(0)
B
6

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.

Blather answered 27/12, 2008 at 14:37 Comment(3)
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: files.dazjorz.com/cache/conversion.pngCoercive
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.Coercive
Got it! int b = ((uchar )(img->imageData + himg->widthStep))[wimg->nChannels + 0]; // B ((float *)(img2->imageData + himg2->widthStep))[w*img2->nChannels + 0] = ((float)b) / 255.0;Coercive
A
30

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.);

Note the dot in 1/255. - to force a double division. Without it you get a scale of 0.

Annulate answered 27/12, 2008 at 0:2 Comment(7)
I tried that, but it didn't accept either the output or the input scale. Or maybe I just used it incorrectly.Coercive
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() ?Annulate
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!Steerage
For the guys who use the C++ API: im8.convertTo(im32, CV_32FC1);Shang
Instead of cvSize(im8->width, im8->height) use cvGetSize(im8)Rhaetic
This is the correct answer but there isn't any need to scale the gray values between 0-1. You can just use 1 instead of 1.0/255.0. (depending on what you plan on doing with the image afterwards).Debt
This worked fine in my case: cvConvertScale(im8, im32, 1.0, 0.0);Kastner
B
6

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.

Blather answered 27/12, 2008 at 14:37 Comment(3)
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: files.dazjorz.com/cache/conversion.pngCoercive
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.Coercive
Got it! int b = ((uchar )(img->imageData + himg->widthStep))[wimg->nChannels + 0]; // B ((float *)(img2->imageData + himg2->widthStep))[w*img2->nChannels + 0] = ((float)b) / 255.0;Coercive
C
2

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!

Coercive answered 27/12, 2008 at 21:4 Comment(0)
M
1

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!!!

Mig answered 27/12, 2008 at 0:2 Comment(0)
F
1

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).

Fractional answered 27/12, 2008 at 0:2 Comment(0)
L
0

IplImage *img8,*img32;
img8 =cvLoadImage("a.jpg",1);

    cvNamedWindow("Convert",1);
    img32 = cvCreateImage(cvGetSize(img8),IPL_DEPTH_32F,3);
    cvConvertScale(img8,img32,1.0/255.0,0.0);

//For Confirmation Check the pixel values (between 0 - 1)

    for(int row = 0; row < img32->height; row++ ){
                float* pt = (float*) (img32->imageData + row * img32->widthStep);
                for ( int col = 0; col < width; col++ )
                            printf("\n %3.3f , %3.3f , %3.3f ",pt[3*col],pt[3*col+1],pt[3*col+2]);                  
            }

    cvShowImage("Convert",img32);
    cvWaitKey(0);
    cvReleaseImage(&img8);
    cvReleaseImage(&img32);
    cvDestroyWindow("Convert");
Lueck answered 27/12, 2008 at 0:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.