locked
Grayscale images with Bitmap class

    Question

  • I am trying to use the grayscale pixel format (Format16bppGrayScale) with the C# Bitmap class. I can successfully construct the Bitmap object but when I try to SetPixel or GetPixel it throws an exception. After much searching through the documentation I discovered that, yes indeed, both those methods will throw exceptions when applied to a Format16bppGrayScale Bitmap. So my first question (directed to the people who wrote the Bitmap class) is "What the heck?" I can conceive of no reasonable reason why there can't be a version of SetPixel and GetPixel that will handle Format16bppGrayScale pixel formats.

    My next question, to all of you who have experence with the Bitmap class is, "How do I effectively get and set pixels in a Format16bppGrayScale Bitmap object?"

    I found one posting on this forum which uses LockBits and System.Runtime.InteropServices.Marshal.Copy to set pixels in the Bitmap. But, geesh, how many hoops does one have to jump through just to put a pixel value into a pixel? And I did not come across any way to effectively GetPixel.

    Is there an hope for doing what I need to do?

    - Roger Garrett
    Tuesday, August 05, 2008 1:56 PM

Answers

  • How would you display a 16 bit grayscale image?  Do you have a 16 bit graphic card?  Most graphics cards are 8 bits, so they can't display a 16 bit image.  Some of the PixelFormats are probably included for future use when the hardware becomes available.  You can do anything you want with the pixels of a 16 bit grayscale image using lockbits.  GetPixel and SetPixel depend upon the graphics engine which does not have 16 bit capability.  Normally you would want to convert a 16 bit grayscale image into a format that could be displayed, and you would never use GetPixel and SetPixel for that purpose.  GetPixel and SetPixel are only used to get or set a few pixels of an image because they are extremely slow.  They are used by programmers with little knowledge of the format of an image because of their simplicity.   

    The documentation clearly states that indexed formats are not supported by the graphics class.

    • Edited by JohnWein Wednesday, August 06, 2008 7:45 PM graphics class support.
    • Marked as answer by jack 321 Friday, August 08, 2008 3:10 AM
    Wednesday, August 06, 2008 7:41 PM

All replies

  • Roger,

    The Get and Set pixel methods explicitly work with 24 bit images.  They cannot set a 24 bit pixel in a 16 bit greyscale image.  You will need to work with a 24 bit bitmap (only adjusting luminescence ) and change it to 16 bit after you've made your changes.

    Mike
    Tuesday, August 05, 2008 2:32 PM
  • HossManDu said:

    Roger,

    The Get and Set pixel methods explicitly work with 24 bit images.  They cannot set a 24 bit pixel in a 16 bit greyscale image.  You will need to work with a 24 bit bitmap (only adjusting luminescence ) and change it to 16 bit after you've made your changes.

    Mike



    Yes, I learned the hard way that SetPixel and GetPixel do not work with 16 bit grayscale Bitmaps. It would be so very nice to know why the authors of that class couldn't have added variations of SetPixel and GetPixel that would indeed work. What technological reason could there possibly be for not providing that capability? The Bitmap class lets me create 16-bit grayscale Bitmaps but doesn't let me Get or Set pixels. Seems rather absurd to me.

    Your suggestion of using the luminescence values in a 24 bit bitmap and then converting to 16 bit grayscale won't work. The Luminesence value is only 8 bits, so only 8 bits of data. When you convert the 24 bit bitmap to 16 bit grayscale you only get grayscale values in the range 0 - 255. I need the full range of 16 bits of grayscale.
    Tuesday, August 05, 2008 3:16 PM
  • Get and Set Pixel can only be used with Bitmaps that can be displayed.  You'll have to access the bits of your bitmap using lockbits.
    • Edited by JohnWein Tuesday, August 05, 2008 6:12 PM Removed graphics card
    Tuesday, August 05, 2008 6:07 PM
  • Subsequent searching on the Internet reveals that, although Format16bppGrayScale, is included as on eo fthe PixelFormat values wihtin C#, in fact it is not supported. You can't load in a Format16bppGrayScale file (it actually gets loaded as a different file format), you CAN, seemingly, create a Bitmap object with the Format16bppGrayScale specified, but you can't connect it to a window (e.g. by making it the BackgroundImage) but it then causes an exception to bethrown when it tries to display it. So, bottom line, C# doesn't support Format16bppGrayScale. It's apparently a result of the underlying DotNet GDI not supporting it.

    Shame on Microsoft!

    The least they should do is change the documentation and explain that it's not supported.

    Wednesday, August 06, 2008 6:37 PM
  • How would you display a 16 bit grayscale image?  Do you have a 16 bit graphic card?  Most graphics cards are 8 bits, so they can't display a 16 bit image.  Some of the PixelFormats are probably included for future use when the hardware becomes available.  You can do anything you want with the pixels of a 16 bit grayscale image using lockbits.  GetPixel and SetPixel depend upon the graphics engine which does not have 16 bit capability.  Normally you would want to convert a 16 bit grayscale image into a format that could be displayed, and you would never use GetPixel and SetPixel for that purpose.  GetPixel and SetPixel are only used to get or set a few pixels of an image because they are extremely slow.  They are used by programmers with little knowledge of the format of an image because of their simplicity.   

    The documentation clearly states that indexed formats are not supported by the graphics class.

    • Edited by JohnWein Wednesday, August 06, 2008 7:45 PM graphics class support.
    • Marked as answer by jack 321 Friday, August 08, 2008 3:10 AM
    Wednesday, August 06, 2008 7:41 PM
  • I've read the posts on this thread and found myself facing a similar problem. Some users MUST use 16bppGrayscale on medical applications, as popular medical imaging formats work in this format (specially DICOM).

    Whenever we try to manipulate any grayscale image in C# the reference formats for images are always defined in multidimensional spaces (HSB, RGB, ARGB, etc) and the single dimension image can not be manipulated.

    What we need are methods to get the 16bits for each pixel, representing only the greyscale and nothing more, and set a 16bit grayscale tone.

    Converting to multidimensional color formats will corrupt the values of the pixels and are worthless for our applications.

    We do not want to exhibit the image, but to process the information contained in the files. We don't care about screen resolution or capabilities, only the manipulation of the data contained in the files.

    If you understand this, you will answer the question properly.

    Thanks,

    Wednesday, April 28, 2010 1:55 AM
  • Whenever we try to manipulate any grayscale image in C# the reference formats for images are always defined in multidimensional spaces (HSB, RGB, ARGB, etc) and the single dimension image can not be manipulated.

    Why not?  Just don't use the Graphics class in System.Drawing.  WPF has extensive 16bpp gray scale capabilities.
    Wednesday, April 28, 2010 4:55 AM
  • I too am facing this problem. I have single channel data in greyscale at 32 bits or 16 bits and I cannot use getpixel to return the 16 or 32 bit value of those pixels. I don't understand why I should have to use this 'lockbits' thing when the task is so devilishly simple with an 8bit bitmap. IT looks as though I'll have to export my data as an ascii text file and read it myself into an array. Stupid or what
    Tuesday, May 18, 2010 2:11 PM