imread / imsave nicht identisch

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Max21
User
Beiträge: 8
Registriert: Mittwoch 1. Dezember 2010, 11:46

Hallo,

ich habe folgendes Problem mit den Bildfunktionen von scipy:

Code: Alles auswählen

import numpy
import scipy

# Path and name of the image
path = 'lena512.png'

# Height and width of the image
height = 512
width = 512

# Read image
input_image = scipy.misc.imread(path)
# Write image into 2D-array
image = numpy.empty( (height,width) )
for i in range(height):
    for j in range(width):
        image[i][j] = input_image[i][j][0]

scipy.misc.imsave('imsave.png', image)
print image
Das gespeicherte Bild out.png ist nicht mit in.png identisch, es gibt Abweichungen zwischen 0 und 15 Pixeln (bei 256 Quantisierungsstufen).
Die Ausgabe der Pixelwerte in der letzten Zeile ist aber auf jeden Fall korrekt (überprüft), es liegt also an der Funktion scipy.misc.imsave.
Da es sich bei dem Bild um ein Bild in Graustufen handelt, wird es für eine spätere Verarbeitung erstmal in ein 2D-Array umgeschrieben. Für out.png macht es dann auch keinen Unterschied, ob man das 2D-Array image übergibt oder ob man wieder in ein 3D-Array mit drei Farbkanälen umschreibt, das Bild ist verfälscht.

Habt ihr eine Idee?

Grüße, Max
Zuletzt geändert von Max21 am Donnerstag 2. Dezember 2010, 12:34, insgesamt 2-mal geändert.
BlackJack

@Max21: Wie überprüfst Du denn die Abweichung?
Max21
User
Beiträge: 8
Registriert: Mittwoch 1. Dezember 2010, 11:46

BlackJack hat geschrieben:@Max21: Wie überprüfst Du denn die Abweichung?
Ich habe die beiden Bilder in Matlab eingelesen und die Differenz berechnet.
Habe bisher schon viel Erfahrung mit Matlab, aber noch kaum mit Python...

Ist aber auch erkennbar, nicht auf den ersten Blick, aber wenn man etwas genauer hinsieht.
BlackJack

@Max21: Wie vergleichst Du denn in Matlab ein RGB-Bild mit einem Graustufenbild? Kann es sein, dass Matlab da nicht einfach eine der drei Komponenten nimmt, sondern den Wert tatsächlich aus allen drei Kanälen berechnet und da an den entsprechenden Pixeln nicht die gleichen Werte stehen?

Kannst Du ein Beispielbild ins Netz stellen, mit dem man das nachvollziehen kann?
Max21
User
Beiträge: 8
Registriert: Mittwoch 1. Dezember 2010, 11:46

Also den vergleich habe ich manuell gemacht, habe einfach nur einen Farbkanal aus dem RGB Bild genommen, nicht erst mit einer Matlab-Funktion in YUV oder ähnliches transformiert.

Mir ist jetzt auch aufgefallen, dass die Scipy-Funktion imsave wohl auf den ganzen Dynamikbereich normalisiert, also den Kontrast erhöht. Sieht man auch deutlich an den folgenden Beispielbildern, dass der Kontrast im zweiten deutlich stärker ist. Im Original war er 16 -> 254, nach imsave 0->255.

In der Doku steht noch was von einem Parameter 'flatten', ich weiß aber nicht, wie ich den übergeben kann und ob es an dem liegt.
http://docs.scipy.org/doc/scipy/reference/misc.html

Ich werde es nun mal mit entsprechenden Funktionen aus PIL probieren.

http://picfront.de/d/7Xhb
http://picfront.de/d/7Xhc
Vielen Dank!
BlackJack

@Max21: Da scheint tatsächlich der Bereich auf die vollen 0-255 ausgedehnt zu werden. `imsave()` stützt sich auf `toimage()` aus `scipy.misc`.

Deine Schleifen kannst Du übrigens deutlich kompakter schreiben:

Code: Alles auswählen

image = input_image[...,0]
Max21
User
Beiträge: 8
Registriert: Mittwoch 1. Dezember 2010, 11:46

BlackJack hat geschrieben: Deine Schleifen kannst Du übrigens deutlich kompakter schreiben:

Code: Alles auswählen

image = input_image[...,0]
Hey, jetzt funktionierts... jetzt sind die Bilder identisch!
Konnte es erst nicht glauben, aber habs mehrmals überprüft...
Wie kann das sein? Die Datenstruktur und die Datentypen sind doch nicht anders als vorher, oder?

Code: Alles auswählen

import numpy
import scipy

# Path and name of the image
path = 'lena512.png'

# Height and width of the image
height = 512
width = 512

# Read image
input_image = scipy.misc.imread(path)

# Write image into 2D-array
image = input_image[...,0]

scipy.misc.imsave('imsave.png', image)
BlackJack

@Max21: Doch die sind anders: Die aus dem Bild eingelesenen Daten haben den Typ `numpy.uint8` -- es sind halt Bytes. Wenn Du einfach so ein `numpy`-Array ohne Typangabe erstellst, dann ist das in der Regel vom Typ `numpy.float_`. Und da macht es schon einen Unterschied beim speichern. Bei `uint8` ist ja klar, dass alle Werte im Bereich 0-255 sind. Bei Fliesskommazahlen hingegen nicht, also werden die auf den Bereich abgebildet.

Grmpf, das hätte mir aber auch früher auffallen können.
Max21
User
Beiträge: 8
Registriert: Mittwoch 1. Dezember 2010, 11:46

Okay, vielen Dank!

Jetzt ist alles klar...
Ich hätte nicht damit gerechnet, dass scipy diese Normalisierung vornimmt, ist aber eigentlich ganz praktisch.
Die Matlab-Funktion imwrite rechnet bei float, dass der Wertebereich zwischen 0 und 1 liegt und das geschriebene Bild ist dann folglich komplett weiß, weil einfach geclippt wird.
Antworten