AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia weniger Scanline aufrufe ... Graustufenbild
Thema durchsuchen
Ansicht
Themen-Optionen

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 2  1 2      
Benutzerbild von dummzeuch
dummzeuch

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

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 12. Feb 2024, 17:15
Nebenbei: Wenn ich dein 8Bit Graustufenbeispiel richtig interpretiere, gehst du davon aus, dass Src die gleiche Palette verwendet wie du sie für Dst in deinem Code festlegst.
Das ist korrekt. Ich habe noch nie ein 8Bit-Graustufen-Bild gesehen, das eine andere Palette als die Standard-Palette benutzt hat, welche dem Pixel-Wert x den RGB-Wert RGB(x,x,x) zuordnet, also das, was Kameras unter MONO8 verstehen. Es mag natürlich sein, dass es solche Spezialfälle gibt, aber der Aufwand, sie zu unterstützen, ist mir einfach viel zu groß.
Thomas Mueller
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 12. Feb 2024, 17:19
Aber natürlich hätte man da dann auch die Qual der Wahl
* einfach nur die kleine Farbtabelle umrechnen
* oder ben jedes Pixel, wo man dann aber aufassen muß, dass wirklich nur eine sortierte Grautabelle vorliegt.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
bernhard_LA

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

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 12. Feb 2024, 17:51
very Basic Nachfrage : Die Definitionen in windows unit wurden nicht verwendet, weil zu langsam ... ?


Delphi-Quellcode:

{$ALIGN 1}
  PRGBTriple = ^TRGBTriple;
  {$EXTERNALSYM tagRGBTRIPLE}
  tagRGBTRIPLE = record
    rgbtBlue: Byte;
    rgbtGreen: Byte;
    rgbtRed: Byte;
  end;
  TRGBTriple = tagRGBTRIPLE;
  {$EXTERNALSYM RGBTRIPLE}
  RGBTRIPLE = tagRGBTRIPLE;
{$ALIGN ON}
  Mit Zitat antworten Zitat
Michael II

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

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 12. Feb 2024, 20:38
Hallo Thomas dein in #15 gezeigter 24Bit Bitmap Code auf #1 angewendet läuft bei mir nun in 1820ms (1000 Mal 1000x1000Pixel) durch.

Delphi-Quellcode:
procedure DZeuch(_SrcBmp, _DstBmp: TBitmap; Threshold: Byte);
const
  BytesPerPixel = 3;
var
  x: Integer;
  y: Integer;
  w: Integer;
  h: Integer;
  SrcLine: PByte;
  DstLine: PByte;
  SrcPixel: PByte;
  DstPixel: PByte;
  BytesPerLine: Integer;
begin
  _SrcBmp.PixelFormat := pf24bit;
  _DstBmp.PixelFormat := pf24bit;
  w := _SrcBmp.Width;
  h := _SrcBmp.Height;
  _DstBmp.SetSize( w, h);

  if h = 0 then
    Exit; //==>

  BytesPerLine := ((w * 8 * BytesPerPixel + 31) and not 31) div 8;

  SrcLine := _SrcBmp.ScanLine[0];
  DstLine := _DstBmp.ScanLine[0];
  for y := 0 to h - 1 do begin
    SrcPixel := SrcLine;
    DstPixel := DstLine;
    for x := 0 to w - 1 do begin
      PdzRgbTriple(DstPixel)^ := PdzRgbTriple(SrcPixel)^;
      if PdzRgbTriple(DstPixel)^.Blue > Threshold then PdzRgbTriple(DstPixel)^.Blue := Threshold;
      if PdzRgbTriple(DstPixel)^.Green > Threshold then PdzRgbTriple(DstPixel)^.Green:= Threshold;
      if PdzRgbTriple(DstPixel)^.Red > Threshold then PdzRgbTriple(DstPixel)^.Red:= Threshold;
      Inc(SrcPixel, BytesPerPixel);
      Inc(DstPixel, BytesPerPixel);
    end;
    Dec(SrcLine, BytesPerLine);
    Dec(DstLine, BytesPerLine);
  end;
end;
Du hast Recht. Assign macht (für den vorliegenden Fall) viele unnötige Dinge. Wenn ich darauf verzichte (man gewinnt ca. 0.5ms), dann läuft mein Code in 810ms:

Delphi-Quellcode:
procedure CreateSpecialImage3(const InBmp, OutBmp : TBitmap; Threshold: Byte);
var // InBmp, OutBmp pf24Bit
  SrcScanline, DstScanline : Pointer;
  OutPixel: PRGBTriple;
  deltascan : NativeInt;
  height, width, x, y: Integer;
begin
  Height := InBmp.Height;
  Width := InBmp.Width;
  OutBmp.PixelFormat := pf24Bit;
  OutBmp.SetSize(width,height);
  if height = 0 then exit;

  DstScanline := OutBmp.ScanLine[height-1];
  SrcScanline := InBmp.ScanLine[height-1];

  if height > 1 then
  deltascan := NativeInt(OutBmp.ScanLine[height-2]) - NativeInt(DstScanline) else deltascan := 0;

  Move( SrcScanline^, DstScanline^, deltascan*height);

  for y := Height - 1 downto 0 do
  begin
    OutPixel := DstScanline;
    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;
     inc(PByte(DstScanline), deltascan);
  end;
end;
Natürlich gibt's wie erwähnt wurde noch Assembler und breite Register (habe ich auch schon mal woanders genutzt - mein Rechner wurde dann wegen der Hitze runter getaktet...), Grpahics32, GDI+ (Clone)... - aber 1000 Bilder zu 1000*1000*24 Bit Bitmaps mit den "doofen" alten Grafikfunktionen in 810ms ist schon recht schnell.
Michael Gasser

Geändert von Michael II (13. Feb 2024 um 15:24 Uhr)
  Mit Zitat antworten Zitat
bernhard_LA

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

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 12. Feb 2024, 22:06
@ Michael :

die Zeile will bei mir nicht :

Delphi-Quellcode:
 
  ....

  Move( InBmp.ScanLine[height-1]^, OutBmp.ScanLine[height-1]^, abs(deltascan)*height);
  ---
Angehängte Grafiken
Dateityp: png move.png (4,3 KB, 26x aufgerufen)
  Mit Zitat antworten Zitat
Michael II

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

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 12. Feb 2024, 23:26
Hallo bernhard_LA ich kann aus deiner Grafik nix lesen. (Tipp: Meldungen in der IDE kann man auch als Text kopieren .)

Hast du mal einen Break Point gesetzt und geprüft, ob die beteiligten Elemente initialisiert sind (InBmp muss Pixelformat=pf24Bit aufweisen, OutBmp muss vor dem Aufruf erzeugt worden sein [sollte ich wohl in der Prozedur prüfen und meckern, falls nicht OK]) und sinnvolle Werte gespeichert sind? Ich nehme mal an, dass height >= 1 ist (sonst würde es bereits beim Ermitteln von deltascan knallen).

Ich habe den Code oben angepasst. Neu wird auf height=0 und beim Ermitteln von deltascan auf height>1 getestet.

In gewissen Anwendungsfällen willst du eventuell gar nicht InBmp und OutBmp verwenden, sondern nur eine BitMap; zum Beispiel TuWas(b). Dann gibt's nix zu moven.

In anderen Fällen verwendest du InBmp und OutBmp, aber du berechnest aus InBmp direkt OutBmp. Dann musst du auch nix moven, benötigst aber in der Schleife auch einen Zeiger für die InBmp Pixel.
Michael Gasser

Geändert von Michael II (13. Feb 2024 um 01:40 Uhr)
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
229 Beiträge
 
#7

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 13. Feb 2024, 08:27
@Michael II, Nice ! this is the right way, by changing the operation from read and write in two different places stressing the CPU cache, do it once in sequential and fast move after that perform the the local operation in one place, CPU can perform 2-3 reads and one write per cycle, but let be real, if Delphi compiler managed to spit code that perform one read in 3 cycle i consider this is a Delphi win.

This way will win with Delphi every time :
Code:
  Move( InBmp.ScanLine[height-1]^, OutBmp.ScanLine[height-1]^, abs(deltascan)*height);

  for y := 0 to Height - 1 do
  begin
    OutPixel := DstScanline;
    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(OutPixels);
    end ;
     inc(PByte(DstScanline), deltascan);
  end ;
One thing though :
Check if InBmp is (=) OutBmp then skip the copy altogether.
  Mit Zitat antworten Zitat
Michael II

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

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 14. Feb 2024, 19:57
Hallo bernhardLA

für die Bearbeitung von 8Bit Graustufenbildern kannst du fast 1:1 den Code kopieren. Du musst einfach daran denken, dass ein Pixel nur noch 1 Byte Platz einnimmt.

Hier habe ich dir noch eine recht schnelle Variante für die Umwandlung RGB > GrauGrauGrau (24Bit -> 24Bit).

Du kannst den Farbwerten RGB Gewichte fr,fg,fb (fr+fg+fb sollte <=1 sein) zuordnen.

Da ich hier im UInt64 Bereich rechne (32 Bit würden wohl für diese Aufgabe auch reichen...), sind die Prozeduren v.a. in Windows64 (1 Mio Pixel im Millisekundenbereich) schnell (Windows32 ca. 7 Mal langsamer).

Wenn du immer mit festen Gewichten (fr,fg,fb) rechnen willst, dann lohnt es sich die Prozedur grau_test in Zeile OutPixel^.Blue := ( OutPixel^.Red * mg + OutPixel^.green* mb + OutPixel^.blue* mr + round_sh ) shr sh; entsprechend anzupassen und für mg,mb,mr,sh Konstanten zu verwenden. (Speedgewinn ca. 33%). mr,mg,mb und sh berechnest du mittels intRGB.


Viel Spass.

Delphi-Quellcode:
procedure intRGB( r, g, b : extended; var ir, ig, ib, shift : UInt64);
var
  i : Integer;
  mul : uint64;
  bestshift : UInt64;
  abserr, besterr, hr,hg,hb : extended;
  // Ziel: Bei der Ermittlung der Grauwerte aus (rot,grün,blau) auf Fliesskommazahlen verzichten
  // IN Gewichte r,g,b grau:= r*rot+g*grün+b*blau
  // OUT ir,ig,ib,shift wobei grau := (ir*rot + ig*grün + ib*blau + 1 shl (shift-1)) shr shift
begin
  shift := 1;
  mul := 2;
  besterr := 4;
  hr := r;
  hg := g;
  hb := b;

  for i := 2 to 56 do
  begin
    hr := hr+hr;
    hg := hg+hg;
    hb := hb+hb;

    abserr := (abs(round(hr)-hr) + abs(round(hg)-hg) + abs(round(hb)-hb));

    if abserr < besterr then
    begin
      besterr := abserr;
      bestshift := shift;
    end;
    (* lesbarer wöre (weiter oben) abserr := .../mul
    schneller ist aber, auf die Division durch mul zu verzichten und stattdessen
    besterr zu verdoppeln:
    *)

    besterr := besterr + besterr;
    inc(shift);
    mul := mul shl 1;
  end;

  shift := bestshift;
  mul := UInt64( 1 ) shl shift;
  ir := round( r*mul);
  ig := round( g*mul);
  ib := round( b*mul);
end;

procedure grau_test(const InBmp : TBitmap; fr:extended=0.299; fg:extended= 0.587; fb:extended = 0.114 );
var // InBmp OUT : pf24Bit
  SrcScanline : Pointer;
  OutPixel: PRGBTriple;
  deltascan : NativeInt;
  height, width, x, y : Integer;
  round_sh, mr,mg,mb, sh : UInt64;

begin
  Height := InBmp.Height;
  Width := InBmp.Width;
  if height = 0 then exit;

  // Standard YCbCr ITU R470 grau = 0.299*R+0.587*G+0.114*B
  // Alternativ G = 0,2126 R + 0,7152 G + 0,0722
  // GIMP 0.21 × R + 0.72 × G + 0.07 × B


  intRGB( fr,fg,fb, mr,mg,mb, sh );
  round_sh := UInt64( 1 ) shl (sh-1);

  SrcScanline := InBmp.ScanLine[height-1];

  if height > 1 then
  deltascan := NativeInt(InBmp.ScanLine[height-2]) - NativeInt(SrcScanline) else deltascan := width*3;

  for y := Height - 1 downto 0 do
  begin
    OutPixel := SrcScanline;
    for x := 0 to Width - 1 do
    begin
      OutPixel^.Blue := ( OutPixel^.Red * mg + OutPixel^.green* mb + OutPixel^.blue* mr + round_sh ) shr sh;
      OutPixel^.Green := OutPixel^.Blue;
      OutPixel^.Red := OutPixel^.Blue;
      inc(OutPixel);
    end;
    inc(PByte(SrcScanline), deltascan);
  end;
end;
Kleine Korrektur: In der vorher veröffentlichten RGB RGB Prozedur sollte stehen:
if height > 1 then
deltascan := ... else deltascan := width*3; (Damit es auch für Bitmaps mit Höhe 1 klappt.)


Ein Bild mit 753x1200 Bildpunkten auf Notebook 11th Gen Intel(R) Core(TM) i7-11800H wird in 966 Mikrosekunden in Grau umgewandelt. Das kann nur Delphi .
Michael Gasser

Geändert von Michael II (15. Feb 2024 um 10:18 Uhr)
  Mit Zitat antworten Zitat
Michael II

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

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 17. Feb 2024, 20:42
One thing though :
Check if InBmp is (=) OutBmp then skip the copy altogether.
Hallo Kas Ob wie vergleichst du BitMaps schnell? Via Streams dauert bei mir der Vergleich für 1 Mio Pixel Bitmaps viel länger als das Rechnen; lohnt sich also nicht (ausser vielleicht für sehr grosse Bitmaps - habe ich nicht getestet). Oder meinst du nur Handle Vergleich?

Und dann noch Sorry für den intRGB Joke

Delphi-Quellcode:
procedure intRGB( dr, dg, db : double; var ir, ig, ib, shift : UInt64 );
const
  faktor = UInt64(1) shl 54;
begin
  shift := 54;
  ir := Round(dr * faktor);
  ig := Round(dg * faktor);
  ib := Round(db * faktor);
end;
tut's natürlich auch.
Michael Gasser
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
229 Beiträge
 
#10

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 18. Feb 2024, 08:26
One thing though :
Check if InBmp is (=) OutBmp then skip the copy altogether.
Oder meinst du nur Handle Vergleich?
That what i meant.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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:22 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