Entwickler-Ecke

Multimedia / Grafik - Bild auf Pixel analysieren


violinenspieler1000 - Di 29.07.08 15:46
Titel: Bild auf Pixel analysieren
Hallo,

ich habe ein Bild in eine Image-Box geladen. Wie kann ich das Bild auf Pixel untersuchen, d.h. z.B. herausfinden welche Farbe der Pixel bei 100|200 hat?

Danke,
Thomas


Tilman - Di 29.07.08 15:57

Kleines Beispiel wie man farben manipulieren kann.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
var
  farbe: tColor;
  rot,gruen,blau: Byte;
[..]

farbe := image1.canvas.pixels[100,200];
rot := getRVAlue(farbe);
gruen := getGValue(farbe);
blau := getBVAlue(farbe);

rot := 255-rot; // Wert invertieren

farbe := RGB(rot,gruen,blau); // farbe zturückschreiben
image1.canvas.pixels[100,200] := farbe;


violinenspieler1000 - Mi 30.07.08 11:32

Hallo,

leider funktioniert das bei mir nicht richtig.

Zuerst lade ich ein Bild in die ImageBox:

Delphi-Quelltext
1:
image1.Picture.LoadFromFile('C:\Users\xyz\Desktop\test1                    

Dann versuche ich ich den Pixel auszulesen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
farbe := image1.picture.bitmap.Canvas.pixels[4,3];

rot := getRVAlue(farbe);
gruen := getGValue(farbe);
blau := getBVAlue(farbe);

showmessage(inttostr(rot));
showmessage(inttostr(gruen));
showmessage(inttostr(blau));

2 Probleme treten auf:
1. Das Bild verschwindet
2. Egal was ich mache, es wird als Farbe immer schwarz ausgegeben.

Hat jemand eine Idee, wie man die Probleme beseitigen kann?

Thomas

Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt


F34r0fTh3D4rk - Mi 30.07.08 12:10

Versuchs mal mit image1.canvas.

mfg


violinenspieler1000 - Mi 30.07.08 12:19

Danke, aber leider funktioniert das nicht:


Delphi-Quelltext
1:
image1.canvas.LoadFromFile('C:\Users\xyz\Desktop\test1');                    

Da bekomme ich die Fehlermeldung Undefinieeter Bezeichner.

Delphi-Quelltext
1:
farbe := image1.Canvas.pixels[4,3];                    

Dann gibt es eine Debugging Exception mit "Bild kann nur geändert werden, wenn es eine Bitmap enthält"

Thomas

Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt


F34r0fTh3D4rk - Mi 30.07.08 12:23

Das loadfromfile kannst du ja auch so lassen wie es war, ich bezog mich lediglich auf das Canvas.

Sprich:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
image1.Picture.LoadFromFile('C:\Users\xyz\Desktop\test1');

farbe := image1.Canvas.pixels[4,3];
rot := getRVAlue(farbe);
gruen := getGValue(farbe);
blau := getBVAlue(farbe);

showmessage(inttostr(rot));
showmessage(inttostr(gruen));
showmessage(inttostr(blau));

Bitte benutze auch du am besten die Delphi-Tags( [Delphi]DEIN CODE[/Delphi] ), damit dein Code übersichtlich angezeigt wird.

mfg


violinenspieler1000 - Mi 30.07.08 12:30

Hallo,

das funktioniert es wie gesagt leider nicht:

es gibt eine Debugging Exception mit "Bild kann nur geändert werden, wenn es eine Bitmap enthält"
Obwohl ich nicht weiß, warum das Bild geändert werden soll.

Thomas


Tilman - Mi 30.07.08 12:33

Was für eine Bilddatei lädst du denn?


violinenspieler1000 - Mi 30.07.08 12:37

Ich lade .jpg. Unter uses habe ich jpeg eingetragen. Das Bild wird auch nach dem Laden angezeigt.

Thomas


Tilman - Mi 30.07.08 13:03

Hm, hab grad kein Delphi zur Hand und kann es nicht testen. Aber wenn es an dem JPG liegt, könnte es abhilfe schaffen wenn du dieses in ein Bitmap umwandelst, etwa so:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
uses jpeg;
[..]
var
  mein_jpeg: TJpegImage;
  mein_bmp: tBitmap;

begin
mein_jpeg := TJpegImage.Create;
mein_jpeg.loadfromfile(bla);
mein_bmp := tBitmap.Create;
mein_bmp.width := mein_jpeg.width;
mein_bmp.height := mein_jpeg.height;
mein_bmp.draw(0,0,mein_jpeg);

image1.picture := mein_bmp;


Yogu - Mi 30.07.08 13:24

Erstmal: Was willst du erreichen? Erzähl uns bitte noch ein wenig mehr Hintergrundinformationen.

Zum Bearbeiten verwendest du lieber TBitmap, wie user profile iconTilman schon schrieb. Allerdings gefällt mir seine Methode zum Unwandeln nicht so ganz ;)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
var Bitmap: TBitmap; JPEG: TJPEGImage;
begin
  Bitmap := TBitmap.Create;
  try
    JPEG := TJPEGImage.Create;
    try
      JPEG.LoadFromFile(Dateiname);
      Bitmap.Assign(JPEG);
    finally
      JPEG.Free;
    end;

    { Hier kommt dann der Code rein }

  finally
    Bitmap.Free;
  end;
end;

Dann kannst du über die Eigenschaft Bitmap.Canvas.Pixels die Farbe eines einzelnen Pixels auslesen.

Das kommt jetzt im oberen Code dort rein, wo der Kommentar steht.


Delphi-Quelltext
1:
Farbe := Bitmap.Canvas.Pixels[100200];                    

Was danach kommt, hängt von deiner Absicht ab. Du könntest zum Beispiel den Hexwert der Farbe einfach mal anzeigen lassen:


Delphi-Quelltext
1:
ShowMessage(IntToHex(Farbe, 8));                    

Edit:: HexToStr korrigiert zu IntToHex


Jakob_Ullmann - Mi 30.07.08 13:39

HexToStr, gibt es (jedenfalls bei mir) nicht, höchstens IntToHex, wobei der Rückgabetyp ein string ist.


Yogu - Mi 30.07.08 13:45

user profile iconJakob_Ullmann hat folgendes geschrieben:
HexToStr, gibt es (jedenfalls bei mir) nicht, höchstens IntToHex, wobei der Rückgabetyp ein string ist.

Oh, der Fehler passiert mir oft. Habs korrigiert. :oops:


F34r0fTh3D4rk - Fr 01.08.08 11:57

Vielleicht fehlt ihm auch einfach nur das hier:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
image1.Picture.LoadFromFile('C:\Users\xyz\Desktop\test1.jpg');

farbe := image1.Canvas.pixels[4,3];
rot := getRVAlue(farbe);
gruen := getGValue(farbe);
blau := getBVAlue(farbe);

showmessage(inttostr(rot));
showmessage(inttostr(gruen));
showmessage(inttostr(blau));

Sollte das nicht gehen ist eine Umwandlung in BMP erforderlich.

mfg


bensch - Di 30.03.10 11:19

Und warum kann man das Pixel eines jpg-Bildes nicht mit oben genannter Methode auslesen?

Es muss doch irgend eine Möglichkeit geben, ein Pixel eines jpg-Bildes auszugeben, ohne es umzuwandeln.

Denn ich wollte 2 gleiche Bilder miteinander vergleichen. Ein Bild ist ein komprimiertes, und das 2te Bild wäre das original. Nun möchte ich überprüfen, ob die Farbwerte eines bestimmten Bildes mit den Farbwerten des Pixels vom original übereinstimmen.

Doch mit folgendem Code erhalte ich bei jpg-Bildern eine Fehlermeldung:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
var c: TColor;
r, g, b:string;
begin

...

c := image1.Canvas.Pixels[0,0];
r := inttostr(getRValue(C));
g := inttostr(getGValue(C));
b := inttostr(getBValue(C));
showmessage(r+' '+g+' '+b); 

...


das Bild habe ich in ein Timage geladen, wird auch angezeigt, aber beim Auslesen kommt die Fehlermeldung: "Bild kann nur geändert werden, wenn es ein Bitmap enthält".

Wie weiter oben bereits steht, funktioniert das Auslesen bei einem bmp problemlos, nur bei jpg zickt der Code rum. Gibt es da irgend eine Möglichkeit, ein Pixel eines jpg-Bildes auszulesen, ohne dass die "echten Farbwerte" des Bildes durch Konvertierung (evtl. in ein anderes Bildformat) verfälscht werden?


Narses - Di 30.03.10 11:56

Moin!

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
Und warum kann man das Pixel eines jpg-Bildes nicht mit oben genannter Methode auslesen?
Weil die Daten in komprimierter Form vorliegen, du also keinen direkten Zugriff auf die Bilddaten hast. :idea:

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
Es muss doch irgend eine Möglichkeit geben, ein Pixel eines jpg-Bildes auszugeben, ohne es umzuwandeln.
AFAIK - nein.

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
das Bild habe ich in ein Timage geladen, wird auch angezeigt, aber beim Auslesen kommt die Fehlermeldung: "Bild kann nur geändert werden, wenn es ein Bitmap enthält".
Das ist korrekt, da die Windows-Bitmap-API nur mit Bitmaps klar kommt. :nixweiss:

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
Gibt es da irgend eine Möglichkeit, ein Pixel eines jpg-Bildes auszulesen, ohne dass die "echten Farbwerte" des Bildes durch Konvertierung (evtl. in ein anderes Bildformat) verfälscht werden?
Ähm, beim Konvertieren von JPG in BMP geht nix verloren, nur umgekehrt. :!: ;)

cu
Narses


platzwart - Di 30.03.10 12:04

Bindest du auch die Unit jpeg ein? Wenn nicht, kommen vielleicht daher diverse Probleme...


bensch - Di 30.03.10 16:24

Ja, die jpg-Unit habe ich eingebunden.

@ Narses: Bist du dir sicher, dass beim Umwandeln von jpg in bmp die Farben nicht verfälscht werden? Denn wenn ich ein komprimiertes jpg mit dem Original auf Farbabweichungen abgleichen will, wäre es ja unsinnig, wenn durch eine Konvertierung die Farbe verfälscht wird und ich dann das verfälschte Bild mit dem Original vergleiche.


Narses - Di 30.03.10 16:56

Moin!

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
Bist du dir sicher, dass beim Umwandeln von jpg in bmp die Farben nicht verfälscht werden?
Solange du als PixelFormat min. pf24Bit verwendest, ja. ;)

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
Denn wenn ich ein komprimiertes jpg mit dem Original auf Farbabweichungen abgleichen will, wäre es ja unsinnig, wenn durch eine Konvertierung die Farbe verfälscht wird und ich dann das verfälschte Bild mit dem Original vergleiche.
Nochmal zum mitlesen: :zwinker:
BMP -> JPG lossy-compression, die Bilddaten sind nicht mehr bit-identisch zum BMP
JPG -> BMP (>=pf24bit) losless, die Bilddaten des JPGs sind identisch im BMP wiederzufinden.

cu
Narses


delphi10 - Di 30.03.10 18:10

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
Und warum kann man das Pixel eines jpg-Bildes nicht mit oben genannter Methode auslesen?
Weil die Daten in komprimierter Form vorliegen, du also keinen direkten Zugriff auf die Bilddaten hast. :idea:

Mit Canvas greife ich doch aber auf den Bildspeicher zu, nicht auf die Dateidaten. Spätestens bei der Anzeige müssten doch im Speicher die Daten 1:1 vorliegen. *Grübel* Ich weiß es nicht wirklich, ist eher als Frage zu verstehen.


Narses - Di 30.03.10 18:19

Moin!

user profile icondelphi10 hat folgendes geschrieben Zum zitierten Posting springen:
Mit Canvas greife ich doch aber auf den Bildspeicher zu, nicht auf die Dateidaten.
Schonmal versucht, auf das Canvas eines TJPEGImages zuzugreifen? ;) Selbiges befindet sich im Picture-Container eines TImage, wenn du dort ein JPG-Bild geladen hast. :idea:

cu
Narses


bensch - Mi 31.03.10 09:52

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Solange du als PixelFormat min. pf24Bit verwendest, ja. ;)


Hi

An welcher Stelle müsste ich das PixelFormat angeben? Hier mal mein Quelltext: Ich rufe zuerst eine Prozedur auf, die mir mein jpg-Bild in bmp konvertiert:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
procedure JPEGtoBMP(const FileName: TFileName);
var
  jpeg: TJPEGImage;
  bmp:  TBitmap;
begin
  jpeg := TJPEGImage.Create;
  try
    jpeg.CompressionQuality := 100{Default Value}
    jpeg.LoadFromFile(filename);
    bmp := TBitmap.Create;
    try
      bmp.Assign(jpeg);
      bmp.SaveTofile(ChangeFileExt(FileName, '.bmp'));
    finally
      bmp.Free
    end;
  finally
    jpeg.Free
  end;
end;


diese Prozedur rufe ich wie folgt auf:


Delphi-Quelltext
1:
2:
3:
4:
5:
...
JPEGtoBMP('s.jpg');
image1.Picture.Bitmap.PixelFormat := pf24bit;
image1.Picture.LoadFromFile('s.bmp');
...


Muss ich nun das image1.Picture.Bitmap.PixelFormat := pf24bit; bereits vor der Konvertierung (jpg -> bmp) aufrufen, oder passt das so, wie oben zu sehen?


Narses - Mi 31.03.10 11:19

Moin!

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
An welcher Stelle müsste ich das PixelFormat angeben?
Bei dem Code eigentlich gar nicht. ;)

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
Ich rufe zuerst eine Prozedur auf, die mir mein jpg-Bild in bmp konvertiert:
Du musst das übrigens nicht erst in eine Datei schreiben, du kannst das auch direkt im Speicher machen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure LoadJPEGasBMP(const FileName: TFileName);
  var
    jpeg: TJPEGImage;
    bmp:  TBitmap;
begin
  jpeg := TJPEGImage.Create;
  try
    jpeg.LoadFromFile(FileName);
    bmp := TBitmap.Create;
    try
      bmp.Assign(jpeg);
      Image1.Picture.Bitmap.Assign(bmp);
    finally
      bmp.Free
    end;
  finally
    jpeg.Free
  end;
end;

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
Muss ich nun das image1.Picture.Bitmap.PixelFormat := pf24bit; bereits vor der Konvertierung (jpg -> bmp) aufrufen, oder passt das so, wie oben zu sehen?
Vorher nutzt das gar nix (genau so, wie die .Compression-Eigenschaft zu setzen, das wird beim Laden sowieso überschrieben) und nachher willst du´s eigentlich nicht, deshalb einfach nix machen, dann passt das (das BMP wird dann auf eine passende Farbtiefe gesetzt, so dass es verlustfrei übernommen werden kann).

cu
Narses


bensch - Mi 31.03.10 14:30

Hi Narses, vielen Dank für deine Hilfe.

Ich habe da aber noch eine Frage: Gibt es neben dem RGB-Farbvergleich noch eine Möglichkeit, 2 Bilder zu vergleichen?

Denn ich habe hier ein unkomprimiertes jpg-Bild und das selbe in komprimierter Form. Der direkte Pixel-Vergleich ergibt 100% Übereinstimmung, aber wenn ich die beiden Bilder übereinander lege und miteinander vergleiche, ist ein Bild immer etwas heller als das andere. Wie kann man sich das erklären?

Ich habe die Bilder mit der Standard-Windows-Bildbetrachtung geöffnet und immer hin und her gewechselt (die Bilder wurden also immer auf der selben Bildschirmposition angezeigt, damit kann man einen ungleichmäßig beleuchteten Bildschirm als "Fehlerquelle" schon mal ausschließen...)

Die Bilder habe ich auf 4 Bildschirmen verglichen. Auf 2 Bildschirmen unterschied sich die Helligkeit der beiden Bilder, auf den anderen beiden Bildschirmen sah das Original-Bild genau so aus wie das komprimierte.

Die beiden Bilder habe ich mal hochgeladen:
Original: original Komprimiert: komprimiert

Wie gesagt, der direkte Pixel-Vergleich ergab über mein Delphi-Programm als auch im Photoshop-Vergleich 100% Übereinstimmung, trotzdem sah man einen Helligkeitsunterschied / Farbunterschied auf einigen Bildschirmen...

Moderiert von user profile iconNarses: Bild als Anhang hochgeladen.


Narses - Mi 31.03.10 14:45

Moin!

user profile iconbensch hat folgendes geschrieben Zum zitierten Posting springen:
der direkte Pixel-Vergleich ergab über mein Delphi-Programm als auch im Photoshop-Vergleich 100% Übereinstimmung, trotzdem sah man einen Helligkeitsunterschied / Farbunterschied auf einigen Bildschirmen...
Wenn die Pixel identisch sind, kann das nur "Einbildung" sein... :? :nixweiss:

cu
Narses


bensch - Mi 31.03.10 16:35

Diese Einbildung sprang dann aber auf mehrere Personen über, denn den Helligkeitsunterschied haben mehrere bestätigt. Gut, ich muss dazu sagen, dass der Farb- / Helligkeitsunterschied bisher nur auf einem Mac aufgetreten ist. Vielleicht liegt es auch daran?

*Mac niedermach*


JonS - Mi 31.03.10 17:17

Kann es sein, dass der Mac da einen Effekt hat, der einen leichten Gradient über den Bildschirm legt?
Das Gefühl hatte ich bei Windows-7 auch schon mehrere Male, dass die selbe Farbe an verschiedenen Stellen am Bildschirm (Höhe, nicht Breite) einen leichten Unterschied in der Helligkeit aufzeigte.

wfg Jon S.


platzwart - Mi 31.03.10 17:20

Bei mir schaun beide gleich aus...


F34r0fTh3D4rk - Mi 31.03.10 19:38

Das rechte Bild wirkt auf mich auch etwas heller. Aber sie scheinen gleich zu sein. Vermutlich eine optische Täuschung.


Martok - Mi 31.03.10 20:23

Ich tippe jetzt einfach mal drauf, dass das JPEG ein Farbprofil mitbringt/verlangt.
Einfache Bitmaps kennen sowas nicht...

Übrigens ist hier kein solcher Effekt. Wenn ich müsste, würde ich eher das rechte dunkler schätzen, aber das kann auch am Bildschirm liegen.