![]() |
weniger Scanline aufrufe ... Graustufenbild
unter
![]() gib es ein code fragment um mit weniger Scanline Zugriffen eine Bild/Bitmap Bearbeitung durch zuführen. Meine Komplette Umsetzung ist unten eingefügt. Frage : Diese Methode ist auf Assert(_InBmp.PixelFormat = pf24bit); also 24bit Bitmaps ausgelegt. Wie würde eine Code Variante aussehen welche pf8bit und pf16 bit auch unterstützt ?
Delphi-Quellcode:
var FImageOut : TBitmap;
begin FImageOut := TBitmap.CReate; try CreateSpecialImage ( FImage , FImageOut, 100 ); OutImage.Picture.Bitmap.Assign(FImageOut); finally // FImageOut.Free; end;
Delphi-Quellcode:
uses Types, classes, Vcl.Graphics;
type TRgbTriple = packed record // do not change the order of the fields, do not add any fields Blue: Byte; Green: Byte; Red: Byte; end; PRgbTriple =^TRgbTriple; TRgbTripleArray = packed array[0..MaxInt div SizeOf(TRgbTriple) - 1] of TRgbTriple; PRgbTripleArray = ^TRgbTripleArray; procedure CreateSpecialImage(const InBmp, OutBmp: TBitmap; Threshold: Byte); implementation function AddToPtr(const _Ptr: Pointer; _Offset: NativeInt): Pointer; inline; begin Result := Pointer(NativeInt(_Ptr) + _Offset); end; function PtrDiff(const _Ptr1, _Ptr2: Pointer): NativeInt; inline; begin Result := NativeInt(_Ptr1) - NativeInt(_Ptr2); end; procedure CreateSpecialImage(const InBmp, OutBmp: TBitmap; Threshold: Byte); var BytesPerPixel: NativeInt; InScanLine0: Pointer; InBytesPerLine: NativeInt; OutBytesPerLine: NativeInt; OutScanLine0: Pointer; InPixel: PRgbTriple; OutPixel: PRgbTriple; Pixel: TRgbTriple; x, y: Integer; Height, Width : Integer; begin Height := inBMP.Height; Width := inBmp.Width; OutBmp.Width := Width; OutBmp.Height := Height; InBmp.PixelFormat := pf24bit; OutBmp.PixelFormat := pf24bit; BytesPerPixel := SizeOf(Pixel); InScanLine0 := InBmp.ScanLine[0]; InBytesPerLine := NativeInt(InBmp.ScanLine[1]) - NativeInt(InScanLine0); OutScanLine0 := OutBmp.ScanLine[0]; OutBytesPerLine := NativeInt( OutBmp.ScanLine[1]) - NativeInt(OutScanLine0); OutPixel := OutScanLine0; for y := 0 to Height - 1 do begin for x := 0 to Width - 1 do begin InPixel := AddToPtr(InScanLine0, InBytesPerLine * y + x * BytesPerPixel); Pixel := InPixel^; /// /// doSomething(Pixel); /// if Pixel.Blue > Threshold then Pixel.Blue := Threshold; if Pixel.red > Threshold then Pixel.red := Threshold; if Pixel.Green > Threshold then Pixel.Green := Threshold; OutPixel := AddToPtr(OutScanLine0, OutBytesPerLine * y + x * BytesPerPixel); OutPixel^ := Pixel; end; end; end; |
AW: weniger Scanline aufrufe ... Graustufenbild
Hi,
First you need to define 16bit and 8bit bit per pixel format, because there is many ! 8bit and 16bit are so old when different systems had different color space, example : 8bit pixel either colored or gray, in colored case is it 332 or 233 for RGB or BGR ... Same goes for 16bit, is there Alpha, in case of alpha then mostly it is 5551 or 1555 if not then 555 or 565, is it BGR(A) or (A)RGB... Searching for good resource is semi-useless, again unless you have one specific format to follow,.. the best i could find is this : ![]() and if we talk Windows Bitmap then this might give a little insight too ![]() notice 1) in the first link from Microsoft, the pixel decode is done by masking and bit shifting, again there is only two mentioned here RGB 555 and RGB 565, not mention for Alpha. 2) For converting these color, 5bit or 6bit to 8bit per color you need to multiply by 8 or by 4, this operation is bit shifting by 3 or 2, making a single color of 5bit [0..31] go in [0..255] and for 6bit [0..63] do the same. 3) you can change threshold mentioned in the code within the range of [0..31] or shift it accordingly to fit the 5/6 bit : talking about the following part
Code:
after performing the compare and adjust you need to repack the pixel bits, or perform this on the bits directly.
if Pixel.Blue > Threshold then Pixel.Blue := Threshold;
if Pixel.red > Threshold then Pixel.red := Threshold; if Pixel.Green > Threshold then Pixel.Green := Threshold; As for 8bit the as above but 8bit bitmap are very rare and almost dead format and most importantly it is very wide in range !, this format or to be more accurate the lack of unified/standardized format goes to 80s and the its color space is might hard to work with, Why working with 8bit Windows Bitmap (or 8bit DIB) is hard ? because When we talk Windows Bitmap then the there is a table define these 8bit colors representing 256 color value predefined to be used within this 8bit bitmap, so such bitmap will have lookup table with 256 value, the the pixel with grab the value form there, these values can be 8bit, 16bit.. 24bit color value.. Now on bright side for 8bit Windows Bitmap with lookup table, you can adjust the lookup table against the threshold, you don't need to walk the pixels at all ! Hope that help and clear. |
AW: weniger Scanline aufrufe ... Graustufenbild
Found a resource might be helpful at last.
![]() From the first answer, though the question and the code is to make a gray scale 8bit bitmap from colored
Code:
This line is adjusting the palette (i was looking for this word!!) i used lookup table or predefined color table.
var entry = bmp.Palette.Entries[index];
var gray = (int)(0.30 * entry.R + 0.59 * entry.G + 0.11 * entry.B); newPalette.Entries[index] = Color.FromArgb(gray, gray, gray); |
AW: weniger Scanline aufrufe ... Graustufenbild
Ich habe in der Unit
![]() (Die Unit ist Teil meiner ![]() |
AW: weniger Scanline aufrufe ... Graustufenbild
Zitat:
![]() Zitat:
|
AW: weniger Scanline aufrufe ... Graustufenbild
Zitat:
|
AW: weniger Scanline aufrufe ... Graustufenbild
Dein Code ist viel zu kompliziert und dadurch auch langsam.
So könntest du es für 24Bit tun. Und für die anderen Formate natürlich ähnlich.
Delphi-Quellcode:
procedure CreateSpecialImage(const InBmp, OutBmp: TBitmap; Threshold: Byte);
var OutPixel: PRgbTriple; height, width, x, y: Integer; begin OutBmp.Assign(InBmp); Height := OutBmp.Height; Width := OutBmp.Width; for y := 0 to Height - 1 do begin OutPixel := OutBmp.ScanLine[y]; for x := 0 to Width - 1 do begin if OutPixel^.Blue > Threshold then OutPixel^.Blue := Threshold; if OutPixel^.Red > Threshold then OutPixel^.Red := Threshold; if OutPixel^.Green > Threshold then OutPixel^.Green := Threshold; inc(OutPixel); end; end; end; |
AW: weniger Scanline aufrufe ... Graustufenbild
Im CreateSpecialImage kann ein IF/Assert nicht schaden, wenn das PixelFormat nicht stimmt, sonst kann man sich hier den Speicher zerschießen (z.B. wenn pf1 bis bf16 und somit der Speicher kleiner wäre)
Zitat:
Delphi-Quellcode:
Man bräuchte nur "einmal" ScanLine abzufragen, da alle Lines hintereinander liegen,
var OutByte: PByte; // mit aktiver Pointer-Arithmetic
for y := 0 to Height - 1 do begin OutByte := OutBmp.ScanLine[y]; for x := Width * 3 - 1 downto 0 do begin if OutByte^ > Threshold then OutByte^ := Threshold; Inc(OutByte); end; end; for y := 0 to Height - 1 do begin OutByte := OutBmp.ScanLine[y]; for OutByte := OutByte to OutByte + Width * 3 - 1 do if OutByte^ > Threshold then OutByte^ := Threshold; end; aber da die Linien an im Speicher ausgerichtet/aligned sind (auf 4 Bytes), sind eventuell nachträglich noch Bytes eingefügt. Wenn Width ein Vielfaches von 4, dann nicht ... sonst nach jeder Line aufgerundet werden oder man arbeitet z.B. mit pf32bit. Außerdem aufpassen, dass die Lines meistens unten anfangen zu zählen, also die letzte Line zuerst im Speicher liegt. |
AW: weniger Scanline aufrufe ... Graustufenbild
Zitat:
Dein Code ruft TBitmap.Scanline Width*Height-mal auf. Jeder dieser Aufrufe ist extrem lahm, wenn auch schon wesentlich schneller als der Zugriff auf TBitmap.Canvas.Pixel[x,y]. Genau das war der Punkt in meinem Blog-Post, auf den Bernhard im ersten Post verwiesen hat. Und da er jedes Pixel sowieso nochmal anpasst, kann er auch gleich die erste Bitmap pixelweise lesen und die zweite schreiben, das spart dann auch noch das TBitmap.Assign. Edit: Und Himitsu hat recht: Da die Grenze für alle Farben dieselbe ist, kann man die RGB-Bytes auch einfach mittels einer Schleife von 3*Width byteweise abarbeiten statt ein PRgbTriple zu verwenden. Ob das von der Performance her nochmal einen großen Unterschied macht, weiß ich aber nicht. Die Vermeidung der Scanline-Aufrufe bringt deutlich mehr. |
AW: weniger Scanline aufrufe ... Graustufenbild
Dann Sorry - macht es so wie es besser ist - ich lasse aber meinen Code als sehr schlechtes Beispiel stehen; ein Mahnmal für "wie man es nicht tun sollte". Danke für die wertvollen Inputs.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:14 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz