6

I'm trying to write a program which takes an SDL_Surface, converts it to an IplImage, uses the cvBlobsLib to find blobs, paints the blobs as spots back over the image, then converts the output IplImage back to an SDL_Surface.

I'm almost done: only converting the IplImage back to an SDL_Surface hasn't been done yet. This IplImage has 3 image channels and is 8 bits per pixel. I think I have two calls I can use:

SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);

I'm currently trying with SDL_CreateRGBsurfaceFrom. I have no idea, however, what the correct values of pitch, Rmask, Gmask and Bmask are. (Amask is 0, because there is no alpha channel.)

Could anybody help me out by explaining how to do this?

Thanks!

Edit: For example, this is code I tried to use:

SDL_Surface *ipl_to_surface (IplImage *opencvimg)
{
    int pitch = opencvimg->nChannels*opencvimg->width;
    printf("Depth %d, nChannels %d, pitch %d\n", opencvimg->depth,
                    opencvimg->nChannels, pitch);
    SDL_Surface *surface = SDL_CreateRGBSurfaceFrom((void*)opencvimg->imageData,
                    opencvimg->width,
                    opencvimg->height,
                    opencvimg->depth,
                    pitch,
                    0x0000ff, 0x00ff00, 0xff0000, 0
                    );
    return surface;
}

(SDL Documentation writes "Pitch is the size of the scanline of the surface, in bytes, i.e. widthInPixels*bytesPerPixel.") This outputs "Depth 8, nChannels 3, pitch 1920" and displays a completely red image. I think a solution would be to convert my 8-bits image to 24-bits (1 byte per channel), but I don't know how to do that. Any ideas?

sgielen
  • 349
  • 1
  • 5
  • 15
  • Your image is 8 bits per pixel with 3 channels? Did you mean 24 bits per pixel, since that's what the RGB masks you specified seems to suggest? – codelogic Dec 26 '08 at 19:50
  • No, it's the other way around: the RGB masks I specified are wrong. The image is really 8 bits per pixel with 3 channels. I'm going to try this code now: http://paster.dazjorz.com/?p=3705 – sgielen Dec 26 '08 at 19:52
  • Yeah your best bet would be to convert it to 24 bit or 32 bit since I don't think SDL handles non-standard bit depths too well. – codelogic Dec 26 '08 at 19:56
  • see question at http://stackoverflow.com/questions/394488/how-to-convert-an-8-bit-opencv-iplimage-to-a-32-bit-iplimage too... :( – sgielen Dec 27 '08 at 00:02
  • Ok. So now I've got a 32-bit 3-channel image, which I need to convert to SDL_Surface. – sgielen Dec 27 '08 at 20:26

2 Answers2

11

Ok, I got it working!

I think I was confused by the fact that an OpenCV depth of 8 means a pixel has 8 bits per channel, so in a 3-channel image, a pixel has 24 bits. So when converting that to the SDL meaning of depth, we get 8 * 3 = 24 bits.

The image was 24 bits after all, which SDL supports. So converting the image to SDL is as simple as:

SDL_Surface *surface = SDL_CreateRGBSurfaceFrom((void*)opencvimg->imageData,
                opencvimg->width,
                opencvimg->height,
                opencvimg->depth*opencvimg->nChannels,
                opencvimg->widthStep,
                0xff0000, 0x00ff00, 0x0000ff, 0
                );
return surface;

Sorry for the confusion, I hope this helps anybody searching for the same answer.

Other links of interest: http://www.libsdl.org/cgi/docwiki.cgi/Pixel_Access
And the complete subroutine at: http://paster.dazjorz.com/?p=3714

sgielen
  • 349
  • 1
  • 5
  • 15
  • If you are using C++, I really encourage you to turn the standard pointer (*) into a smart pointer as soon as possible. Otherwise, unexpected, unhandled exceptions will produce memory leaks. Take a look at the boost family of smart pointers. There are also other implementations. OpenCV itself offers one, which is perhaps not as fancy as everything in boost, but it does prevent memory leaks and dangling pointers. – Raúl Salinas-Monteagudo Apr 23 '13 at 21:57
3

First of all: Thanks!!

Second: It works perfectly with 3 Channel images but I want to display a Single-Channel-IplImage

so there we go:

SDL_Surface *single_channel_ipl_to_surface (IplImage *opencvimg)
{
    SDL_Surface *surface = SDL_CreateRGBSurfaceFrom((void*)opencvimg->imageData,
                           opencvimg->width,
                           opencvimg->height,
                           opencvimg->depth*opencvimg->nChannels,
                           opencvimg->widthStep,
                           0xffffff, 0xffffff, 0xffffff,0);
    return surface;
}
clesenne
  • 153
  • 1
  • 6