Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Pixel gleicher Farbe zählen (https://www.delphipraxis.net/116050-pixel-gleicher-farbe-zaehlen.html)

dominikkv 22. Jun 2008 17:30


Pixel gleicher Farbe zählen
 
Hi

ich brauche von euch die schnellste Möglichkeit die Anzahl Pixel gleicher Farbe herauszufinden.
Ganz einfaches Beispiel:
Delphi-Quellcode:
type
  TColorArray = Array of TColor;
  TAnzahlArray = Array of Integer;

function CountColor(aBitmap: TBitmap; Colors: TColorArray ): TAnzahlArray ;
var
  I, J, K: Integer;
  Unten, Oben: Integer;
begin
  Unten := Low(Colors); // Um nacher nicht so oft die Funktionen zu benutzen
  Oben := High(Colors);

  SetLength(Result, Succ(Oben));

  for I := Unten to Oben do
    Result[I] := 0;

  for I := 0{oder 1?} to aBitmap.Width do
    for J := 0{oder 1?} to aBitmap.Height do
      for K := Unten to Oben do
        if aBitmap.Canvas.Pixels[I, J] = Color[K] then
          Inc(Result[K]);
end;

procedure bla;
var
  Colors: TColorArray;
  Anzahl: TAnzahlArray;
begin
  SetLength(Colors, 2);
  Colors[0] := clRed;
  Colors[1] := clBlue;
  Anzahl := CountColor(meinBitmap, Colors);
  showmessage(Format('%d Pixel sind Rot, %d Pixel sind Blau', [Anzahl[0], Anzahl[1]));
end;
Ich hoffe ihr versteht was ich meine. Ich bin mir sicher das geht noch schneller als bei meinem Beispiel...
Hat jemand von euch ne Idee?

mfg.Dominik

Apollonius 22. Jun 2008 17:35

Re: Pixel gleicher Farbe zählen
 
Nimm TBitmap.Scanline.

dominikkv 22. Jun 2008 17:58

Re: Pixel gleicher Farbe zählen
 
Zitat:

Zitat von Apollonius
Nimm TBitmap.Scanline.

Ich kenne ScanLine zwar nicht, habe mal aber hier im Forum gesucht und das ist dabei rausgekommen:
Delphi-Quellcode:
type
  TColorArray = Array of TColor;
  TAnzahlArray = Array of Integer;
  TLine = Array[1..3] of Byte;

function CountColor(aBitmap: TBitmap; Colors: TColorArray): TAnzahlArray;
var
  I, J, K: Integer;
  Unten, Oben: Integer;
  Line: ^TLine;
begin
  Unten := Low(Colors); // Um nacher nicht so oft die Funktionen zu benutzen
  Oben := High(Colors);

  SetLength(Result, Succ(Oben));

  for I := Unten to Oben do
    Result[I] := 0;

  for I := 0{oder 1?} to aBitmap.Height do
    begin
      Line := aBitmap.ScanLine[I];
      for J := 0{oder 1?} to aBitmap.Width do
        for K := Unten to Oben do
          if Line[J] = Colors[K] then
            Inc(Result[K]);
    end;
end;
Leider kommt in der Zeile
Delphi-Quellcode:
if Line[J] = Colors[K] then
eine AV. Wo ist mein Fehler?

Neutral General 22. Jun 2008 18:12

Re: Pixel gleicher Farbe zählen
 
Zitat:

Zitat von dominikkv
Leider kommt in der Zeile
Delphi-Quellcode:
if Line[J] = Colors[K] then
eine AV. Wo ist mein Fehler?

Mich wundert es, das der code überhautp compiliert...

Delphi-Quellcode:
if Line[J]{!}^{/!} = Colors[K] then // dereferenzieren nicht vergessen!
// ==>
if Array[1..3] of Byte = TColor then
// Das wird nichts oder?
Außerdem geht dein Array nur von 1-3 und nicht bis j (Das Bild wird wohl breiter als 3 Pixel sein ;) )

Line^ enthält den RGB wert, des ersten Pixels der gescannten Reihe.

Delphi-Quellcode:
Line^[1] = Rot
Line^[2] = Grün
Line^[3] = Blau
Wenn du jetzt den nächsten Pixel haben willst, musst du den Zeiger nach jedem j-Schleifendurchlauf inkrementieren:

Delphi-Quellcode:
inc(Line);
Der Vergleich wäre dann so möglich:

Delphi-Quellcode:
if RGB(line[1],line[2],line[3]) = Colors[k] then
Ich hoffe du hast es ungefähr verstanden ;)

Gruß
Neutral General

marabu 22. Jun 2008 18:24

Re: Pixel gleicher Farbe zählen
 
Hallo Dominik,

bitte auch den Gültigkeitsbereich der Laufvariablen (off by one) beachten.

Grüße vom marabu

dominikkv 22. Jun 2008 18:47

Re: Pixel gleicher Farbe zählen
 
hey danke für eure Antworten :mrgreen:

ich hab das nun so hingepfrimelt:
Delphi-Quellcode:
type
  TLine = TRGBTriple;

function TPaintEngine.CountColor(Colors: TColorArray): TAnzahlArray;
var
  I, J, K: Integer;
  Unten, Oben: Integer;
  Line: ^TLine;
begin
  Unten := Low(Colors); // Um nacher nicht so oft die Funktionen zu benutzen
  Oben := High(Colors);

  SetLength(Result, Succ(Oben));

  for I := Unten to Oben do
    Result[I] := 0;

  for I := 1 to fBuffer.Height - 1 do
    begin
      Line := fBuffer.ScanLine[I];
      for J := 1 to fBuffer.Width - 1 do
        begin
          for K := Unten to Oben do
            if RGB(line^.rgbtRed,line^.rgbtGreen,line^.rgbtBlue) = Colors[k] then
              Inc(Result[K]);
          Inc(Line);
        end;
    end;
end;
Ergebnis: braucht ca doppelt so viel Zeit wie die Methode über Pixels[I, J] und liefert zudem noch falsche Werte.

littleDave 22. Jun 2008 19:14

Re: Pixel gleicher Farbe zählen
 
Zitat:

Zitat von Neutral General
Delphi-Quellcode:
Line^[1] = Rot
Line^[2] = Grün
Line^[3] = Blau

*ZONK*

In Bitmaps werden die RGB-Werte anders herum gespeichert (BGR):

Delphi-Quellcode:
Line^[1] = Blau
Line^[2] = Grün
Line^[3] = Rot

Neutral General 22. Jun 2008 19:17

Re: Pixel gleicher Farbe zählen
 
Mist, ich war mir nichtmehr sicher :mrgreen:

dominikkv 22. Jun 2008 19:37

Re: Pixel gleicher Farbe zählen
 
Zitat:

Zitat von littleDave
In Bitmaps werden die RGB-Werte anders herum gespeichert (BGR):

Delphi-Quellcode:
Line^[1] = Blau
Line^[2] = Grün
Line^[3] = Rot

Trotzdem falsche Werte:
Delphi-Quellcode:
type
  TLine = array [1..3] of Byte;

function CountColor(aBitmap: TBitmap; Colors: TColorArray): TAnzahlArray;
var
  I, J, K: Integer;
  Unten, Oben: Integer;
  Line: ^TLine;
begin
  Unten := Low(Colors); // Um nacher nicht so oft die Funktionen zu benutzen
  Oben := High(Colors);

  SetLength(Result, Succ(Oben));

  for I := Unten to Oben do
    Result[I] := 0;

  for I := 1 to aBitmap.Height - 1 do
    begin
      Line := aBitmap.ScanLine[I];
      for J := 1 to aBitmap.Width - 1 do
        begin
          for K := Unten to Oben do
            if RGB(line^[3],line^[2],line^[1]) = Colors[k] then
              Inc(Result[K]);
          Inc(Line);
        end;
    end;
end;

Neutral General 22. Jun 2008 19:57

Re: Pixel gleicher Farbe zählen
 
Hi,

... Ich weiß nicht genau was bei dir schief läuft. Ich habe mal selbst eine Funktion geschrieben, die, soweit ich sie getestet habe, funktioniert.

Ich hoffe ich werde nicht erschlagen weil ich fertigen Code poste.

Delphi-Quellcode:
TIntArray = Array of Integer;

function CountColors(bmp: TBitmap; Colors: Array of TColor): TIntArray;
var i,j,k: Integer;
    old: TPixelformat;
    x: PRGBQuad;
    tmp: TColor;
begin
  SetLength(Result,Length(Colors));
  old := bmp.PixelFormat; // Pixelformat sichern
  bmp.PixelFormat := pf32Bit; //Mit 32-Bit Bitmaps gehts schneller
  for i := 0 to bmp.Height-1 do
  begin
    x := bmp.ScanLine[i];
    for j:= 0 to bmp.Width-1 do
    begin
      tmp := RGB(x^.rgbRed,x^.rgbGreen,x^.rgbBlue);
      for k := 0 to High(Colors) do
        if Colors[k] = tmp then
          inc(Result[k]);
      inc(x);
    end;
  end;
  bmp.PixelFormat := old; // Altes Pixelformat wiederherstellen
end;
Gruß
Neutral General

littleDave 22. Jun 2008 20:16

Re: Pixel gleicher Farbe zählen
 
Das wird es wahrscheinlich sein @dominikkv, dein Bitmap hat keine 24/32 Bit.

bmp.PixelFormat := pf32Bit; :arrow: array[0..3] of byte
bmp.PixelFormat := pf24Bit; :arrow: array[0..2] of byte

Mit weniger Bits solltest du nicht rumhantieren, da du sonst die Werte erst "mühsam" in RGB-Werte umrechnen musst. Also schau mal, dass du bei dir
Delphi-Quellcode:
bmp.PixelFormat := pf24Bit;
aufrufst

dominikkv 22. Jun 2008 20:35

Re: Pixel gleicher Farbe zählen
 
Wenn ich das ganze mit pf32Bit mache geht das wirklich ein ganzes Stück schneller!
Und wenn ich bei deiner Function, Neutral General, Result zunächst mit 0 initialisiere kommt auch wirklich das richtige Ergebnis raus 8)

Vielen Dank euch beiden für eure Hilfe :cheers:

2 Fragen habe ich aber noch:
- Wird das ganze mit pf24Bit nochmal schneller?
- Wenn ja, wie komme ich dann zu meinem Farbwert, ich hab ja dann nur 2 Werte in dem Array, für RGB brauche ich aber 3

Neutral General 22. Jun 2008 20:37

Re: Pixel gleicher Farbe zählen
 
Hi,

1. Die 32-Bit Methode ist die schnellste.
2. [0..2] = 3 Einträge (24 Bit), [0..3] = 4 Einträge (32 Bit)

PS: Also bei mir ist das Array schon standardmäßig "genullt"... :gruebel:

Aber wenn du es schon nullen willst dann hätte ich da was für dich:

Delphi-Quellcode:
FillChar(Result[0],Length(Result)*SizeOf(Integer),0);

dominikkv 22. Jun 2008 20:55

Re: Pixel gleicher Farbe zählen
 
Zitat:

Zitat von Neutral General
1. Die 32-Bit Methode ist die schnellste.

Ok, dann werde ich die verwenden.
Zitat:

Zitat von Neutral General
2. [0..2] = 3 Einträge (24 Bit), [0..3] = 4 Einträge (32 Bit)

oh... das fängt bei 0 an... hab ich nicht gesehen :oops:
Darum ist bei mir bei den ersten Versuchen wahrscheinlich immer ein falsches Ergebnis rausgekommen -.-
Zitat:

Zitat von Neutral General
PS: Also bei mir ist das Array schon standardmäßig "genullt"... :gruebel:

Aber wenn du es schon nullen willst dann hätte ich da was für dich:

Delphi-Quellcode:
FillChar(Result[0],Length(Result)*SizeOf(Integer),0);

Bei mir kam da immer ein anderes Ergebnis raus, nachdem ich das dann initialisiert habe wurds richtig...egal^^
Werde jetzt auf jedenfall FillChar verwenden, Danke :stupid:

Nochmal Danke an euch beide

:dp: :love:


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