AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia weniger Scanline aufrufe ... Graustufenbild

weniger Scanline aufrufe ... Graustufenbild

Ein Thema von bernhard_LA · begonnen am 10. Feb 2024 · letzter Beitrag vom 6. Apr 2024
Antwort Antwort
Seite 1 von 4  1 23     Letzte » 
bernhard_LA

Registriert seit: 8. Jun 2009
Ort: Bayern
1.124 Beiträge
 
Delphi 11 Alexandria
 
#1

weniger Scanline aufrufe ... Graustufenbild

  Alt 10. Feb 2024, 17:24
unter https://blog.dummzeuch.de/2019/12/12...lls-in-delphi/
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;
  Mit Zitat antworten Zitat
Kas Ob.
Online

Registriert seit: 3. Sep 2023
227 Beiträge
 
#2

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 11. Feb 2024, 09:11
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 :
https://learn.microsoft.com/en-gb/wi...ith-16-bit-rgb
and if we talk Windows Bitmap then this might give a little insight too https://en.wikipedia.org/wiki/BMP_file_format

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:
      if Pixel.Blue > Threshold then Pixel.Blue := Threshold;
      if Pixel.red > Threshold then Pixel.red := Threshold;
      if Pixel.Green > Threshold then Pixel.Green := Threshold;
after performing the compare and adjust you need to repack the pixel bits, or perform this on the bits directly.

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.
  Mit Zitat antworten Zitat
Kas Ob.
Online

Registriert seit: 3. Sep 2023
227 Beiträge
 
#3

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 11. Feb 2024, 09:35
Found a resource might be helpful at last.

https://stackoverflow.com/questions/...-grayscale-bmp

From the first answer, though the question and the code is to make a gray scale 8bit bitmap from colored
Code:
            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);
This line is adjusting the palette (i was looking for this word!!) i used lookup table or predefined color table.
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.473 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#4

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 11. Feb 2024, 10:40
Ich habe in der Unit u_dzGraphicUtils, auf der der Code im Blogpost ursprünglich basierte, weitere Funktionen zur Bitmap-Bearbeitung, die auch mit 8 Bit (Graustufen) und 32 Bit (TBitmap32) arbeiten. Vielleicht hilft Dir das ja weiter. Vermutlich kann man sie relativ leicht auch an 16 Bit anpassen (wenn man weiß, wie die Farben oder Graustufen kodiert werden. Es kan sogar sein, dass in der Unit auch Code für 12 und 16 Bit Graustufen vorhanden ist. Es ist schon ewig her, ich erinnere mich nicht mehr wirklich daran.

(Die Unit ist Teil meiner dzlib.)
Thomas Mueller
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.473 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 11. Feb 2024, 10:51
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,
Actually, the 8 bit greyscale (Mono8) is a common format used in machine vision cameras. To use that in bitmaps, they need a greyscale palette. Which then makes access quite easy, because the byte value directly represents the brightness of the pixel.

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..
As for generic 8 bit color bitmaps you are right: These are very uncommon nowadays, because memory and storage size are no longer limited and graphics cards / monitors generally use 24 bits or even more.
Thomas Mueller
  Mit Zitat antworten Zitat
Kas Ob.
Online

Registriert seit: 3. Sep 2023
227 Beiträge
 
#6

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 11. Feb 2024, 11:18
Actually, the 8 bit greyscale (Mono8) is a common format used in machine vision cameras. To use that in bitmaps, they need a greyscale palette. Which then makes access quite easy, because the byte value directly represents the brightness of the pixel.
That makes sense, thank you for the links.
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
744 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 11. Feb 2024, 14:55
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;
Michael Gasser
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.211 Beiträge
 
Delphi 12 Athens
 
#8

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 11. Feb 2024, 15:18
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)


Dein Code ist viel zu kompliziert
Da es überall der selbe Code/Threshold ist ...

Delphi-Quellcode:
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;
Man bräuchte nur "einmal" ScanLine abzufragen, da alle Lines hintereinander liegen,
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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (11. Feb 2024 um 15:26 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.473 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#9

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 11. Feb 2024, 15:21
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;
Von wegen langsam:
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.
Thomas Mueller

Geändert von dummzeuch (11. Feb 2024 um 15:27 Uhr)
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
744 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 11. Feb 2024, 15:26
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.
Michael Gasser
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:52 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz