Преобразование PNGIMAGE в серого с использованием Delphi
Вопрос
Привет, вот мой код:
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;
Это не работает, и это делает Pic Muny, я уверен, что это из-за RGbreserved. что я должен делать?
Решение
Это как серо -растровое изображение. (И, да, если вы хотите, чтобы серо -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;
Другие советы
Ответ Андреаса даст вам хорошее, быстрое приближение, но вы потеряете качество, потому что красный, зеленый и синий не смешиваются с равными интенсивностью в человеческом глазах. Если вы хотите «сделать это правильно», вместо
grey := (rgbBlue + rgbGreen + rgbRed) div 3;
попробуй это:
grey := round(rgbRed * .3) + round(rgbGreen * .59) + round(rgbBlue * .11);
Вы получите небольшую производительность из -за простого среднего, хотя, вероятно, это не будет заметно, если вы не на очень большом изображении.
Я знаю, что вопрос уже ответил, но вот мой 2C стоит ...
Следующий код поступает из пакета 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, который показывает, как сделать другие вещи, такие как альфа-смешивание двух изображений, вращение, наложение и т. Д. CodeCentral Link.
Это действительно должно было быть комментарий к рутине @ Mason, чтобы повернуть RGB в Greyscale, но так как я не знаю, как сделать комментарий Show Code, я делаю это ответом вместо этого.
Вот как я делаю преобразование:
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 или что-то еще, но они, кажется, работают в моих программах :-).
Почему бы вам просто не назначить его TJpegimage, установите свойство GreyScale JPEG на True, а затем обратитесь к Tpngimage?!