Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Scanline erklären (https://www.delphipraxis.net/42007-scanline-erklaeren.html)

steppo 11. Mär 2005 19:43


Scanline erklären
 
Hi Leute,

kann mir jemand erklären wie Scanline funktioniert?

Habe in diversen Beispielen zwar Code gefunden, werde aber nicht schlau daraus.
Was für mich unverständlich ist,
wofür brauche ich Scanline.

In der Funktion wird doch über For-Schleifen jedes Pixel ausgelesen. Das heißt über die x und y Koordinaten. Wofür brauche ich da noch Scanline.

Auch habe ich bei der Benutzung von Scanline (welches sich ja immer noch in zwei for-schleifen befindet, keine Performancesteigerung festgestellt. Es wird immer noch jedes Pixel durchlaufen.

Welches Ergebnis soll Scanline eigentlich liefern.
1. Die Farbe eines Pixels?
2. Eine Kombination aus allen Farbwerten in einer Reihe?

Keine Ahnung!

Wer kann helfen?

Gruß
Steppo

Khabarakh 11. Mär 2005 19:52

Re: Scanline erklären
 
Scanline gibt dir einen Pointer auf das erste Pixel einer Zeile zurück, durch Inkrementieren von diesem kannst du auch die anderen Pixel ansprechen. Es wird also jeweils ein Pixel abgefragt.
Die Pixel-Property ist seehr langsam und macht intern noch einige Umwege. Über Scanline kannst du aber sofort auf den Speicher zugreifen, dadurch ist diese Variante viel schneller.
Noch schneller kannst du mit der GR32-Lib auf Pixel zugreifen, die bietet auch noch andere nette Sachen (Transparenz, Layer, Float-Koordinaten...).

sniper_w 11. Mär 2005 21:17

Re: Scanline erklären
 
Zitat:

Noch schneller kannst du mit der GR32-Lib auf Pixel zugreifen,
Oh ja. :love:

Muetze1 11. Mär 2005 21:21

Re: Scanline erklären
 
Moin!

Und wie die Daten bei dem Zeiger von ScanLine[] vorliegen hängt von der PixelFormat Property ab.

pf1bit - jedes Byte enthält 8 Pixel, jedes Bit des Bytes ist ein Pixel
pf4bit - jedes Nibble enthält einen Index für die Farbpalette des Bildes. Die RGB Werte erhälst du, wenn du die Farbpalette für den im Nibble gefundenen Index abfragst. (Nibble = Halbbyte = 4 Bit; ergo: 2 Pixel pro Byte)
pf8bit - jedes Byte stellt ein Pixel da und das Byte enthält wieder einen Index für die Palette des Bildes.
pf15bit - Ein Pixel besteht auf einem Word (16 Bit) wobei aber nur 3x 5 Bit benutzt werden - 5 Bit pro Farbanteil (rot, grün, blau). Dies sind direkt die Farben.
pf16bit - wie pf15Bit, nur das diesmal der AFAIR grüne Farbanteil als Ausnahme 6 Bit anstatt 5 Bit zur Verfügung hat. Grund: Das Auge ist empfindsamer auf dem Farbanteil...
pf24bit - ein Pixel besteht aus 3 Bytes (rot, grün, blau) und enthalten die direkten RGB Farben. Diese Farbtiefe ist nicht zu empfehlen, da jeder 2. Pixel an einer ungeraden Adresse liegt. Besser ist es 32 Bit zu nutzen, dort ist jeder Pixel aligned und der Prozessor muss keine extra Lesezyklen einlegen um die Farbwerte des Pixels zu ermitteln.
pf32bit - genauso wie 24 Bit, nur das hier noch ein Füllbyte vorhanden ist (im Normalfall ohne Funktion) und somit ein Pixel auf 4 Byte kommt, was dem Alignment von einem 32 Bit Prozessor entspricht. Es gibt z.B. bei DirectX Farbmodien wo das 4. Byte für den Alphakanal benutzt wird (und auch bei der WinAPI: AlphaBlend).

Im Normalfall musst du die bei pf15bit und pf16bit gefundenen RGB Werte noch um 2 Bits nach links shiften um ordentliche RGB Werte zu erhalten...

So, das war ein Kurzanriss...

MfG
Muetze1

steppo 11. Mär 2005 21:51

Re: Scanline erklären
 
Das heißt, wenn ich etwas suche und wirklich jeden Pixel überprüfen muß, sind alle Funktionen gleich langsam.
Richtig?

dizzy 11. Mär 2005 21:59

Re: Scanline erklären
 
Nein!

Pixels ist imho eigentlich immer die schlechteste Wahl, vor allem wenn du jeden Pixel wirklich "von Hand" anpacken musst. Meine Empfehlung ist für Bitmap-basierte Dinge auch immer die G32 ;). (Weil ich den Umgang mit Scanline nicht sehr komfortabel finde, und ich zumindest eigentlich immer mit 32-Bit Bildern zu tun hab.)
Die Pixels-Property eines TBitmap32 (der G32-Lib) dürfte etwa gleich schnell sein wie Scanline.

Muetze1 11. Mär 2005 22:03

Re: Scanline erklären
 
Moin!

Sie sind gleich schnell, da TBitmap32 auch über GetDIBits() geht.

Und nein, ScanLine ist nicht langsamer. Pixels[] nutzt nicht die ScanLine Eigenschaft sondern die WinAPI um die Farbes eines Pixels zu ermitteln und diese Funktion ist mehr als lahm. Die ScanLine[] Methode ist in so fern schon schneller, da sie einen Zeiger auf alle Pixel einer Zeile liefert. Du musst nur noch den Zeiger erhöhen. Dieses ist ein immenser Geschwindigkeitsvorteil gegenüber Windows jedesmal mit 'zig Aufrufen erneut für jeden Pixel zu fragen...

MfG
Muetze1

steppo 11. Mär 2005 22:33

Re: Scanline erklären
 
Ok Leute,
das ist der Qelltext, den ich bis jetzt habe.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  BitMap: TBitMap;
  y, x: integer;
  P: PByteArray;
begin
  BitMap := TBitMap.create;

  try
    BitMap.LoadFromFile('Datei.bmp');

      BitMap.PixelFormat:= pf24Bit;

    for y := 0 to BitMap.Height - 1 do
    begin
      P := BitMap.ScanLine[y];
      ProgressBar1.StepIt;
      for x := 0 to BitMap.Width - 1 do
      begin
        P[x] := y;
        Caption := inttostr(x) + ' \ ' + inttostr(y) + ' \ ' +
          ColorToString(Canvas.Pixels[x, y]) + ' \ ' + inttostr(P[x]);
        if (Canvas.Pixels[x, y] = clblack) or (ColorToString(Canvas.Pixels[x,
          y]) = '#000000') then
          Sleep(1000);
        Canvas.Pixels[x, y] := clBlue;
      end;
    end;

  finally
    BitMap.Free;
  end;
end;
Ich färbe einfach jedes gelesene weiße Pixel in ein blaues Pixel ein.
Womit arbeite ich jetzt im Endeffekt.

Mit ScanLine oder mit Pixel?
Meiner Meinung nach kann ich diesen Vorgang auch mit zwei einfachen Schleifen verwirklichen.
Mit gleicher Performance.
Oder?

Muetze1 11. Mär 2005 23:07

Re: Scanline erklären
 
Moin!

Du arbeitest mit dem langsamen Pixels[] Zugriff. Den Wert den du aus ScanLine rausholst benutzt du nicht. Ausserdem hast du bei 24 Bit 3 Bytes pro Pixel, somit greifst du völlig falsch auf die Pixeldaten zu. Und 24 Bit sind von Haus aus langsam, da der Prozessor extra Lesezyklen pro Pixel einfügen muss...

Ok, ScanLine, weisse Pixel in blaue:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  BitMap: TBitMap;
  y, x: integer;
  P: PRGBQuad; // definiert in Windows.pas
begin
  BitMap := TBitMap.create;

  try
    BitMap.LoadFromFile('Datei.bmp');
    BitMap.PixelFormat:= pf32Bit;

    for y := 0 to BitMap.Height - 1 do
    begin
      P := BitMap.ScanLine[y];

      for x := 0 to BitMap.Width - 1 do
      begin
        If ( P^.rgbRed = $ff ) And ( P^.rgbGreen = $ff ) And ( P^.rgbBlue = $ff ) Then
        Begin
          P^.rgbRed  := 0;
          P^.rgbGreen := 0;
          // P^.rgbBlue := $ff; <-- haben wir ja schon, siehe IF Bedingung
        End;
        Inc(P);
      end;
    end;
  finally
    BitMap.Free;
  end;
end;
Und dazu eine reine Pixels[] Routine:

Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var
  BitMap: TBitMap;
  y, x: integer;
begin
  BitMap := TBitMap.create;

  try
    BitMap.LoadFromFile('Datei.bmp');
    BitMap.PixelFormat:= pf32Bit;     // gleiche Grundlagen schaffen

    for y := 0 to BitMap.Height - 1 do
    begin
      for x := 0 to BitMap.Width - 1 do
      begin
        If ( BitMap.Canvas.Pixels[x, y] = clWhite ) Then
          Bitmap.Canvas.Pixels[x, y] := clBlue;
      end;
    end;
  finally
    BitMap.Free;
  end;
end;
So, vergleiche die beiden Routinen mal nach Geschwindigkeit - und benutze dabei am besten aucb Bilder die deutlich grösser als 300x300 sind...

MfG
Muetze1

steppo 11. Mär 2005 23:24

Re: Scanline erklären
 
Ich sehe nichts. Das Programm läuft zwar aber ich sehe keine Farbänderung.
Wo änderst du die Pixelfarbe?

steppo 11. Mär 2005 23:26

Re: Scanline erklären
 
Habs gefunden.

Oh Man. Das nennt mann Performance.
Ok jetzt sehe ich den Unterschied mehr als deutlich.

Danke für deine Hilfe.

steppo 11. Mär 2005 23:37

Re: Scanline erklären
 
Doch noch eine Frage.

Was passiert hier:
Delphi-Quellcode:
          P^.rgbRed  := 0;
          P^.rgbGreen := 0;
          P^.rgbBlue := $ff; <-- haben wir ja schon, siehe IF Bedingung
Habe die Einfärbung unter dem oben genannten Code vorgenommen.
Delphi-Quellcode:
          Canvas.Pixels[x, y] := clBlue;

Muetze1 11. Mär 2005 23:52

Re: Scanline erklären
 
Moin!

Zitat:

Zitat von steppo
Was passiert hier:
Delphi-Quellcode:
          P^.rgbRed  := 0;
          P^.rgbGreen := 0;
          P^.rgbBlue := $ff; <-- haben wir ja schon, siehe IF Bedingung

Im 32 Bit Farben Modus besteht ein Pixel aus 4 Bytes: 1 Byte Rotanteil, 1 Byte Grünanteil, 1 Byte Blauanteil und 1 Füllbyte. Die TRGBQuad Struktur setzt sich aus den 4 Elementen zusammen. Darin hast du 4 Elemente definiert: rgbRed, rgbGreen, rgbBlue und rgbReserved. Das sind die 4 Elemente und deren Funktion sollte klar sein.
ScanLine liefert dir immer ein Zeiger auf das 1. Byte der jeweiligen Zeile zurück und ich habe mir die Variable P als PRGBQuad definiert, also ein Zeiger auf diese oben angesprochene TRGBQuad Struktur. Damit habe ich also beim zuweisen von P := ScanLine[y]; sofort einen Zeiger auf das erste Pixel und ich erhalte damit sofort z.B. den Rotanteil des Pixel mit P.rgbRed (das ^ vor dem . ist ab Delphi 5 optional).
So, nun zu deiner Frage: Dieser 3-zeiler weisst die Farbe Blau dem Pixel zu. Die Farbe blau besteht aus 0 Rotanteil, 0 Grünanteil und vollen 255 Blauanteil. Diese weise ich zu ($ff = hexadezimalzahl FF = 255 dezimal).

Zitat:

Zitat von steppo
Habe die Einfärbung unter dem oben genannten Code vorgenommen.
Delphi-Quellcode:
          Canvas.Pixels[x, y] := clBlue;

? Wie ist das zu verstehen? Hast du in der ScanLine Routine nochmals diese Zeile eingefügt? Warum? Dann ist doch der gesamte Geschwindigkeitsvorteil von ScanLine wieder dahin??!?!

MfG
Muetze1

steppo 11. Mär 2005 23:59

Re: Scanline erklären
 
Habe meine Zeile (mit gleichem Einwand wie du eben bezogen auf Geschwindigkeitsverlust) unter deinen dreizeiler eingefügt.
Habe keinen Verlust Festgestellt.

Grund:

Bei deinem Code wird kein Pixel eingefärbt.
Habe also keinen direkten Vergleich.

Die Seite bleibt bei deinem Code unverändert.
Entschuldige

Muetze1 12. Mär 2005 00:03

Re: Scanline erklären
 
Moin!

Zitat:

Zitat von steppo
Grund:

Bei deinem Code wird kein Pixel eingefärbt.
Habe also keinen direkten Vergleich.

Dann sag/schreib das und nicht:

Zitat:

Zitat von steppo
Habs gefunden.

Oh Man. Das nennt mann Performance.
Ok jetzt sehe ich den Unterschied mehr als deutlich.

Ich klicke mal schnell eine Beispiel App zusammen samt Zeitmessung und dann sehen wir weiter... mom...

MfG
Muetze1

steppo 12. Mär 2005 00:07

Re: Scanline erklären
 
Entschuldigung, war ein Schnellschuß meinerseits.

steppo 12. Mär 2005 00:21

Re: Scanline erklären
 
Du hast recht, die Performance leidet erheblich darunter.
OK.

Dennoch wird keine Pixeländerung vorgenommen.
Wenn ich dich richtig verstanden habe, werden in diesem Beispiel die Farbanteile von Rot und Grün auf null gesetzt, sodaß nur der Blaue Anteil übrig bleibt.
Warum wird dieser nicht angezeigt?

Muetze1 12. Mär 2005 00:31

Re: Scanline erklären
 
Liste der Anhänge anzeigen (Anzahl: 2)
Moin!

Das ist ein Fehler in deinem Code - mein Code habe ich übernommen in die Beispiel App und der klappt einwandfrei. Schau es dir an...

Also der Unterschied ist auch sehr gut zu erkennen, siehe Screenshot...

MfG
Muetze1

steppo 12. Mär 2005 00:49

Re: Scanline erklären
 
Das sieht gut aus.
Habe jetzt den Qullcode eins zu eins übernommen (copy/past).
Lediglich den Pfad zu meiner datei angepasst.
Keine Pixelfarbänderung.

OK.

Werde morgen weitermachen.

Danke für deine Hilfe

Gute Nacht


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:40 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