使用delphi将PNGImage转换为灰度

发布于 2024-09-30 20:55:09 字数 582 浏览 1 评论 0原文

你好呀 这是我的代码:

procedure TForm4.Button1Click(Sender: TObject);
var
  png: TPNGImage;
  data: PRGBQarray;
  p: ^tagRGBQuad;
  i, o: integer;
begin
  png := TPNGImage.Create;
  try
    png.LoadFromFile('C:\Untitled.png');
    for o := 1 to 100 do
    begin
      data:=png.Scanline[o];
      for I := 1 to 400 do
      begin
        p := @data^[i];
        p.rgbGreen := p.rgbBlue;
        p.rgbRed := p.rgbGreen;
      end;
    end;
    img.picture.Assign(png);
  finally
    png.Free;
  end;
end;

它不起作用并且使图片变得混乱,我确定这是因为 rgbReserved 的原因。 我应该怎么办?

hi there
here it is my code:

procedure TForm4.Button1Click(Sender: TObject);
var
  png: TPNGImage;
  data: PRGBQarray;
  p: ^tagRGBQuad;
  i, o: integer;
begin
  png := TPNGImage.Create;
  try
    png.LoadFromFile('C:\Untitled.png');
    for o := 1 to 100 do
    begin
      data:=png.Scanline[o];
      for I := 1 to 400 do
      begin
        p := @data^[i];
        p.rgbGreen := p.rgbBlue;
        p.rgbRed := p.rgbGreen;
      end;
    end;
    img.picture.Assign(png);
  finally
    png.Free;
  end;
end;

it doesn't work and it makes the pic messy, I'm sure it's because of the rgbReserved.
what should i do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

谜兔 2024-10-07 20:55:09

安德烈亚斯的答案将为您提供一个良好、快速的近似值,但您会失去一些质量,因为在人眼中红色、绿色和蓝色不会以相同的强度混合。如果你想“做对”,而不是

grey := (rgbBlue + rgbGreen + rgbRed) div 3;

试试这个:

grey := round(rgbRed * .3) + round (rgbGreen * .59) + round(rgbBlue * .11);

与简单平均值相比,您的性能会受到一些影响,尽管除非您使用的是非常大的数据,否则可能不会很明显。图像。

Andreas's answer will give you a good, fast approximation, but you'll lose some quality, because red, green and blue don't mix with equal intensities in the human eye. If you want to "get it right", instead of

grey := (rgbBlue + rgbGreen + rgbRed) div 3;

try this:

grey := round(rgbRed * .3) + round(rgbGreen * .59) + round(rgbBlue * .11);

You'll get a bit of a performance hit over the simple average, though it probably won't be noticeable unless you're on a very large image.

路弥 2024-10-07 20:55:09

这就是将位图灰化的方法。 (是的,如果您想灰化 PNG,您首先需要从中获取位图数据。我认为 VCL 会为您完成此操作。)

type
  PRGB32Array = ^TRGB32Array;
  TRGB32Array = packed array[0..MaxInt div SizeOf(TRGBQuad)-1] of TRGBQuad;

procedure MakeGrey(Bitmap: TBitmap);
var
  w, h: integer;
  y: Integer;
  sl: PRGB32Array;
  x: Integer;
  grey: byte;
begin
  Bitmap.PixelFormat := pf32bit;
  w := Bitmap.Width;
  h := Bitmap.Height;
  for y := 0 to h - 1 do
  begin
    sl := Bitmap.ScanLine[y];
    for x := 0 to w - 1 do
      with sl[x] do
      begin
        grey := (rgbBlue + rgbGreen + rgbRed) div 3;
        rgbBlue := grey;
        rgbGreen := grey;
        rgbRed := grey;
      end;
  end;
end;

示例用法:

procedure TForm4.Button1Click(Sender: TObject);
var
  bm: TBitmap;
begin
  bm := TBitmap.Create;
  try
    bm.LoadFromFile('C:\Users\Andreas Rejbrand\Pictures\Porträtt, litet, kvadratiskt.bmp');
    MakeGrey(bm);
    Canvas.Draw(0, 0, bm);
  finally
    bm.Free;
  end;
end;

This is how to greyify a bitmap. (And, yes, if you want to greyify a PNG, you first need to get the bitmap data out of it. I think the VCL will do this for you.)

type
  PRGB32Array = ^TRGB32Array;
  TRGB32Array = packed array[0..MaxInt div SizeOf(TRGBQuad)-1] of TRGBQuad;

procedure MakeGrey(Bitmap: TBitmap);
var
  w, h: integer;
  y: Integer;
  sl: PRGB32Array;
  x: Integer;
  grey: byte;
begin
  Bitmap.PixelFormat := pf32bit;
  w := Bitmap.Width;
  h := Bitmap.Height;
  for y := 0 to h - 1 do
  begin
    sl := Bitmap.ScanLine[y];
    for x := 0 to w - 1 do
      with sl[x] do
      begin
        grey := (rgbBlue + rgbGreen + rgbRed) div 3;
        rgbBlue := grey;
        rgbGreen := grey;
        rgbRed := grey;
      end;
  end;
end;

Sample usage:

procedure TForm4.Button1Click(Sender: TObject);
var
  bm: TBitmap;
begin
  bm := TBitmap.Create;
  try
    bm.LoadFromFile('C:\Users\Andreas Rejbrand\Pictures\Porträtt, litet, kvadratiskt.bmp');
    MakeGrey(bm);
    Canvas.Draw(0, 0, bm);
  finally
    bm.Free;
  end;
end;
著墨染雨君画夕 2024-10-07 20:55:09

我知道问题已经得到解答,但这是我的 2c 价值...

以下代码来自 Thany 生成的 PNGComponents 包 (PngFunctions.pas)。

//
//The Following code comes from the PNGComponents package from Thany...
//
procedure MakeImageGrayscale(Image: TPNGObject; Amount: Byte = 255);

  procedure GrayscaleRGB(var R, G, B: Byte);
  var
     X: Byte;
  begin
  X := Round(R * 0.30 + G * 0.59 + B * 0.11);
  R := Round(R / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  G := Round(G / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  B := Round(B / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  end;

var
   X, Y, PalCount: Integer;
   Line: Pointer;
   PaletteHandle: HPalette;
   Palette: array[Byte] of TPaletteEntry;
begin
//Don't do anything if the image is already a grayscaled one
if not (Image.Header.ColorType in [COLOR_GRAYSCALE, COLOR_GRAYSCALEALPHA])
then begin
     if Image.Header.ColorType = COLOR_PALETTE
     then begin
          //Grayscale every palette entry
          PaletteHandle := Image.Palette;
          PalCount := GetPaletteEntries(PaletteHandle, 0, 256, Palette);
          for X := 0 to PalCount - 1
          do GrayscaleRGB(Palette[X].peRed, Palette[X].peGreen, Palette[X].peBlue);
          SetPaletteEntries(PaletteHandle, 0, PalCount, Palette);
          Image.Palette := PaletteHandle;
          end
     else begin
          //Grayscale every pixel
          for Y := 0 to Image.Height - 1
          do begin
             Line := Image.Scanline[Y];
             for X := 0 to Image.Width - 1
             do GrayscaleRGB(PRGBLine(Line)^[X].rgbtRed, PRGBLine(Line)^[X].rgbtGreen, PRGBLine(Line)^[X].rgbtBlue);
             end;
          end;
     end;
end;

有一组例程最初由 PNGImage 组件的作者发布,可以在 Code Central 上找到,它展示了如何执行其他操作,例如 Alpha 混合两个图像、旋转、叠加等。 CodeCentral 链接

I know the question has already been answered but here is my 2c worth...

The following code comes from the PNGComponents package (PngFunctions.pas) produced by Thany.

//
//The Following code comes from the PNGComponents package from Thany...
//
procedure MakeImageGrayscale(Image: TPNGObject; Amount: Byte = 255);

  procedure GrayscaleRGB(var R, G, B: Byte);
  var
     X: Byte;
  begin
  X := Round(R * 0.30 + G * 0.59 + B * 0.11);
  R := Round(R / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  G := Round(G / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  B := Round(B / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  end;

var
   X, Y, PalCount: Integer;
   Line: Pointer;
   PaletteHandle: HPalette;
   Palette: array[Byte] of TPaletteEntry;
begin
//Don't do anything if the image is already a grayscaled one
if not (Image.Header.ColorType in [COLOR_GRAYSCALE, COLOR_GRAYSCALEALPHA])
then begin
     if Image.Header.ColorType = COLOR_PALETTE
     then begin
          //Grayscale every palette entry
          PaletteHandle := Image.Palette;
          PalCount := GetPaletteEntries(PaletteHandle, 0, 256, Palette);
          for X := 0 to PalCount - 1
          do GrayscaleRGB(Palette[X].peRed, Palette[X].peGreen, Palette[X].peBlue);
          SetPaletteEntries(PaletteHandle, 0, PalCount, Palette);
          Image.Palette := PaletteHandle;
          end
     else begin
          //Grayscale every pixel
          for Y := 0 to Image.Height - 1
          do begin
             Line := Image.Scanline[Y];
             for X := 0 to Image.Width - 1
             do GrayscaleRGB(PRGBLine(Line)^[X].rgbtRed, PRGBLine(Line)^[X].rgbtGreen, PRGBLine(Line)^[X].rgbtBlue);
             end;
          end;
     end;
end;

There is a set of routines, that was originally published by the author of the PNGImage components, that can be found on Code Central that shows how to do other things like Alpha blending two images, rotation, overlay, etc. CodeCentral Link

因为看清所以看轻 2024-10-07 20:55:09

这确实应该是对 @Mason 将 RGB 转换为 GreyScale 的例程的注释,但由于我不知道如何使注释显示代码,所以我将其作为答案。

这就是我进行转换的方式:

FUNCTION RGB2GRAY(R,G,B : BYTE) : BYTE; Register; ASSEMBLER;
  ASM
                IMUL    EAX,19595
                IMUL    EDX,38470
                IMUL    ECX,7471
                ADD     EAX,EDX
                ADD     EAX,ECX
                SHR     EAX,16
  END;

FUNCTION GreyScale(C : TColor) : TColor; Register; ASSEMBLER;
  ASM
                MOVZX   EDX,AH
                MOV     ECX,EAX
                SHR     ECX,16
                MOVZX   EAX,AL
                CALL    RGB2GRAY
                MOVZX   EAX,AL
                MOV     AH,AL
                SHL     EAX,8
                MOV     AL,AH
  END;

我不知道它是否是 NTSC 公式或其他什么,但它们似乎在我的程序中工作:-)。

This really should have been a comment to @Mason's routine to turn RGB into GreyScale, but since I don't know how to make a comment show code, I'm making it an answer instead.

This is how I do the conversion:

FUNCTION RGB2GRAY(R,G,B : BYTE) : BYTE; Register; ASSEMBLER;
  ASM
                IMUL    EAX,19595
                IMUL    EDX,38470
                IMUL    ECX,7471
                ADD     EAX,EDX
                ADD     EAX,ECX
                SHR     EAX,16
  END;

FUNCTION GreyScale(C : TColor) : TColor; Register; ASSEMBLER;
  ASM
                MOVZX   EDX,AH
                MOV     ECX,EAX
                SHR     ECX,16
                MOVZX   EAX,AL
                CALL    RGB2GRAY
                MOVZX   EAX,AL
                MOV     AH,AL
                SHL     EAX,8
                MOV     AL,AH
  END;

I don't know if it is NTSC formula or whatever, but they seem to work in my programs :-).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文