Recent

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

winni

  • Hero Member
  • *****
  • Posts: 3197
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
  3.   ScanData, ResultData: PRGBQuad;
  4.   ValR, ValG, ValB, monoByte : Byte;
  5.   X, Y: Integer;
  6. begin
  7.   if openpicturedialog1.Execute then
  8.      Begin
  9.        Image1.Picture.LoadFromFile(openpicturedialog1.FileName);
  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

Adding the following...
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. :o

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! :D

This is the result
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. Var
  3.   ScanData, ResultData: PRGBQuad;
  4.   ValR, ValG, ValB, monoByte : Byte;
  5.   X, Y: Integer;
  6. begin
  7.   if openpicturedialog1.Execute then
  8.      Begin
  9.        Image1.Picture.LoadFromFile(openpicturedialog1.FileName);
  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

  • Jr. Member
  • **
  • Posts: 52
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.  
  40.     BM.LoadFromIntfImage(IntfImg);
  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: 11857
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.

Ally

  • Jr. Member
  • **
  • Posts: 52
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.

Slawek

  • New Member
  • *
  • Posts: 43
Re: Convert a picture to Gray
« Reply #26 on: May 23, 2022, 04:10:35 pm »
I refresh the topic because I was looking for a procedure for changing the image to grayscale. But here's a bug that causes if Image1.Stretch is: = True; only part of the image is converted to grayscale.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. Var
  3.   ScanData, ResultData: PRGBQuad;
  4.   ValR, ValG, ValB, monoByte : Byte;
  5.   X, Y: Integer;
  6. begin
  7.   if openpicturedialog1.Execute then
  8.      Begin
  9.        Image1.Picture.LoadFromFile(openpicturedialog1.FileName);
  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.  
To correct it:
Line 16 should read: For Y: = 0 To Image1.Picture.Height-1 Do
And in know 20: For X: = 0 To Image1.Picture.Width-1 Do
Please, does anyone have an idea on how to convert directly Image1 to grey (without creating a new Image) ?

Thank you !!
Just change Image 7 to Image1. Moreover, in my opinion, lines 11, 12, 13, 18, 31 will not be needed then and only one PRGBQuad type variable is enough.
Like this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. Var
  3.   LineData: PRGBQuad;
  4.   ValR, ValG, ValB, monoByte : Byte;
  5.   X, Y: Integer;
  6. begin
  7.   if openpicturedialog1.Execute then
  8.      Begin
  9.        Image1.Picture.LoadFromFile(openpicturedialog1.FileName);
  10.      end;
  11.   Image1.Picture.Bitmap.BeginUpdate;
  12.  
  13.   For Y:=0 To Image1.Picture.Height-1 Do
  14.   Begin
  15.     LineData := Image1.Picture.Bitmap.ScanLine[Y];
  16.     For X:=0 To Image1.Picture.Width-1 Do
  17.     Begin
  18.       //   X, Y, TotalTime, DistCurve: Integer;Point to the pixel location
  19.       // Get RGB value of the pixel
  20.       ValR := LineData^.rgbRed;
  21.       ValG := LineData^.rgbGreen;
  22.       ValB := LineData^.rgbBlue;
  23.  
  24.       MonoByte := round(0.2125 * ValR + 0.7154 * ValG + 0.0721 * ValB);
  25.  
  26.       LineData^.rgbRed:=MonoByte;
  27.       LineData^.rgbGreen:=MonoByte;
  28.       LineData^.rgbBlue:=MonoByte;
  29.  
  30.       Inc(LineData);
  31.     end;
  32.   end;
  33.   Image1.Picture.Bitmap.EndUpdate;
  34. end;  
  35.  

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Convert a picture to Gray
« Reply #27 on: May 23, 2022, 04:31:11 pm »
Hi!

The default graphics of fpc/Lazarus are very restricted and uncomfortable.

Install the BGRAbitmapPack and you solve the problem with only some lines of code:

Code: Pascal  [Select][+][-]
  1. uses ...BGRAbitmap;
  2. ...
  3. procedure TForm1.Button3Click(Sender: TObject);
  4. var tmp: TBGRABitmap;
  5. begin
  6.   if openpicturedialog1.Execute then
  7.        tmp := TBGRABitmap.Create ( openpicturedialog1.FileName) else exit;
  8.   tmp.InplaceGrayscale;
  9.   BGRAReplace (tmp,tmp.resample(Image1.width, Image1.height));
  10.   tmp.Draw (Image1.Canvas,0,0,true);
  11.   tmp.saveToFile('Gray.png');
  12.   tmp.free;
  13. end;
  14.  

Winni

Ally

  • Jr. Member
  • **
  • Posts: 52
Re: Convert a picture to Gray
« Reply #28 on: May 23, 2022, 04:49:55 pm »
Hello,

in the meantime I have created a sample program for my unit rhsBitmapGrayscale.pas.
The program shows how to get different results with different values.

Many greetings Roland

 

TinyPortal © 2005-2018