la conversione di un PNGImage in scala di grigi con Delphi
Domanda
ci hi qui è il mio codice:
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;
non funziona e rende il disordinato pic, sono sicuro che sia a causa della rgbReserved. che cosa devo fare?
Soluzione
Questo è il modo di greyify una bitmap. (E, sì, se si vuole greyify un PNG, è necessario prima di ottenere i dati bitmap fuori di esso. Credo che la VCL farà questo per voi.)
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;
Utilizzo di esempio:
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;
Altri suggerimenti
La risposta di Andreas vi darà una buona, veloce approssimazione, ma dovrete perdere un po 'di qualità, perché il rosso, verde e blu non si mescolano con intensità pari a l'occhio umano. Se si vuole "farlo bene", al posto di
grey := (rgbBlue + rgbGreen + rgbRed) div 3;
provare questo:
grey := round(rgbRed * .3) + round(rgbGreen * .59) + round(rgbBlue * .11);
Si otterrà un po 'di un calo di prestazioni sopra la media semplice, anche se probabilmente non sarà visibile se non sei su un grande immagine.
So che la questione è già stata risolta, ma ecco la mia 2c pena ...
Il seguente codice viene dal pacchetto PNGComponents (PngFunctions.pas) prodotto da 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;
C'è un insieme di routine, che è stato originariamente pubblicato dall'autore dei componenti PNGImage, che può essere trovato sul codice centrale che mostra come fare altre cose come l'alpha blending due immagini, la rotazione, overlay, ecc CodeCentral collegamento
Questo in realtà avrebbe dovuto essere un commento a @ di routine di Mason per trasformare RGB in scala di grigi, ma dal momento che non so come fare un codice commento spettacolo, sto rendendo una risposta, invece.
Questo è come io faccio la conversione:
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;
Non so se è NTSC formula o qualsiasi altra cosa, ma sembrano funzionare nei miei programmi: -).
Perché non solo assegnazione a un TJPEGImage, impostare la proprietà in scala di grigio JPEG su true e quindi assegnare di nuovo a TPNGImage?!