Autor Beitrag
schnake
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Mo 29.10.07 22:35 
Hallo Leute,

erstmal Gratulation zu dem gelungenen Forum.
Ich bin absoluter Delphi Neuling und versuche gerade ein kleines Bildbearbeitungsprog. zu schreiben.

Es klappt schon dass ich zwei .bmp files lade und anzeigen lassen.
Nun soll beim ButtonClick jedes Pixel des einen mit jedem Pixel des anderen Bildes addiert (oder dividiert etc.) werden und das neue Bild natürlich auch zusammengesetzt und angezeigt werden.

Der bisherige Quellcode lautet folgendermaßen:

ausblenden volle Höhe 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:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Image1: TImage;
    Image2: TImage;
    Image3: TImage;
    OpenDialog1: TOpenDialog;
    OpenDialog2: TOpenDialog;
    MainMenu1: TMainMenu;
    Bild11: TMenuItem;
    ffnen1: TMenuItem;
    Bild21: TMenuItem;
    ffnen2: TMenuItem;
    procedure ffnen1Click(Sender: TObject);
    procedure ffnen2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Bitmap: TBitmap;

implementation

{$R *.dfm}

procedure TForm1.ffnen1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    begin
      Bitmap:=TBitmap.Create;
      Image1.Picture.Bitmap.LoadFromFile(OpenDialog1.FileName);
      end;
end;

procedure TForm1.ffnen2Click(Sender: TObject);
begin
  if OpenDialog2.Execute then
    begin
      Bitmap:=TBitmap.Create;
      Image2.Picture.Bitmap.LoadFromFile(OpenDialog2.FileName);
      end;
end;

procedure AddImage(Image1, Image2, Image3: TImage);
var
  x,y: integer;
  k: LongInt;
  zeile1, zeile2, zeile3: PByteArray;

begin
  k:=0;
  for y:=0 to image1.Picture.Bitmap.Height-1 do begin
    zeile1:=image1.Picture.Bitmap.ScanLine[y];
    zeile2:=image2.Picture.Bitmap.ScanLine[y];
      for x:=0 to image1.Picture.Bitmap.width-1 do
        zeile3[x]:=zeile1[x]+zeile2[x];
          inc(k);

end;
end;
end.


Bei der Prozedur AddImage weiß ich irgendwie nicht mehr weiter. Wie schaffe ich das PByteArray zeile3 in ein Bitmap bzw. Image3 und lasse es anzeigen???

Für Tipps und Anregungen schon mal Danke im Vorraus!!!

Gruß

schnake

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Di 30.10.07 09:30 
Wenn du versuchst ein Bildbearbeitungsprogramm zu schreiben, dass tu dir bitte einen gefallen und übergib keine Konponenten an deine Methoden. Sondern benutz lieber die Klasse TBitmap. Denn du kannst nicht immer davon ausgehen, dass du auch tatsächlich eine Komponente haben wirst.

Als zweites auch wenn es derzeit noch nicht so wichtig ist. Bitte die Variablen nicht 1, 2, 3 benennen. Image 1 und 2 mögen beim Addieren okay sein aber das Ausgabebild ist nicht klar erkenntlich.

Jetzt aber zu dem eigentlichen Problem. Als erstes solltest du überprüfen ob die Auflösung und die Farbtiefe der Bilder gleich sind. Also überprüfen ob Width, Height und PixelFormat den gleichen Werte haben. Besonders ein gleiches Pixelformat ist wichtig. Evtl solltest du diese derzeit auch einfach Stumpf auf pf32Bit setzen.

Dann etwas zum Detail der Daten die sich in den Scanlines befinden. Dort hast du echte Bilddaten. Je nach dem PixelFormat können diese auch komplett anders aussehen. Bei 32 Bit hat jedes Pixel 4 Byte. Das erste Byte ist der blaue Farbkanal. Das Zweite der Grüne. Der Dritte der Rote und der Vierte ist unbenutzt bzw kann für den Alpha "missbraucht" werden. Mit anderen Worten Sieht es so aus. XXXXXXXX Bei 24 Bit würde der letzte Kanal wegfallen sonst ist es gleich.

Das Addieren ist zwar gerade ein einfaches Beispiel aber normal ist das ein Modus den ich persönlich eher nicht verwende. Außerdem musst du aufpassen, dass die Werte nicht zu hoch werden. Aber für den Anfang ist das gerade okay.

Dein Code ist vom Prinzip her schon richtig allerdings fehlen noch ein paar Kleinigkeiten. Bei dem Ausgabebild musst du eine Höhe/Breite und Farbtiefe setzen. Damit würdest du also ein Ausgabebild erzeugen. Und mittels Scanline könntest du dort hineinschreiben. Ich würde dir allerdings auch empfehlen kein ByteArray zu benutzen sondern eher ein PRGBQuad (für 32 Bit) oder ein PRGBTriple (für 24 Bit). Denn dann hättest du alle Daten eines Pixels sofort parat.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure AddImage(Source1, Source2, Dest: TImage);
var
  X, Y: Integer;
  pDest, pSource1, pSource2: PRGBQuad;
begin
  for Y := 0 to Source1.Height -1 do begin
    pSource1 := Source1.ScanLine[Y];
    pSource2 := Source2.ScanLine[Y];
    pDest := Dest.ScanLine[Y];

    for X := 0 to Source1.width -1 do begin
      Dest^.rgbRed   := Source1^.rgbRed   + Source2^.rgbRed;
      Dest^.rgbGreen := Source1^.rgbGreen + Source2^.rgbGreen;
      Dest^.rgbBlue  := Source1^.rgbBlue  + Source2^.rgbBlue;

      Inc(pSource1);
      Inc(pSource2);
      Inc(pDest);
    end;
  end;
end;

In diesem Code ist es wichtig die Pointer der Scanlines per Hand weiter zu setzen. Vorher hattes du ein Array wo du X reingereicht hattest. Jetzt ist es ein einzelner Pointer. Wenn du lieber Arrays magst kannst du auch so etwas definieren. Und dann das PRGBQuadArray benutzen. Technisch gesehen gibt es da keinen Unterschied. Ist geschmackssache.
ausblenden Delphi-Quelltext
1:
2:
PRGBQuadArray = ^TRGBQuadArray;
TRGBQuadArray = array [0..$FFFF] of TRGBQuad;


PS: Falls das jetzt zu viel auf einen Schlag war und du Fragen hast. Tu dir keinen Zwang an. ;)

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
schnake Threadstarter
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Mi 31.10.07 21:53 
Schönen Dank schonmal für die schnelle Hilfe.

Ich bekomms aber noch nicht hin, dass das neue (addierte Image3 oder Dest) in einem neuen Fenster angezeigt wird wenn ich z.B. Button1Click betätige.

Sorry dass ich den ganzen Code poste:

ausblenden volle Höhe 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:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Image1: TImage;
    Image2: TImage;
    OpenDialog1: TOpenDialog;
    OpenDialog2: TOpenDialog;
    MainMenu1: TMainMenu;
    Bild11: TMenuItem;
    ffnen1: TMenuItem;
    Bild21: TMenuItem;
    ffnen2: TMenuItem;
    Image3: TImage;
    procedure ffnen1Click(Sender: TObject);
    procedure ffnen2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
   // procedure Image3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Bitmap: TBitmap;
  PixelFormat : TPixelFormat;

implementation

{$R *.dfm}

procedure TForm1.ffnen1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    begin
      Image1.Picture.Bitmap.PixelFormat:=pf32bit;
      Bitmap:=TBitmap.Create;
      Image1.Picture.Bitmap.LoadFromFile(OpenDialog1.FileName);
      end;
end;

procedure TForm1.ffnen2Click(Sender: TObject);
begin
  if OpenDialog2.Execute then
    begin
      Image2.Picture.Bitmap.PixelFormat:=pf32bit;
      Bitmap:=TBitmap.Create;
      Image2.Picture.Bitmap.LoadFromFile(OpenDialog2.FileName);
      end;
end;

procedure AddImage(Image1, Image2, Image3: TBitmap);
var
  x,y: integer;
  pImage1, pImage2, pImage3: PRGBQuad;

begin
  for y:=0 to image1.Height-1 do begin
    pImage1:=image1.ScanLine[y];
    pImage2:=image2.ScanLine[y];
      for x:=0 to image1.width-1 do
        pImage3^.rgbRed   := pImage1^.rgbRed   + pImage2^.rgbRed;
        pImage3^.rgbGreen := pImage1^.rgbGreen + pImage2^.rgbGreen;
        pImage3^.rgbBlue  := pImage2^.rgbBlue  + pImage2^.rgbBlue;
          Inc(pImage1);
          Inc(pImage2);
          Inc(pImage3);

  end;
   Image3.PixelFormat:=pf32bit;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  Bitmap.assign(image3);
  Bitmap.Free;
end;

end.


Eine Fehlermeldung ist ...Cannot convert TImgage to TBitmap...

Gruß und Danke!

Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Fr 02.11.07 15:55 
Es ist natürlich klar, dass du kein TImage dort übergeben kannst du ein TBitmap benötigt wird. Deswegen solltest du folgendes tun.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
AddImage(
  Image1.Picture.Bitmap,
  Image2.Picture.Bitmap,
  Image3.Picture.Bitmap);

Falls nach dem Aufruf sich die Daten nicht verändert haben hilft ein Image3.Repaint. Da sich nur intern daten verändert haben müssen die noch gezeichnet werden.

ausblenden Delphi-Quelltext
1:
2:
  Image1.Picture.Bitmap.PixelFormat:=pf32bit;
  Image1.Picture.Bitmap.LoadFromFile(OpenDialog1.FileName);
Das setzen des Pixelformates hat keine Wirkung, da LoadFromFile selber das pixelformat noch einmal setzt. Also musst du es nach dem Laden setzen.


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure AddImage(Image1, Image2, Image3: TBitmap);
...
begin
  ...
  Image3.PixelFormat:=pf32bit;
end;
Der umdrehte Fall von oben. Da du keine Daten in dem Bitmap hast musst du es natürlich vorher bestimmen welches Format es haben soll. Und zusätzlich dazu musst du die Größe setzen, da das Bitmap gar nicht weiß wie groß es überhaupt werden soll. Also in etwa so.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure AddImage(Image1, Image2, Image3: TBitmap);
begin
  Image3.PixelFormat := pf32bit;
  Image3.Width := die passende Breite;
  Image3.Height := die passende Höhe;

  // hier erst kopieren
end;


Das Ding mit dem zusätzlichen Bitmap kannst du bitte ganz streichen. Keine Ahnung was du damit vor hast aber es ist ziemlich nutzlos, da du erstens durch doppeltes erstellen nur Speicherlöcher erzeugst und direkt nach dem Zuweisen auch frei gibst. Ist aber auch gar nicht nötig mit der Methode von oben.

PS: Deine Codeformatierung ist ziemlich gewöhnungsbedürftig. ;)

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.