【问题标题】:Issue converting an image to gray scale in Lazarus在 Lazarus 中将图像转换为灰度的问题
【发布时间】:2021-03-20 15:01:07
【问题描述】:

我写了一个名为gray_scaleprocedure,它假设有一个输入TImage 组件,将它包含的图像转换为灰度,然后在同一个TImage 组件中打印它。它的问题是它打印黑色图像。我的代码在下面,请注意我创建了一个名为img2: TPicture 的局部变量,其目的是充当过程输入和输出之间的中间阶段。

procedure gray(var img1: TImage);
var
  i,j: Integer;
  y: integer;
  color: TColor;
  img2: TPicture;
begin
  i := 0; j := 0;
  img2 := TPicture.create;
  img2.Bitmap.Width:= img1.width;
  img2.Bitmap.Height:= img1.height;
  for i := 0 to img1.width  do begin
    for j := 0 to img1.height do begin
      y:= trunc((255 * luminance(img1,i,j)));
      color := RGBToColor(byte(y), byte(y), byte(y));
      img2.Bitmap.Canvas.DrawPixel(i,j, TColorToFPColor(color));
    end;
    img1.Picture.Assign(img2);
  end;
end;                                                 

【问题讨论】:

  • 使用调试器,您是否检查过每个像素的颜色并不总是 0?
  • 如果您使用支持 AlphaChannel 但未设置 AlphaChannel 的位图格式,您的输出正是您所期望的。我不熟悉 Lazarus 的默认设置,但如果您的 TPicture 使用 AlphaChannel 支持的格式,您将需要在每个像素上设置 AlphaChannel。
  • fpiette:颜色总是不为 0!
  • @MiqueasGamero - 你检查过 AlphaChannel - 对于任何 RGB 值,AlphaChannel 为 0 意味着没有绘制任何内容......在我看来就像你在这里看到的一样。
  • 嗯,我会尽快检查 AlphaChannel,我会在这里更新。谢谢!

标签: delphi image-processing pascal freepascal lazarus


【解决方案1】:

看看这段代码,你有两个嵌套循环。

  for i := 0 to img1.width  do begin
    for j := 0 to img1.height do begin
      y:= trunc((255 * luminance(img1,i,j)));
      color := RGBToColor(byte(y), byte(y), byte(y));
      img2.Bitmap.Canvas.DrawPixel(i,j, TColorToFPColor(color));
    end;
    img1.Picture.Assign(img2);
  end;

在内循环之后,您将img2 分配给img1.Picture,您将在访问外循环后继续阅读。结果,img1 在外循环进入第二次迭代时变为空(最左边的像素列除外)。

修改代码如下:

  for i := 0 to img1.width  do begin
    for j := 0 to img1.height do begin
      y:= trunc((255 * luminance(img1,i,j)));
      color := RGBToColor(byte(y), byte(y), byte(y));
      img2.Bitmap.Canvas.DrawPixel(i,j, TColorToFPColor(color));
    end;
  end;
  img1.Picture.Assign(img2);

TPicture 命名为img2 也会产生误导,尤其是当img1 指代TImage 时。

此外,为了提高代码效率,您应该考虑以下几点。最重要的是在扫描线的帮助下一次扫描一行位图图像。

Look at this SO post

【讨论】:

  • 你是对的!我不得不重写我的代码,但我没有意识到你指出了什么。谢谢!
  • @DelphiCoder 您声称:AFAIK,在 Lazarus/FreePascal 中没有 ScanLine 您可以轻松地查看自己进行验证。 TBitmap 继承(通过其他类)从 TRasterImage 声明 property ScanLine[Row: Integer]: Pointer read GetScanLine; platform;
  • 有趣,谢谢!几年前我试图让一些代码与 Delphi 和 Lazarus 兼容时找不到。
  • @DelphiCoder 由于Graphics 单元包含在大多数程序中,并带有声明的变量:bmp: TBitmap,您只需键入bmp.Sc 即可获得Scanline 的建议。找的不多,但没关系。干杯;)
【解决方案2】:
unit rhsBitmapGrayscale;

interface

uses
  SysUtils, Classes, Graphics, IntfGraphics, FPImage;

  procedure BitmapGrayscale(BM: TCustomBitmap; R, G, B: Single);

implementation

// BitmapGrayscale(Bitmap, 0.30, 0.59, 0.11);  // ISO-Neutral-Gray

procedure BitmapGrayscale(BM: TCustomBitmap; R, G, B: Single);
var
  IntfImg: TLazIntfImage = nil;
  x, y, w, h: Integer;
  TempColor: TFPColor;
  Gray: Word;
begin
  try
    IntfImg := BM.CreateIntfImage;

    w := IntfImg.Width - 1;
    h := IntfImg.Height - 1;

    IntfImg.BeginUpdate;
    for y := 0 to h do
      for x := 0 to w do
      begin
        TempColor := IntfImg.Colors[x, y];
        Gray := Round(TempColor.Red * R + TempColor.Green * G + TempColor.Blue * B);
        TempColor.Red := Gray;
        TempColor.Green := Gray;
        TempColor.Blue := Gray;
        IntfImg.Colors[x, y] := TempColor;
      end;
    IntfImg.EndUpdate;

    BM.LoadFromIntfImage(IntfImg);
  finally
    IntfImg.Free;
  end;
end;

end.

使用 TLazIntfImage 可以提高处理速度。 通过红、绿、蓝的参数,可以单独影响结果。

这里有一些例子:

BitmapGrayscale(Image1.Picture.Bitmap, 0.30, 0.59, 0.11);  // Neutral filter
BitmapGrayscale(Image1.Picture.Bitmap, 1.00, 0.00, 0.00);  // Red filter
BitmapGrayscale(Image1.Picture.Bitmap, 0.00, 1.00, 0.00);  // Green filter
BitmapGrayscale(Image1.Picture.Bitmap, 0.00, 0.00, 1.00);  // Blue filter
BitmapGrayscale(Image1.Picture.Bitmap, 0.00, 0.50, 0.50);  // Cyan filter
BitmapGrayscale(Image1.Picture.Bitmap, 0.50, 0.00, 0.50);  // Magenta filter
BitmapGrayscale(Image1.Picture.Bitmap, 0.50, 0.50, 0.00);  // Yellow filter

【讨论】:

  • 请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。
  • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。 proper explanation 将通过展示为什么这是解决问题的好方法,并使其对有其他类似问题的未来读者更有用,从而大大提高其长期价值。请edit您的回答添加一些解释,包括您所做的假设。
猜你喜欢
  • 2015-07-26
  • 1970-01-01
  • 2013-01-03
  • 2010-11-20
  • 1970-01-01
相关资源
最近更新 更多