I am new to sdl. I have basically have the following codes which can load the images. I know how to access the pixel as below. What I need it to convert the image to 8 bit grey level and 1 bit monochrome separately. I know it got to do with pixel manipulation. Any hint or idea how to to this? I am not too sure what to set for SDL_CreateRGBSurface and also once I get the pixel what manipulation to be done?


Essentially you're just looking for a conversion function, i.e. breaking down a three component color into a one component color. This can be done different ways, probably easiest one being a simple average function:

gray(r, g, b) = (r + g + b) / 3

In C/C++ this could be done the following way (assuming you've got 24/32 bit colors with alpha being unused/occupying the most significant byte; one byte per color; i.e. RGB888 or RGBA8888):

int source_color = SDL_GetPixel(...); // some color

const unsigned int component1 = source_color & 0xff; // red or blue
const unsigned int component2 = (source_color >> 8) & 0xff; // green
const unsigned int component3 = (source_color >> 16) & 0xff; // blue or red

// calculating the average component/color (i.e. grayscale)
const unsigned int gray = (component1 + component2 + component3) / 3;

// back to SDL's RGB color (optional)
const int gray_rgb = 0xff000000 | (gray << 16) | (gray << 8) | gray;

// There are multiple ways to get the monochrom image, based on the format you'd like (e.g. just a boolean value or just a RGB value).

// First version (actually not recommended, but might save you code e.g. having one fixed conversion function):

    // calculating the monochromatic color with a given threshold (127)
    const unsigned int mono = gray > 127 ? 255 : 0;

    // once again back to SDL's RGB model (optional)
    const int mono_rgb = 0xff000000 | (mono << 16) | (mono << 8) | mono;

// Second version:

    // just return the final color in one step
    // this returns pure white or pure black
    const int mono_rgb = gray > 127 ? 0xffffffff : 0xff000000;

Note that there are similar approaches using different weightings applied to the color components. Also you can try different thresholds for the monochrome conversion to lighten/darken the image.

As for the actual SDL Surface, that's up to you. I'd just stick with SDL_PIXELFORMAT_RGB888 or SDL_PIXELFORMAT_RGBA8888 to avoid further conversions, unless it understands grayscale images now (which I don't think?).

Further explanation on the conversions:

If you're storing a color in an integer value, you'll usually use one byte per color. In hex notation this will mean that you've got two digits per color, essentially translating to something like AABBGGRR, where AA are the byte for alpha, BB the byte for blue, etc. If you're familiar with the hexadecimal notation of colors in HTML/CSS (like #ff0000 for red), then this should sound familiar to you.

If you'd like to store a grayscale value x in (A)RGB notation, you'd end up setting all three color components (red, green, and blue) to the same value (of x). This happens in this line:

const int gray_rgb = 0xff000000 | (gray << 16) | (gray << 8) | gray;
  • The logical or (|) essentially adds the various components.
  • 0xff000000 represents full opacity (alpha = 255).
  • gray << 16 moves the value of gray to the correct position for red or blue (depends on pixel format). This is known as a left shift, e.g. 0x00000012 << 8 will result in 0x00001200 (values moved to the left by 8 bits).
  • gray << 8 moves the value of gray to the correct position for green.
  • gray finally stays as is, which will be the value for blue or red (again depending on the pixel format).

Finally, const unsigned int mono = gray > 127 ? 255 : 0; will set the monochrome color (which is actually grayscale again, 256 different values!) based on the grayscale value. 255 represents white, 0 represents black.

  • \$\begingroup\$ yes I saw some articles give different weights for RGB but some are doing averaging like yours. I am not so here what are you doing here const int gray_rgb = 0xff000000 | (gray << 16) | (gray << 8) | gray; What is is this if statement for gray > 127 ? 255 : 0; I guess for single bit image right? \$\endgroup\$ – biz14 Sep 8 '13 at 14:24
  • \$\begingroup\$ Exactly, instead of using gray > 127 ? 255 : 0 you could as well just use gray > 127 to get a true boolean value (i.e. 1 bit), but you can't use that to get an RGB color directly. \$\endgroup\$ – Mario Sep 8 '13 at 14:55
  • \$\begingroup\$ Further updated the answer, the monochrome color generation has been a bit too "complicated" based on what you're trying to achieve. Also, just to note: SDL is a library to display images, write games, etc. If you'd like to do image manipulation and computer vision stuff, I'd suggest you have a look at OpenCV, which offers far better support for different pixel formats, conversions, etc. (lots of stuff built in as well). \$\endgroup\$ – Mario Sep 8 '13 at 14:58
  • \$\begingroup\$ ok I am very clear now but before that we got to confirm whether is RGBA or ARGB right how normally your confirm on that else the whole of this will be wrong const int gray_rgb = 0xff000000 | (gray << 16) | (gray << 8) | gray; right? One more things once all 3 have some color value how will they be gray scale when they still have color values in it? \$\endgroup\$ – biz14 Sep 8 '13 at 15:27
  • \$\begingroup\$ You'll have to pick the proper pixel format to ensure you're setting the correct values, which will influence the order in which you shift values. The generated values are indeed grayscale due to the way the RGB color system works. In short: All components are identical = gray(scale). Have a look at Wikipedia and other sites. Of course, there are more efficient formats for grayscale images, like 1 byte per pixel, but SDL isn't really made for these. \$\endgroup\$ – Mario Sep 8 '13 at 15:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.