### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: Convert a picture to Gray  (Read 5275 times)

#### winni

• Hero Member
• Posts: 2807
##### Re: Convert a picture to Gray
« Reply #15 on: December 23, 2019, 06:25:52 pm »
Hi!

Before you resize Image7 you have to initialize the internal bitmap.

The easiest way is to fill it white
Code: Pascal  [Select][+][-]
1. image7.canvas.brush.color := clWhite;
2. image7.Canvas.fillrect(0,0,image7.width,image7.height);
3.
Now you can resize the bitmap of image7 without crash.

Winni

#### fpauw

• New Member
• Posts: 11
##### Re: Convert a picture to Gray
« Reply #16 on: December 24, 2019, 08:35:21 am »
I add the code but now the same error is now on closing the program. The gray image is just a white surface...

Code: Pascal  [Select][+][-]
1. procedure TForm1.Button1Click(Sender: TObject);
2. Var
4.   ValR, ValG, ValB, monoByte : Byte;
5.   X, Y: Integer;
6. begin
7.   if openpicturedialog1.Execute then
8.      Begin
10.      end;
11.
12.   Image7.Picture.Bitmap.Width := Image1.Picture.Width;
13.   Image7.Picture.Bitmap.Height := Image1.Picture.Height;
14.   image7.canvas.brush.color := clWhite;
15.   image7.Canvas.fillrect(0,0,image7.width,image7.height);
16.
17.   For Y:=0 To Image1.Height-1 Do
18.   Begin
19.     ScanData := Image1.Picture.Bitmap.ScanLine[Y];
20.     ResultData := Image7.Picture.Bitmap.ScanLine[Y];
21.     For X:=0 To Image1.Width-1 Do
22.     Begin
23.       ValR := ScanData^.rgbRed;
24.       ValG := ScanData^.rgbGreen;
25.       ValB := ScanData^.rgbBlue;
26.
27.       MonoByte := round(0.2125 * ValR + 0.7154 * ValG + 0.0721 * ValB);
28.
29.       ResultData^.rgbRed:=MonoByte;
30.       ResultData^.rgbGreen:=MonoByte;
31.       ResultData^.rgbBlue:=MonoByte;
32.
33.       Inc(ScanData);
34.       Inc(ResultData);
35.     end;
36.   end;
37. end;
38.
« Last Edit: December 24, 2019, 09:19:36 am by fpauw »

#### martijnn

• New Member
• Posts: 16
##### Re: Convert a picture to Gray
« Reply #17 on: December 24, 2019, 09:16:20 am »
Have a look at comment on the ScanLine property:

Code: Pascal  [Select][+][-]
1. property ScanLine[Row: Integer]: Pointer read GetScanLine; platform; // Use only when wrpped by a begin/endupdate

Code: Pascal  [Select][+][-]
1. Image7.Picture.Bitmap.BeginUpdate;
2. // Double loop here
3. Image7.Picture.Bitmap.EndUpdate;
4.
... at least starts to show a grayscale picture (still with some issues left)

#### fpauw

• New Member
• Posts: 11
##### Re: Convert a picture to Gray
« Reply #18 on: December 24, 2019, 09:29:35 am »
Thanks I have output now!

And yes there are still errors now I have vertical white lines.

#### martijnn

• New Member
• Posts: 16
##### Re: Convert a picture to Gray
« Reply #19 on: December 24, 2019, 09:50:46 am »
As a next step it will probably help to match the number of bits per pixel of the input image. For example:

Code: Pascal  [Select][+][-]
1. image7.Picture.Bitmap.PixelFormat := image1.Picture.Bitmap.PixelFormat;

#### fpauw

• New Member
• Posts: 11
##### Re: Convert a picture to Gray
« Reply #20 on: December 24, 2019, 10:28:10 am »
Thanks a Lot!

Now it works without errors!

This is the result
Code: Pascal  [Select][+][-]
1. procedure TForm1.Button1Click(Sender: TObject);
2. Var
4.   ValR, ValG, ValB, monoByte : Byte;
5.   X, Y: Integer;
6. begin
7.   if openpicturedialog1.Execute then
8.      Begin
10.      end;
11.   Image7.Picture.Bitmap.Width := Image1.Picture.Width;
12.   Image7.Picture.Bitmap.Height := Image1.Picture.Height;
13.   image7.Picture.Bitmap.PixelFormat := image1.Picture.Bitmap.PixelFormat;
14.   Image7.Picture.Bitmap.BeginUpdate;
15.
16.   For Y:=0 To Image1.Height-1 Do
17.   Begin
18.     ScanData := Image1.Picture.Bitmap.ScanLine[Y];
19.     ResultData := Image7.Picture.Bitmap.ScanLine[Y];
20.     For X:=0 To Image1.Width-1 Do
21.     Begin
22.       //   X, Y, TotalTime, DistCurve: Integer;Point to the pixel location
23.       // Get RGB value of the pixel
24.       ValR := ScanData^.rgbRed;
25.       ValG := ScanData^.rgbGreen;
26.       ValB := ScanData^.rgbBlue;
27.
28.       MonoByte := round(0.2125 * ValR + 0.7154 * ValG + 0.0721 * ValB);
29.
30.       ResultData^.rgbRed:=MonoByte;
31.       ResultData^.rgbGreen:=MonoByte;
32.       ResultData^.rgbBlue:=MonoByte;
33.
34.       Inc(ScanData);
35.       Inc(ResultData);
36.     end;
37.   end;
38.   Image7.Picture.Bitmap.EndUpdate;
39. end;
40.
« Last Edit: December 24, 2019, 10:45:29 am by fpauw »

#### trheo

• Newbie
• Posts: 2
##### Re: Convert a picture to Gray
« Reply #21 on: October 21, 2021, 09:23:38 am »
Please, does anyone have an idea on how to convert directly Image1 to grey (without creating a new Image) ?

Thank you !!

#### Ally

• New Member
• Posts: 22
##### Re: Convert a picture to Gray
« Reply #22 on: October 21, 2021, 10:20:41 am »
Hallo trheo,

rhsBitmapGrayscale uses TLazIntfImage, which speeds up processing significantly.

Code: Pascal  [Select][+][-]
1. // rhsBitmapGrayscale
2. // ----------------------------------------------------------------------------
3.
4. unit rhsBitmapGrayscale;
5.
6. {\$mode objfpc}{\$H+}
7.
8. interface
9.
10. uses
11.   SysUtils, Classes, Graphics, IntfGraphics, FPImage;
12.
13.   procedure BitmapGrayscale(BM: TCustomBitmap; R, G, B: Single);
14.
15. implementation
16.
17. procedure BitmapGrayscale(BM: TCustomBitmap; R, G, B: Single);
18. var
19.   IntfImg: TLazIntfImage = nil;
20.   x, y: Integer;
21.   TempColor: TFPColor;
22.   Gray: Word;
23. begin
24.   try
25.     IntfImg := BM.CreateIntfImage;
26.
27.     IntfImg.BeginUpdate;
28.     for y := 0 to IntfImg.Height - 1 do
29.       for x := 0 to IntfImg.Width - 1 do
30.       begin
31.         TempColor := IntfImg.Colors[x, y];
32.         Gray := Round(TempColor.Red * R + TempColor.Green * G + TempColor.Blue * B);
33.         TempColor.Red := Gray;
34.         TempColor.Green := Gray;
35.         TempColor.Blue := Gray;
36.         IntfImg.Colors[x, y] := TempColor;
37.       end;
38.     IntfImg.EndUpdate;
39.
41.   finally
42.     IntfImg.Free;
43.   end;
44. end;
45.
46. end.

Here is another example for the use of rhsBitmapGrayscale.

Code: Pascal  [Select][+][-]
1. BitmapGrayscale(Image1.Picture.Bitmap, 0.30, 0.59, 0.11);  // Neutral filter
2. BitmapGrayscale(Image1.Picture.Bitmap, 1.00, 0.00, 0.00);  // Red filter
3. BitmapGrayscale(Image1.Picture.Bitmap, 0.00, 1.00, 0.00);  // Green filter
4. BitmapGrayscale(Image1.Picture.Bitmap, 0.00, 0.00, 1.00);  // Blue filter
5. BitmapGrayscale(Image1.Picture.Bitmap, 0.00, 0.50, 0.50);  // Cyan filter
6. BitmapGrayscale(Image1.Picture.Bitmap, 0.50, 0.00, 0.50);  // Magenta filter
7. BitmapGrayscale(Image1.Picture.Bitmap, 0.50, 0.50, 0.00);  // Yellow filter

« Last Edit: October 21, 2021, 10:33:43 am by Ally »

#### trheo

• Newbie
• Posts: 2
##### Re: Convert a picture to Gray
« Reply #23 on: October 21, 2021, 10:45:39 am »
Thank you very much Ally

#### wp

• Hero Member
• Posts: 9051
##### Re: Convert a picture to Gray
« Reply #24 on: October 21, 2021, 11:46:46 am »
If the input bitmap is in pf24Bit pixelformat every r,g,b component is stored as 1 byte. After converting to grayscale by Ally's code, the 24Bit pixelformat stays the same, but r,g,b have the same value. Even worse, if the input bitmap is pf32Bit. It would be more memory-efficient to store the gray value only once, like in pf8bit.
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

#### Ally

• New Member
• Posts: 22
##### Re: Convert a picture to Gray
« Reply #25 on: October 21, 2021, 12:28:17 pm »
Hello wp,

that's true, of course.
But in the case of images with an alpha channel, the transparency would be lost.