Entwickler-Ecke

Multimedia / Grafik - RGB Farben eines Bildes auslesen und in matrix speichern


Heider - Do 20.07.06 15:04
Titel: RGB Farben eines Bildes auslesen und in matrix speichern
hi!

hab mal ne Fragen zu meinen Quelltext (siehe unten). Ich will ein Bild mit Scanline auslesen und in ne Matrix schreiben um damit berechnungen (Fouriertransformation, etc) durchzuführen. Doch das Programm brich immer beim zweiten Pixel ab, der erste wird noch, so wie es aussieht korrekt in die matrix geschrieben.

Deklaration der Matrix Global

Delphi-Quelltext
1:
  imagematrix: array of array of array of Byte;                    


Programmteil mit Fehler (so wies aussieht)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
function TfrmMain.GetColorMatrix(): Boolean;
type
 PixArray = array[1..3of Byte;
var
  X, Y, I, J: Integer;
  pData: ^PixArray;
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
  GetColorMatrix:= False;
  try
    with bmp do begin
      // 24 Bit Pixelformat
      PixelFormat := pf24bit;
      bmp.assign(imgOrig.Picture);
      Width := bmp.Width;
      Height := bmp.Height;
      SetLength(imagematrix,Height);
      for I := Low(imagematrix) to High(imagematrix) do
        begin
          SetLength(imagematrix[I], Width);
        for J := Low(imagematrix[I]) to High(imagematrix[I]) do
          SetLength(imagematrix[I,J], 3);
        end;
      // Zeile holen
      for Y := 0 to Height -1 do begin
        pData := bmp.ScanLine[Y];

        // Spalte
        for X := 0 to Width -1 do begin

          // im Matrix schreiben
          imagematrix[X][Y][0] := pData^[1]; //Rotwert
          imagematrix[X][Y][1] := pData^[2]; //Grünwert
          imagematrix[x][Y][2] := pData^[3]; //Blauwert
          // Pointer aufs nächste Pixel setzen.
         Inc(pData);
        end;
      end;
    end;
  finally
    // frei geben
    bmp.Free;
    GetColorMatrix:= True
  end;

end;


digi_c - Do 20.07.06 15:53

Ach wie ging das nochmal? RGB() war es nicht, ColourToRGB. Ohh diese Hitze...

Darf man fragen, wass du genau vor hast? Weil TBitmap.Canvas.Pixels[x,y]bzw. Scanlinewäre doch vielleicht optimaler?


JayEff - Do 20.07.06 16:10

Erstens: Er benutzt doch ScanLine ^^ Zweitens: Wo ist denn der Fehler und welcher tritt auf? Drittens würde ich das Result nicht im FINALLY (Das auch bei einer exception ausgelöst wird, also egal, ob eine auftritt oder nicht) auf True setzen, sondern im EXCEPT auf false!


Heider - Do 20.07.06 16:26

Also der Fehler tritt in zeile 33 bis 35 auf und ist ein Speicherzugriffsfehler, aber erst nachdem der erste Pixel ausgelesen und in die Matrix geschrieben wurde.

Ps. Danke für den Hinweis mit dem Except


F34r0fTh3D4rk - Do 20.07.06 18:24

warum benutzt du ein 3d array ? warum machst du net:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  type
    TRGBColor = record
      R,
      G,
      B: byte;
{...}


Delphi-Quelltext
1:
2:
var
  colormatrix: array of array of TRGBColor;


? steigert die übersicht


Heider - Do 20.07.06 23:26

Also ich hab mir erstmal alle Tips zu herzen genommen und den Quelltext entsprechend geändert und aufeinmal scheints zu gehen. :D

hier der neue Quelltext

Globale Deklaration

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
type
  TRGBColor = record
    R,
    G,
    B: byte;
  end;

var
 imagematrix: array of array of TRGBColor;


und hier der Programmteil

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
function TfrmMain.GetColorMatrix(): Boolean;
type
 PixArray = array[1..3of Byte;
var
  I,J : Integer;
  pData: ^PixArray;
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
  GetColorMatrix:= False;
  try
    with bmp do begin
      // 24 Bit Pixelformat
      PixelFormat := pf24bit;
      bmp.assign(imgOrig.Picture);
      Width := bmp.Width;
      Height := bmp.Height;
      SetLength(imagematrix,Height);
      for I := Low(imagematrix) to High(imagematrix) do
          SetLength(imagematrix[I], Width);
      // Zeile holen
      for I := 0 to Height -1 do begin
        pData := bmp.ScanLine[I];
        // Spalte
        for J := 0 to Width -1 do begin
          // im Matrix schreiben
          imagematrix[I][J].R := pData^[1]; //Rotwert
          imagematrix[I][J].G := pData^[2]; //Grünwert
          imagematrix[I][J].B := pData^[3]; //Blauwert
          // Pointer aufs nächste Pixel setzen.
         Inc(pData);
        end;
      end;
      bmp.Free;
      GetColorMatrix:= True;
    end;
  Except
    // frei geben
    bmp.Free;
    GetColorMatrix:= False;
  end;
end;


Vielen Dank für eure Hilfe!


Phantom1 - Fr 21.07.06 09:28

der Grund warum es bei dir mit dem ersten Quellcode oben nicht ging ist weil du:


Delphi-Quelltext
1:
2:
3:
          imagematrix[X][Y][0] := pData^[1]; //Rotwert
          imagematrix[X][Y][1] := pData^[2]; //Grünwert
          imagematrix[x][Y][2] := pData^[3]; //Blauwert

du hast dort die X und Y dimension vertauscht gehabt.

so hätte es funktioniert:

Delphi-Quelltext
1:
2:
3:
          imagematrix[Y][X][0] := pData^[1]; //Rotwert
          imagematrix[Y][X][1] := pData^[2]; //Grünwert
          imagematrix[Y][X][2] := pData^[3]; //Blauwert


Achja noch ein Tipp:

Delphi-Quelltext
1:
2:
3:
      SetLength(imagematrix,Height);
      for I := Low(imagematrix) to High(imagematrix) do
          SetLength(imagematrix[I], Width);
Die function SetLength unterstützt mehrere Dimensionen, du brauchst also nur:

Delphi-Quelltext
1:
SetLength(imagematrix, Height, Width);                    

das bewirkt das gleiche wie dein Quellcode


Heider - Fr 21.07.06 12:45

Leider funktionierte es nur eine kurze Zeit, ich hab gestern abend noch den Quelltext um eine weitere Funktion ergänzt, aber die Funktion nicht weiter verändert, trotzdem funktionert es nun nicht mehr. Es gibt einen Speicherzugriffsfehler und die Zeile 29 der funktion wird markiert. Wieder wird nur der erste Pixel ausgelesen und danach kommt der Abbruch. Es ist zum verzweifeln.


Phantom1 - Fr 21.07.06 17:28

user profile iconHeider hat folgendes geschrieben:
Leider funktionierte es nur eine kurze Zeit, ich hab gestern abend noch den Quelltext um eine weitere Funktion ergänzt, aber die Funktion nicht weiter verändert, trotzdem funktionert es nun nicht mehr. Es gibt einen Speicherzugriffsfehler und die Zeile 29 der funktion wird markiert. Wieder wird nur der erste Pixel ausgelesen und danach kommt der Abbruch. Es ist zum verzweifeln.

Tja iss schwer zu sagen, kann an vielen dingen liegen, zb wenn man ein jpg in das Image lädt, dann stürzt deine function auch ab.

Ansonsten probiere es mal so hier, habe nur kleine änderungen vorgenommen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
function TForm1.GetColorMatrix: Boolean;
var
  X, Y: Integer;
  pData: ^TRGBColor;
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
  try
    bmp.assign(imgOrig.Picture.Bitmap);
    // 24 Bit Pixelformat
    bmp.PixelFormat := pf24bit;
    SetLength(imagematrix, Height, Width);
    // Zeile holen
    for Y := 0 to Height -1 do begin
      pData := bmp.ScanLine[I];
      // Spalte
      for X := 0 to Width -1 do begin
        // im Matrix schreiben
        imagematrix[Y, X] := pData^; // Rot & Grün & Blau
        // Pointer aufs nächste Pixel setzen.
        Inc(pData);
      end;
    end;
    bmp.Free;
    Result := True;
  except
    // frei geben
    bmp.Free;
    Result := False;
  end;
end;


Heider - Sa 22.07.06 02:31

Danke Phantom1, ich hab deine Variante des Quelltextes benutzt und jetzt geht es. Könnte sein, dass die Deklaration von Pdata, die entscheidende Änderung war, oder halt doch irgendein dummer indexfehler.

Nochmals vielen Dank an alle die geholfen haben das Problem zu lösen!


Phantom1 - Sa 22.07.06 09:09

user profile iconHeider hat folgendes geschrieben:
Danke Phantom1, ich hab deine Variante des Quelltextes benutzt und jetzt geht es. Könnte sein, dass die Deklaration von Pdata, die entscheidende Änderung war, oder halt doch irgendein dummer indexfehler.

Ne das war auch bei deiner Variante in Ordnung, ich habe es nur etwas vereinfacht.

Was mir jetzt noch eingefallen war, ist das du das Pixelformat an der richtigen stelle hättest setzen müssen.
Bei dir war es so:

Delphi-Quelltext
1:
2:
bmp.pixelformat:=pf24bit;
bmp.assign(img.picture.bitmap);

Beim Assign wird jetzt alles vom img übernommen, das wären die Bilddaten, Größe und auch das Pixelformat! Daher muss das pixelformat nach dem assign gesetzt werden.

mfg