代码之家  ›  专栏  ›  技术社区  ›  Javid

用delphi将PNGImage转换为灰度

  •  4
  • Javid  · 技术社区  · 14 年前

    你好 这是我的代码:

    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。 我该怎么办?

    5 回复  |  直到 14 年前
        1
  •  8
  •   Andreas Rejbrand    14 年前

    这是如何灰显位图。(而且,是的,如果你想把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;
    
        2
  •  8
  •   Mason Wheeler    14 年前

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

    试试这个:

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

    你会得到一个比简单平均值稍高的性能,不过除非你在一个非常大的图像上,否则它可能不会很明显。

        3
  •  3
  •   Vivian Mills    14 年前

    以下代码来自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组件的作者发布,可以在代码中心找到,它展示了如何做其他事情,如Alpha混合两个图像、旋转、覆盖等。 CodeCentral Link

        4
  •  1
  •   HeartWare    14 年前

    这真的应该是@Mason将RGB转换为灰度的例行程序的注释,但是由于我不知道如何编写注释显示代码,所以我将它改为一个答案。

    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公式还是什么,但它们似乎在我的程序中起作用。

        5
  •  -1
  •   ComputerSaysNo    14 年前