Autor Beitrag
P_G
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 75

Win XP
Delphi 7 / 8 Enterprise
BeitragVerfasst: Do 29.01.09 10:34 
Hallo,
sehe zur Zeit wohl den Wald vor lauter Bäumen nicht. Ich will ein Bitmap analysieren. Dazu erstelle ich ein Array of Array of TColor (hier fData), um schnell auf die Farbwerte der Pixel zugreifen zu können.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
 
 OrigBmp.HandleType := bmDIB;
 OrigBmp.PixelFormat := pf8bit;
  FOR j := 0 TO OrigBmp.Height-1 DO
  BEGIN
    Row := OrigBmp.Scanline[j];
    FOR i := 0 TO OrigBmp.Width-1 DO
    BEGIN
     fData[I,J].Color := // Was kommt hier hin??? Row[i] nicht!
    END
  END;


Scanline liefert merkwürdige Farbwerte. Die Farbzuweisung durch Row[i] liefert nur schwarz und rot. Kann mir jemand die Augen öffnen?

Gruß, P_G
P_G Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 75

Win XP
Delphi 7 / 8 Enterprise
BeitragVerfasst: Do 29.01.09 11:51 
Irgendjemand? Mir gehen die Ideen aus...
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Do 29.01.09 12:06 
Etwas mehr Code bitte :)

Was hat Row für einen Datentyp?

Wo schiebst du den Pointer weiter?
JayEff
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: Do 29.01.09 12:09 
Schau dir mal meinen FAQ-Beitrag an, der beschreibt, wie man eine Bitmap stufenweise ausgraut :) Dort wird Scanline korrekt angewendet.

Du wirst durt sehen, dass dir Scanline einen Pointer zurückgibt, der am besten als der folgende Datentyp aufgefasst werden kann:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
type TColorRec = record
  r, g, b: Byte;

  type PColorRec = ^TColorRec;
(Aus dem Kopf...) Was du nun tun musst, ist zunächst den Inhalt des pointers auslesen wie in meinem FAQ beitrag (link such ich dir gleich raus), dann den pointer per "inc" erhöhen um das nächste pixel zu bekommen.

Edit: hier der link: www.delphi-library.d...iewtopic.php?t=70493
Ich sehe dort, dass ich einen array [0 .. 2] of Byte genommen habe. Ich weiß nicht, ob beide Datentypen die gleiche Größe und den gleichen Aufbau haben, falls ja, müsste der Record auch gehen, aber zur Sicherheit lieber den Array nehmen.

_________________
>+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
P_G Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 75

Win XP
Delphi 7 / 8 Enterprise
BeitragVerfasst: Do 29.01.09 12:43 
Zunächst Danke für die Antworten.
Der Datentyp for Row ist PByteArray (Pixelformat des Bitmaps ist pf8bit). Ich gehe davon aus, daß der Pointer durch die i-Schleife weitergesetzt wird (erster Fehler?)
Scheinbar liefert der Pointer aber nur den Rotwert des Pixels - auch bei 8 bit (zweiter Fehler weil Verständnisproblem?)
Die Frage ist letztendlich: Wie frage ich per scanline die Farbwerte eines Bitmaps ab, so daß ich einen TColor-Wert erhalte? Wenn ich fData[I,J].Color mit der Eigenschaft Pixels beantworte, läuft es wunderbar, nur eben viel zu langsam...

Noch mal zum Code:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
Var I, J: Integer;
Row:  PByteArray;
begin
 SetLength(fData, OrigBmp.Width);
 for I := 0 to High(fData) do
  begin
    SetLength(fData[I], OrigBmp.Height);
  end;

 OrigBmp.HandleType := bmDIB;
 OrigBmp.PixelFormat := pf8bit;
  FOR j := 0 TO OrigBmp.Height-1 DO
  BEGIN
    Row := OrigBmp.Scanline[j];
    FOR i := 0 TO OrigBmp.Width-1 DO
    BEGIN
     fData[I,J].Color := // ????????
    END
  END;


Gruß, P_G
JayEff
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: Do 29.01.09 12:48 
user profile iconP_G hat folgendes geschrieben Zum zitierten Posting springen:
Zunächst Danke für die Antworten.
Ich gehe davon aus, daß der Pointer durch die i-Schleife weitergesetzt wird (erster Fehler?)
Scheinbar liefert der Pointer aber nur den Rotwert des Pixels - auch bei 8 bit (zweiter Fehler weil Verständnisproblem?)
Die Frage ist letztendlich: Wie frage ich per scanline die Farbwerte eines Bitmaps ab, so daß ich einen TColor-Wert erhalte? Wenn ich fData[I,J].Color mit der Eigenschaft Pixels beantworte, läuft es wunderbar, nur eben viel zu langsam...

Erster Fehler: warum sollte, wenn die Schleifenvariable erhöht wird, der Pointer erhöht werden? Die beiden Variablen sind für gewöhnlich nicht Quantenverschränkt ;)
Zweiter Fehler: Vielleicht ist es das Pixelformat, ich nutz da immer 24bit.
Meinen Code hast du dir angeguckt, in dem Library Beitrag? der sollte eigentlich alles erklären :nixweiss:
Darin siehst du auch, wie du die drei Farbwerte ausließt. mit der Funktion RGB(r, g, b) erhälst du aus 3 Bytewerten einen TColor wert.

_________________
>+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 29.01.09 13:07 
user profile iconJayEff hat folgendes geschrieben Zum zitierten Posting springen:
Erster Fehler: warum sollte, wenn die Schleifenvariable erhöht wird, der Pointer erhöht werden? Die beiden Variablen sind für gewöhnlich nicht Quantenverschränkt ;)
Schau dir seinen Code nochmal an: Er benutzt einen Pointer auf ein Array, das Pointer-Verschieben geschieht also implizit bei der Indizierung Row[i].
Für 24-Bit gibt es schon einen vorgefertigten Record, afair TRGBTriple.

_________________
>λ=
P_G Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 75

Win XP
Delphi 7 / 8 Enterprise
BeitragVerfasst: Do 29.01.09 13:11 
Hi,
durch Row erhalte ich einen Pointer auf die jeweilige Zeile. Row[i] innerhalb der i-Schleife sollte nun den Pointer auf Pixel i innerhalb der Zeile Row liefern. Warum muß ich also noch weiter inkrementieren? Ich gebe zu, daß ich mich mittlerweile schon zu sehr verbissen habe, so daß mir dein Code-Beispiel nur bedingt weiterhilft (du manipulierst die Pixel und fragst sie nicht nur in Form eines TColor-Wertes ab - bin eben mittlerweile blind...).
Ich erkenne immerhin, daß du jeweils noch durch 3 dividierst, weil du durch das 24 bit Format sonst Verschiebungen hättest, die bei mir nicht anliegen (8 bit). Wenn ich übrigens RGB(GetRValue(Row[i]), GetGValue(Row[i]), GetBValue(Row[i])) einsetze, bekomme ich dieselben Fehlfarben. Irgendwo habe ich im Netz gelesen, daß scanline einen Farbwert zurückliefert, bei dem Rot und Blau vertauscht sind. Aber die RGB-Werte zu versetzen, bringts auch nicht.

Gruß, P_G
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 29.01.09 13:29 
Moin!

user profile iconP_G hat folgendes geschrieben Zum zitierten Posting springen:
auch bei 8 bit (zweiter Fehler weil Verständnisproblem?)
Die Frage ist letztendlich: Wie frage ich per scanline die Farbwerte eines Bitmaps ab, so daß ich einen TColor-Wert erhalte?
[...]
ausblenden Delphi-Quelltext
1:
2:
 OrigBmp.HandleType := bmDIB;
 OrigBmp.PixelFormat := pf8bit;
Wenn ich das richtig sehe, vermutest du hier "Klartextfarbwerte", aber Bilder mit 8-Bit-Farbtiefe haben eine Palette! :idea: Also entweder doch in 24-Bit konvertieren oder den Wert aus dem Scanline-Array als Index in die Farbtabelle des Bildes interpretieren. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
P_G Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 75

Win XP
Delphi 7 / 8 Enterprise
BeitragVerfasst: Do 29.01.09 14:15 
Zitat:
Wenn ich das richtig sehe, vermutest du hier "Klartextfarbwerte", aber Bilder mit 8-Bit-Farbtiefe haben eine Palette! :idea: Also entweder doch in 24-Bit konvertieren oder den Wert aus dem Scanline-Array als Index in die Farbtabelle des Bildes interpretieren


Sorry - verstehe ich nicht. Delphis TColor ist in jedem Fall vom Typ Cardinal. Unabhängig von der Frage, ob die Farbzuweisung eines Bitmaps per indizierter Tabelle abläuft oder nicht, sollte man doch erwarten, daß sich über scanline ein TColor-Wert abfragen läßt, der später unmittelbar wieder für TCanvas verwendet werden kann. Pixels tut das schließlich auch. Nehme ich mal einen Moment lang an, daß ich nicht drum herumkomme, Pixelformat auf 24 zu setzen - wie bekomme ich nun per scanline für ein beliebiges Pixel einen TColor-Wert, der demselben Wert entspricht, wie eine Abfrage über Pixels?
:autsch: :autsch: :autsch:

Gruß, P_G
P_G Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 75

Win XP
Delphi 7 / 8 Enterprise
BeitragVerfasst: Do 29.01.09 14:42 
Problem gelöst!
Pixelformat wird auf 32 gesetzt. Dann deklariere ich:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
type
  TRGB32 = packed record
  B, G, R, A: Byte;
  end;
  TRGB32Array = packed array[0..MaxInt div SizeOf(TRGB32) - 1] of TRGB32;
  PRGB32Array = ^TRGB32Array;


Und setze scanline ein:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
Var I, J: Integer;
Row:  PRGB32Array;
begin
 SetLength(fData, OrigBmp.Width);
 for I := 0 to High(fData) do
  begin
    SetLength(fData[I], OrigBmp.Height);
  end;

 OrigBmp.HandleType := bmDIB;
 OrigBmp.PixelFormat := pf32bit;
  FOR j := 0 TO OrigBmp.Height-1 DO
  BEGIN
    Row := OrigBmp.Scanline[j];
    FOR i := 0 TO OrigBmp.Width-1 DO
    BEGIN
     fData[I,J].Marked := False;
     fData[I,J].Color := RGB(Row[i].R, Row[i].G, Row[i].B);
    END
  END;


Ich weiß immer noch nicht wirklich, warum meine vorherige Lösung nichts brachte. Aber egal, so gehts jedenfalls. Danke an alle, die Anregungen geliefert haben.

Gruß, P_G
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 29.01.09 15:34 
Moin!

user profile iconP_G hat folgendes geschrieben Zum zitierten Posting springen:
Delphis TColor ist in jedem Fall vom Typ Cardinal.
Das ist richtig, hast aber nix damit zu tun:
user profile iconP_G hat folgendes geschrieben Zum zitierten Posting springen:
Unabhängig von der Frage, ob die Farbzuweisung eines Bitmaps per indizierter Tabelle abläuft oder nicht, sollte man doch erwarten, daß sich über scanline ein TColor-Wert abfragen läßt, der später unmittelbar wieder für TCanvas verwendet werden kann.
Nein, das ist nicht so. Scanline[] liefert lediglich einen Zeiger auf eine Zeile (raw!) des Bildes, damit ist nix über die Werte gesagt, die an dieser Adresse zu finden sind. :idea:

user profile iconP_G hat folgendes geschrieben Zum zitierten Posting springen:
Pixels tut das schließlich auch.
Ja, allerdings wird hier eine GDI-API-Funktion gekapselt, die einen definierten Output hat. Das Speicherabbild des Images hat damit aber nix zu tun.

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.