Graustufenbild ind Farbbild - Fehler bei den Datentypen

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
kl.feigling89
User
Beiträge: 42
Registriert: Montag 24. Februar 2014, 14:47

Hallo, ich möchte gern ein Python-Skript schreiben, dass mir aus einem Graustufenbild ein RGB-Bild erzeugt.
Hier hab ich versucht, ein Bild mit der Lichtart D65 einzufärben. Leider bekomme ich jedoch die Fehlermeldung, dass der Datentyp nicht passt. Leider bin ich sehr neu in der Programmiersparche und ohne das deklarieren von Datentypen fällt es mir sehr schwer den Fehler zu beheben. Kann mir vielleicht jemand von euch helfen?

Hier Einmal das Programm:

Code: Alles auswählen

import cv2
import numpy
import PIL
import sys
from PIL import Image  					
import numpy as np

image_file = "grey_cy.bmp"																						#imagename
grey_image = Image.open(image_file)																				#image oeffnen
width, height = grey_image.size

#-----------------------
print "Bildaufloesung:"
print "Breite:",  width
print "Hoehe:", height
#-----------------------

color_100 = numpy.array([90,-48,-14])																			#Lab-Wert Vollton
color_0 = numpy.array([100,0,0])																				#Lab-Wert Hintergrund 
referenz_lab2xyz = numpy.array([95.027,100.000,108.883])														#Referenzmatrix Lab nach XYZ
referenz_xyz2rgb = numpy.array(((3.2406,-0.9689,0.0557),(-1.5372,1.8758,0.2040),(-0.4986,0.0415,1.0570)))		#Referenzmatrix XYZ nach RGB

back_100 = numpy.array([0,0,0])	
back_0 = numpy.array([255,255,255])	
M = numpy.array([0,0,0])	
N = numpy.array([0,0,0])

def lab2xyz (c,mat):
	var_Y = ((c[0]+16)/116) 
	var_X =	((c[1]/500)+ var_Y)
	var_Z = (var_Y - (c[2]/200))
	
	
	if (var_Y^3)>0.008856:	
		Y0 = (var_Y)^3
	else:
		Y0= (((var_Y-16)/116)/7.787)
		
	if (var_X^3)>0.008856:	
		X0 = (var_X)^3
	else:
		X0= (((var_X-16)/116)/7.787)
	
	if (var_Z^3)>0.008856:	
		Z0 = (var_Z)^3
	else:
		Z0= (((var_Z-16)/116)/7.787)		
	
	if (X0*mat[0])>=0:
		M[0]= X0*mat[0]
	elif (X0*mat[0])>mat[0]:
		M[0]=mat[0]
	else:
		M[0] = 0
		
	if (Y0*mat[1])>=0:
		M[1]= Y0*mat[1]
	elif (Y0*mat[1])>mat[1]:
		M[1]=mat[1]
	else:
		M[1] = 0
		
	if (Z0*mat[2])>=0:
		M[2]= X0*mat[2]
	elif (Z0*mat[2])>mat[2]:
		M[2]=mat[2]
	else:
		M[2] = 0
	return M
		
def xyz2rgb(x,mat):
	var_X = x[0]/100
	var_Y = x[1]/100
	var_Z = x[2]/100
	
	var_R = (var_X * mat[0,0]) + (var_Y * mat[0,1]) + (var_Z * mat[0,2])
	var_G = (var_X * mat[1,0]) + (var_Y * mat[1,1]) + (var_Z * mat[1,2])
	var_B = (var_X * mat[2,0]) + (var_Y * mat[2,1]) + (var_Z * mat[2,2])
	
	
	if var_R > 0.0031308:
		R0 = (1.055 *(var_R**(1.0/2.4))-0.055)
	else:
		R0 = 12.92 * var_R
		
	if var_G > 0.0031308:
		G0 = (1.055 *(var_G**(1/2.4)))-0.055
	else:
		G0 = 12.92 * var_G
		
	if var_B > 0.0031308:
		B0 = (1.055 *(var_B**(1/2.4)))-0.055
	else:
		B0 = 12.92 * var_B		
	
	if (R0 * 255) >= 0:
		N[0]= R0*255
	elif (R0 * 255) > 255:
		N[0]= 255
	else: 
		N[0] = 0
		
	if (G0 * 255) >= 0:
		N[1]= G0*255
	elif (G0 * 255) > 255:
		N[1]= 255
	else: 
		N[1] = 0
		
	if (B0 * 255) >= 0:
		N[2]= B0*255
	elif (B0 * 255) > 255:
		N[2]= 255
	else: 
		N[2] = 0
	return N	

xyz100 = lab2xyz(color_100,referenz_lab2xyz)
xyz0 = lab2xyz(color_0,referenz_lab2xyz)
rgb100 = xyz2rgb(xyz100,referenz_xyz2rgb)
rgb0 = xyz2rgb(xyz0,referenz_xyz2rgb)
	
def grey2color(M,x0,x100,r0,r100):
	
	m_R = (r100[0]-r0[0])/(x100[0]-x0[0])
	m_G = (r100[1]-r0[1])/(x100[1]-x0[1])
	m_B = (r100[2]-r0[2])/(x100[2]-x0[2])
	
	b_R = ((r0[0]*x100[0])-(r100[0]*x0[0]))/(x100[0]-x0[0])
	b_G = ((r0[1]*x100[1])-(r100[1]*x0[1]))/(x100[1]-x0[1])
	b_B = ((r0[2]*x100[2])-(r100[2]*x0[2]))/(x100[2]-x0[2])
	
	for z in range(0, height, 1): 
		for s in range(0, width, 1):
			A[z][s] = round((( m_R * M[z][s] )+ b_R),0 )				
			A[z][s+width] = round((( m_G * M[z][s] )+ b_G),0 )	
			A[z][s+width+width] = round(((m_B * M[z][s] )+ b_B),0 )
	return A
	
image = grey2color(image_file, back_0, back_100, rgb0, rgb100 )
image.save("gcy_out.bmp")
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Bitte die genaue Fehlermeldung inklusive Traceback hierher kopieren.
In specifications, Murphy's Law supersedes Ohm's.
BlackJack

@kl.feigling89: Man muss zwar keine Typen für Namen deklarieren, aber jeder Wert hat natürlich einen festen Datentyp den man mit `type()` ermitteln kann, und Funktionen, Methoden, und Operatoren funktionieren jeweils nur mit den Typen die vom Code erwartet werden. Du musst also über den Traceback herausfinden welcher Code betroffen ist, und Dir da mal die Typen der beteiligten Werte ausgeben lassen und dann überlegen welche erwartet werden, welche vorliegen, und warum das so ist und wo man das am besten ändert.

Ansonsten: Die Einrücktiefe ist per Konvention vier Leerzeichen pro Ebene.

Die wirklich sehr langen Zeilen mit den Inline-Kommentaren am Zeilenende sehen in einem Editor der umbricht unschön aus. Zeilenlänge sollte man auf 80 Zeichen begrenzen. Die Kommentare sind teilweise auch überflüssig weil sie einfach nur sehr offensichtliche Sachen als Text wiederholen die schon im Code stehen. Wer bei ``image_file = 'grey_cy.bmp'`` nicht mitbekommt dass dort der Bilddateiname definiert wird, dem wird auch der Kommentar nicht helfen.

Das Vermischen von Hauptprogramm und Funktionsdefinitionen auf Modulebene macht das Programm unübersichtlich. Das Hauptprogramm sollte in einer eigenen Funktion verschwinden. Üblicherweise nennt man die `main()`.

Wenn man das macht, dann fällt auf das die Funktionen mehr benutzen als sie eigentlich dürften, nämlich Werte die nicht als Argumente übergeben werden sondern auf Modulebene existieren und keine Konstanten sind. Das betrifft `M` und `N`. Interessanterweise werden diese Werte am Ende von den Funktionen als Rückgabewerte verwendet, obwohl sie der Aufrufer auf Modulebene ja bereits kennt und sie übergeben müsste. Das ist eine komische, asymmetrische API. Ausserdem vermute ich hier einen Fehler weil die *selben* Arrays mehrfach manipuliert werden und an verschiedene Namen gebunden werden. Ich gehe mal davon aus das `xyz100` und `xyz0` sowie `rgb100` und `rgb0` jeweils unterschiedliche Werte haben sollen. Tun sie aber nicht weil jedes Namenspaar an das selbe Array gebunden wird. Die Erzeugung eines neuen Arrays gehört also in die jeweilige Funktion.

Ungefähr jeder zweite Import wird nicht verwendet.

In `grey2color()` wird `A` nirgends definiert.

Code: Alles auswählen

import numpy
from PIL import Image


def lab2xyz(c, mat):
    var_Y = ((c[0]+16)/116)
    var_X = ((c[1]/500)+ var_Y)
    var_Z = (var_Y - (c[2]/200))

    if (var_Y^3)>0.008856:
        Y0 = (var_Y)^3
    else:
        Y0= (((var_Y-16)/116)/7.787)

    if (var_X^3)>0.008856:
        X0 = (var_X)^3
    else:
        X0= (((var_X-16)/116)/7.787)

    if (var_Z^3)>0.008856:
        Z0 = (var_Z)^3
    else:
        Z0= (((var_Z-16)/116)/7.787)

    M = numpy.array([0,0,0])

    if (X0*mat[0])>=0:
        M[0]= X0*mat[0]
    elif (X0*mat[0])>mat[0]:
        M[0]=mat[0]
    else:
        M[0] = 0

    if (Y0*mat[1])>=0:
        M[1]= Y0*mat[1]
    elif (Y0*mat[1])>mat[1]:
        M[1]=mat[1]
    else:
        M[1] = 0

    if (Z0*mat[2])>=0:
        M[2]= X0*mat[2]
    elif (Z0*mat[2])>mat[2]:
        M[2]=mat[2]
    else:
        M[2] = 0

    return M


def xyz2rgb(x, mat):
    var_X = x[0]/100
    var_Y = x[1]/100
    var_Z = x[2]/100

    var_R = (var_X * mat[0,0]) + (var_Y * mat[0,1]) + (var_Z * mat[0,2])
    var_G = (var_X * mat[1,0]) + (var_Y * mat[1,1]) + (var_Z * mat[1,2])
    var_B = (var_X * mat[2,0]) + (var_Y * mat[2,1]) + (var_Z * mat[2,2])

    if var_R > 0.0031308:
        R0 = (1.055 *(var_R**(1.0/2.4))-0.055)
    else:
        R0 = 12.92 * var_R

    if var_G > 0.0031308:
        G0 = (1.055 *(var_G**(1/2.4)))-0.055
    else:
        G0 = 12.92 * var_G

    if var_B > 0.0031308:
        B0 = (1.055 *(var_B**(1/2.4)))-0.055
    else:
        B0 = 12.92 * var_B

    N = numpy.array([0, 0, 0])

    if (R0 * 255) >= 0:
        N[0]= R0*255
    elif (R0 * 255) > 255:
        N[0]= 255
    else:
        N[0] = 0

    if (G0 * 255) >= 0:
        N[1]= G0*255
    elif (G0 * 255) > 255:
        N[1]= 255
    else:
        N[1] = 0

    if (B0 * 255) >= 0:
        N[2]= B0*255
    elif (B0 * 255) > 255:
        N[2]= 255
    else:
        N[2] = 0

    return N


def grey2color(M, x0, x100, r0, r100):

    m_R = (r100[0]-r0[0])/(x100[0]-x0[0])
    m_G = (r100[1]-r0[1])/(x100[1]-x0[1])
    m_B = (r100[2]-r0[2])/(x100[2]-x0[2])

    b_R = ((r0[0]*x100[0])-(r100[0]*x0[0]))/(x100[0]-x0[0])
    b_G = ((r0[1]*x100[1])-(r100[1]*x0[1]))/(x100[1]-x0[1])
    b_B = ((r0[2]*x100[2])-(r100[2]*x0[2]))/(x100[2]-x0[2])

    for z in range(0, height, 1):
        for s in range(0, width, 1):
            A[z][s] = round((( m_R * M[z][s] )+ b_R),0 )
            A[z][s+width] = round((( m_G * M[z][s] )+ b_G),0 )
            A[z][s+width+width] = round(((m_B * M[z][s] )+ b_B),0 )
    return A


def main():
    image_file = 'grey_cy.bmp'
    grey_image = Image.open(image_file)
    width, height = grey_image.size

    print 'Bildaufloesung:'
    print 'Breite:', width
    print 'Hoehe:', height

    color_100 = numpy.array([90, -48, -14])  # Lab-Wert Vollton.
    color_0 = numpy.array([100, 0, 0])  # Lab-Wert Hintergrund.
    referenz_lab2xyz = numpy.array([95.027, 100.000, 108.883])
    referenz_xyz2rgb = numpy.array(
        (
            (3.2406, -0.9689, 0.0557),
            (-1.5372, 1.8758, 0.2040),
            (-0.4986, 0.0415, 1.0570),
        )
    )
    back_100 = numpy.array([0, 0, 0])
    back_0 = numpy.array([255, 255, 255])
    xyz100 = lab2xyz(color_100, referenz_lab2xyz)
    xyz0 = lab2xyz(color_0, referenz_lab2xyz)
    rgb100 = xyz2rgb(xyz100, referenz_xyz2rgb)
    rgb0 = xyz2rgb(xyz0, referenz_xyz2rgb)

    image = grey2color(image_file, back_0, back_100, rgb0, rgb100)
    image.save('gcy_out.bmp')


if __name__ == '__main__':
    main()
kl.feigling89
User
Beiträge: 42
Registriert: Montag 24. Februar 2014, 14:47

Danke BlackJack, deine Antowort hat mir sehr weitergeholfen.

Hab es jetzt aufgeteilt in eine Main und eine Funktion und auch die Kommentare bearbeitet.
Hab noch einen kleinen Fehler, denke aber den finde ich gleich selber herraus.

Gruß kl.Feigling
kl.feigling89
User
Beiträge: 42
Registriert: Montag 24. Februar 2014, 14:47

Hab da noch ein kleines Problem:
Warum kann ich hier einfach nicht mit der Funktion die Pixelwerte ändern und es anschließend speichern? Das Programm ist nur ein Ausschnitt und die Werte zB m_R = 255 sind nur zu test zwecken und geben keinen richtigen Sinn. Möchte nur das Bild ändern und speichern.

Code: Alles auswählen

import Image
import cv2
import numpy
import PIL
import sys
import random
from PIL import Image, ImageDraw               
import numpy as np
 
image_file = "greycy2.bmp"                                                                                                                                                                             
grey_image = Image.open(image_file)                                                                                            
width, height = grey_image.size
pix = grey_image.load()

def grey2color(M):
        pixel = M.load() 
        draw = ImageDraw.Draw(M)
       
        m_R = 255
        m_G = 255
        m_B = 255
       
        b_R = 0
        b_G = 0
        b_B = 0
       
        for z in range(0, height, 1):
                for s in range(0, width, 1):
                        a_Pixel = pixel[z,s]                        
                        red_Pixel = round((( m_R *a_Pixel )+ b_R),0)
                        green_Pixel = round((( m_G * a_Pixel )+ b_G),0 )
                        blue_Pixel = round(((m_B * a_Pixel )+ b_B),0 )                       
                        draw.point((z, s), (red_Pixel, green_Pixel, blue_Pixel)) 
        return M     
       
image2 = grey2color(grey_image)
image2.save("gcy_out.bmp")
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Du gibst M zurück, liest aber nur von M.

Grüße,
anogayales
kl.feigling89
User
Beiträge: 42
Registriert: Montag 24. Februar 2014, 14:47

Okay hab verstanden wo das Problem liegt, leider weiß ich nicht wie ich es lösen kann.
Könnte mir jemand wohl das Programm verbessern?

Habe schon ausprobiert aus M ein neues Bild zu erstellen, dieses zubearbeiten und das dann zurückzugeben. Leider klappt es einfach nicht :K

Hoffe Jemand kann mir das Programm verbessern ... wäre super lieb.

Gruß
BlackJack

@kl.feigling89: Also ich sehe ja erst einmal ein ganz anderes Problem: Du zeigst hier ziemlich wahrscheinlich keinen Quelltext den Du mal laufen lassen hast. Oder Du verrätst wichtige Informationen nicht. Ich bekommen beim Versuch `Draw.point()` eine Farbe als RGB-Tupel mit Gleitkommawerten zu übergeben jedenfalls einen `TypeError: integer argument expected, got float`.

Das mit dem `Draw`-Objekt verstehe ich sowieso nicht, weil Du ja schon Zugriff auf die Pixelwerte hast und zum lesen der Pixelwerte einen anderen Weg nimmst als um Pixelwerte zu setzen.

Da sowieso schon Numpy verwendet wird, würde es sich doch irgendwie auch anbieten das gleich über Array-Operationen zu erledigen wenn alle Werte eines Farbkanals gleich behandelt werden sollen. Man kann ein `Image`-Objekt einfach `numpy.array()` übergeben und erhält ein mehrdimensionales Array als Ergebnis.
kl.feigling89
User
Beiträge: 42
Registriert: Montag 24. Februar 2014, 14:47

Hallo BlackJack, ich habe bewusst den Code sehr einfach gehalten, um ein Beispiel Programm zubekommen, dass ich dann nur noch erweitern muss. Das mit dem Draw Objekt ist echt eine doofe lösung. Hatte nur die Idee aus dem Internet und dachte es wäre eine schnelle und gute lösung um die einzelnen Pixel zu ändern.
Jetzt hab ich aber leider mein Problem immer noch .. Sollte ich das Bild als Array Objekt anlegen weiß ich nicht wie ich die einzelnen Farben (Rot, Grün, Blau
) des Bildes ändern soll ... Wo im Array ist rot und wo Blau?

Finde leider auch kein Beispiel Programm, wo ich ein Bild lade und die einzelnen Farben eines Pixels ändern kann ... hat jemand vielleicht sowas ? Das würde mir mega Helfen.



Code: Alles auswählen

import Image
import cv2
import numpy
import PIL
import sys
import random
from PIL import Image, ImageDraw               
import numpy as np
 
image_file = "greycy2.bmp"                                                                                                                                                                             
grey_image = Image.open(image_file)                                                                                            
width, height = grey_image.size
pix = grey_image.load()

def grey2color(M):
        pixel = M.load() 
        draw = ImageDraw.Draw(M)
       
        m_R = 255
        m_G = 255
        m_B = 255
       
        b_R = 0
        b_G = 0
        b_B = 0
       
        for z in range(0, height, 1):
                for s in range(0, width, 1):
                        a_Pixel = pixel[z,s]                        
                        red_Pixel = round((( m_R *a_Pixel )+ b_R),0)
                        green_Pixel = round((( m_G * a_Pixel )+ b_G),0 )
                        blue_Pixel = round(((m_B * a_Pixel )+ b_B),0 )                       
                        # Hier müssten jetzt die einzelnen Fraben in ein Bild/Pixel eingefügt werden. Aber wie???

        return M     
       
image2 = grey2color(grey_image)
image2.save("gcy_out.bmp")
[/quote]
BlackJack

@kl.feigling89: Wenn man diesen Ansatz weiterverfolgen möchte, dann müsste man ein leeres RGB-Bild mit der gleichen Grösse erstellen, sich davon das Pixels-Objekt geben lassen und analog zum Auslesen aus dem Graustufenbild dort das RGB-Tupel an den gleichen Koordinaten zuweisen.

Das ist aber alles ziemlich umständlich und langsam. Man könnte sich die verschachtelten Schleifen sparen in dem man mit der `point()`-Methode ein Graustufenbild für jeden Kanal erstellt und dann mit der `Image.merge()`-Funktion daraus ein RGB-Bild erstellt.

Oder wie schon gesagt das Graustufenbild in ein Numpy-Array wandeln und dann mit Numpy ein mehrdimensionales Array für ein RGB-Bild erstellen.
Antworten