Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Converting Colored Bitmap To Grayscale

bitmap convert image grayscale bitmap delphi graphic

  • Please log in to reply
3 replies to this topic

#1 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 11 April 2012 - 10:07 PM

Recently we have a post in Pascal/Delphi forum asking how to convert 24bit bitmaps into 8bit grayscale. See the post here. Personally I am very interested with graphic manipulation code, so I replied the post with quick answer. While the poster seemed satisfied with the answer, but I, actually, am not. Therefore I write this tutorial with aims of:
  • Show the basic bitmap manipulation using TBitmap graphic class.
  • Show how to directly manipulate pixels in a bitmap (through TBitmap).
  • Show faster pixel manipulation using Scanline property which provide direct access to the pixel.

Overview

Let me quote wikipedia page on definition of grayscale image.

In photography and computing, a grayscale or greyscale digital image is an image in which the value of each pixel is a single sample, that is, it carries only intensity information. Images of this sort, also known as black-and-white, are composed exclusively of shades of gray, varying from black at the weakest intensity to white at the strongest.[1]

Grayscale images are distinct from one-bit bi-tonal black-and-white images, which in the context of computer imaging are images with only the two colors, black, and white (also called bilevel or binary images). Grayscale images have many shades of gray in between. Grayscale images are also called monochromatic, denoting the presence of only one (mono) color (chrome).


That page also gives information on how to convert color to grayscale image. Let me quote the part here.

Conversion of a color image to grayscale is not unique; different weighting of the color channels effectively represent the effect of shooting black-and-white film with different-colored photographic filters on the cameras. A common strategy is to match the luminance of the grayscale image to the luminance of the color image.

To convert any color to a grayscale representation of its luminance, first one must obtain the values of its red, green, and blue (RGB) primaries in linear intensity encoding, by gamma expansion. Then, add together 30% of the red value, 59% of the green value, and 11% of the blue value[2][3][4] (these weights depend on the exact choice of the RGB primaries, but are typical). Regardless of the scale employed (0.0 to 1.0, 0 to 255, 0% to 100%, etc.), the resultant number is the desired linear luminance value; it typically needs to be gamma compressed to get back to a conventional grayscale representation.



Coding the Conversion Routine

Based on the above information we can write our conversion routine. Let's name the routine GetGrayscaleOf.

procedure GetGrayscaleOf(ASrc, AGray: TBitmap);
var
  x, y: Integer;
  vLineSrc  : PRGBTriple;
  vLineGray : PRGBTriple;
  vGrayValue: Byte;
begin
  // make sure the source and destination have 24bit color format
  ASrc.PixelFormat := pf24bit;
  AGray.PixelFormat := pf24bit;

  // make the target to the same dimension with the source
  AGray.Width := ASrc.Width;
  AGray.Height := ASrc.Height;

  for y := 0 to AGray.Height-1 do
  begin
	// get the pointer to the first pixel of the y-th row of the source bitmap
	vLineSrc  := ASrc.ScanLine[y];
	// get the pointer to the first pixel of the y-th row of the grayscale bitmap
	vLineGray := AGray.ScanLine[y];
	
	// iterate the pixels
	for x := 0 to AGray.Width-1 do
	begin
	  // calculate the luminance of the color
	  vGrayValue := Round(0.3 * vLineSrc^.rgbtRed
						  + 0.59 * vLineSrc^.rgbtGreen
						  + 0.11 * vLineSrc^.rgbtBlue);

	  // same values of red, green, blue will result in grayscale color			  
	  vLineGray^.rgbtRed  := vGrayValue;
	  vLineGray^.rgbtGreen:= vGrayValue;
	  vLineGray^.rgbtBlue := vGrayValue;

	  // move to the next pixel
	  Inc(vLineSrc);
	  Inc(vLineGray);
	end;
  end;
end;


Demo Project

Let's build a demo project so we can easily see if our conversion routine is working correctly.


Preparation of the GUI
  • Create new application, or VCL Forms application if you are using newer versions (D2009 and above) of Delphi. You will be taken to the main form for our demo project.
  • Drop a TScrollBox from Additional tab of the component pallette. It will automatically be named ScrollBox1.
  • Drop a TImage from Additional tab of the component pallette inside ScrollBox1. It will automatically be named Image1.
  • Drop another TScrollBox into the form. It will automatically be named ScrollBox2.
  • Drop a TImage from Additional tab of the component pallette inside ScrollBox2. It will automatically be named Image2.
  • Adjust ScrollBox1 and ScrollBox2 to have the same width and height and place ScrollBox1 above ScrollBox2, like shown in the next picture.
  • Drop a TBitBtn from Additional tab of the component pallette on the right of ScrollBox1. Name it btnLoadImage and set its Caption property to "Load Image".
  • Drop another TBitBtn to the form, but this time place it to the right of ScrollBox2. Name it btnGet24bitGrayscale and set its Caption property to "Get grayscale (24bit)".
  • Drop another TBitBtn to the form. This time place it below btnGet24bitGrayscale. Name it btnGet8bitGrayscale and set its Caption property to "Get grayscale (8bit)".

Up to here, you should get something like this.

GrayscaleConvert_Design001.jpg


Event Handlers

Now that our controls have been laid down, let's code their event handlers.

First, we want to open an image file when btnLoadImage is clicked and display it in Image1. Therefore double click on button btnLoadImage and give the following codes for handling its OnClick event.

procedure TForm1.btnLoadImageClick(Sender: TObject);
begin
  if not OpenPictureDialog1.Execute then Exit;
  Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
end;

Second, we want to convert whatever image that shown in Image1 into 24bit grayscale then show it in Image2 when the user click on button btnGet24bitGrayscale. So double click on button btnGet24bitGrayscale and give the following codes to handle its OnClick event.

procedure TForm1.btnGet24bitGrayscaleClick(Sender: TObject);
var
  vSrc : TBitmap;
  vGray: TBitmap;
begin
  if Image1.Picture.Graphic=nil then
	// when there is no source picture shown, raise exception
	raise Exception.Create('No source image currently selected');

  vSrc := TBitmap.Create;
  try
	// set pixel format of the bitmap to 24bits
	vSrc.PixelFormat := pf24bit;

	// transfer the graphic currently displayed in Image1 to our source bitmap
	vSrc.Width  := Image1.Picture.Graphic.Width;
	vSrc.Height := Image1.Picture.Graphic.Height;
	vSrc.Canvas.Draw(0, 0, Image1.Picture.Graphic);

	// start getting the grayscale version of the source image
	vGray := TBitmap.Create;
	try
	  // call the routine that does the grayscale conversion
	  GetGrayscaleOf(vSrc, vGray);

	  // show the grayscale version
	  Image2.Picture.Graphic := vGray;
	finally
	  vGray.Free;
	end;
  finally
	vSrc.Free;
  end;
end;

Third, we want to convert whatever image that shown in Image1 into 8bit grayscale then show it in Image2 when the user click on button btnGet8bitGrayscale. So double click on button btnGet8bitGrayscale and give the following codes to handle its OnClick event.

procedure TForm1.btnGet8bitGrayscaleClick(Sender: TObject);
var
  vSrc : TBitmap;
  vGray: TBitmap;
begin
  if Image1.Picture.Graphic=nil then
	// when there is no source picture shown, raise exception
	raise Exception.Create('No source image currently selected');

  vSrc := TBitmap.Create;
  try
	// set pixel format of the bitmap to 24bits
	vSrc.PixelFormat := pf24bit;

	// transfer the graphic currently displayed in Image1 to our source bitmap
	vSrc.Width  := Image1.Picture.Graphic.Width;
	vSrc.Height := Image1.Picture.Graphic.Height;
	vSrc.Canvas.Draw(0, 0, Image1.Picture.Graphic);

	// start getting the grayscale version of the source image
	vGray := TBitmap.Create;
	try
	  // call the routine that does the grayscale conversion
	  GetGrayscaleOf(vSrc, vGray);

	  // set pixel format of the grayscale picture to 8bit
	  vGray.PixelFormat := pf8bit;

	  // show the grayscale version
	  Image2.Picture.Graphic := vGray;
	finally
	  vGray.Free;
	end;
  finally
	vSrc.Free;
  end;
end;

Now we are ready to test run the demo project.


Running the Demo Project

On running the demo project you might get result something like these:
  • Initial run
    GrayscaleConvert_Run001.jpg
  • Convert to 24bit grayscale
    GrayscaleConvert_Run002.jpg
  • Convert to 8bit grayscale
    GrayscaleConvert_Run003.jpg
And here is source code of the demo project Attached File  Demo.zip   292.7KB   972 downloads, feel free to use it for anything.
  • 2

#2 RubyS

RubyS

    CC Lurker

  • New Member
  • Pip
  • 5 posts

Posted 12 April 2012 - 09:53 PM

Good tutorial. Can you show how to add one jpg image to other image?


  • 0

#3 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 12 April 2012 - 10:08 PM

Thanks RubyS, and Welcome to CodeCall!

While I can show you how to combining jpg image to another image (of any type as long as supported by your Delphi environment), but not here. Please start a new thread in Pascal/Delphi forum, and I will reply asap.
  • 1

#4 RubyS

RubyS

    CC Lurker

  • New Member
  • Pip
  • 5 posts

Posted 12 April 2012 - 11:54 PM

I post my question here: http://forum.codecal...ing-jpg-images/

Please look to it. Thx!
  • 0





Also tagged with one or more of these keywords: bitmap, convert image, grayscale bitmap, delphi graphic

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download