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!

sgielen
  • 349
  • 1
  • 5
  • 15

6 Answers6

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.

ANeves
  • 6,219
  • 3
  • 39
  • 63
Martin
  • 12,408
  • 6
  • 34
  • 30
  • I tried that, but it didn't accept either the output or the input scale. Or maybe I just used it incorrectly. – sgielen Jan 30 '09 at 18:42
  • 11
    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 Feb 02 '09 at 21:34
  • 1
    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 May 28 '09 at 14:43
  • For the guys who use the C++ API: im8.convertTo(im32, CV_32FC1); – Geniedesalpages Oct 04 '11 at 13:31
  • Instead of `cvSize(im8->width, im8->height)` use `cvGetSize(im8)` – Mark Jeronimus Jan 18 '12 at 03:09
  • 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). – redfood Sep 21 '12 at 23:53
  • This worked fine in my case: `cvConvertScale(im8, im32, 1.0, 0.0);` – Lampis Dec 03 '12 at 14:03
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.

Stefan Schmidt
  • 1,152
  • 11
  • 18
  • 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 – sgielen Dec 27 '08 at 15:45
  • 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. – sgielen Dec 27 '08 at 17:50
  • 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; – sgielen Dec 27 '08 at 17:56
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!

sgielen
  • 349
  • 1
  • 5
  • 15
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!!!

Enzo
  • 1,042
  • 7
  • 7
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).

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");
Faizan Ayyub
  • 41
  • 1
  • 3