Pixelzählen (Absolute Noobfrage)

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
maow
User
Beiträge: 29
Registriert: Mittwoch 24. Februar 2016, 16:30

Huhu,

ich bin ganz neu (gerade eben bei 0 begonnen) und nach einigem Suchen habe ich keine Lösung gefunden, daher habe ich mich hier mal angemeldet:

Problem:

Ich habe eine kleine Bilddatei gemacht. Diese soll eine Testdatei sein, bei welcher eine 10 pixel-lange Reihe schwarze Pixel sind, gefolgt von einer Reihe blauer, grüner und schließlich roter Pixel. Die Pixel sollen gezählt werden.

Meine bisherige Lösung die an dem Bild testdatei.png (http://www.file-upload.net/download-113 ... d.png.html
) leider nicht funktioniert:

Code: Alles auswählen

from PIL import Image
import operator

img = Image.open("testbild.png")
r = (254,3,4) # Farbwert entspricht Absolutwert (001) entsprechend EBSD-Orientierungsdreieck
bl = (1,3,254) # Farbwert entspricht Absolutwert (111) entsprechend EBSD-Orientierungsdreieck
g = (4,254,4) # Farbwert entspricht Absolutwert (011) entsprechend EBSD-Orientierungsdreieck
b = (0,0,0) # Schwarzfarbauswahl entspricht dem Schwarz der Korngrenzen

red=0    #counter rot ist Null
blue=0   #counter blau ist Null
black=0    #counter schwarz ist Null
green=0    #counter grün ist Null

for pixel in img.getdata():
	if pixel == b:
	black += 1
	elif pixel == bl:
	blue += 1
	elif pixel == g:
	green += 1
	elif pixel == r:
	rot += 1

print("schwarze Pixel:" +str(black)+ "grüne Pixel:" +str(green)+ "rote Pixel:" +str(red)+ "blaue Pixel:" +str(blue))
wäre super wenn jemand mir schnell sagen kann wo mein Fehler liegt . Und sry. ich bin totaler Anfänger, ich hab echt keine Ahnung was ich eigentlich tue. Aber für mich ergibt das vom Gedankengang her Sinn. Denn eigentlich sag ich dem Programm ja nur, setze Zähler anfangs auf Null. Schau in der Datei welche Farbwerte das Pixel hat. Wenn es den richtigen Farbwert hat, so setze den Counter +1 und gebe mir später das Ergebnis aus.

P.S. Farbwerte entsprechen exakt den Farbwerten aus der Datei
BlackJack

@maow: Schau Dir mal die Werte von `pixel` an, dann sollte klar sein warum der Vergleich für jedes Pixel ungleich sein muss.
Sirius3
User
Beiträge: 17822
Registriert: Sonntag 21. Oktober 2012, 17:20

@maow: "funktioniert nicht" ist eine schlechte Fehlerbeschreibung. Was ist der Fehler (Fehlermeldung)? Was ist das erwartete Ergebnis, was ist das tatsächliche Ergebnis?

Zum Code: die Einrückungen sind bei den if-Blöcken falsch. Das operator-Modul wird nicht benutzt. Statt Strings mit + zusammenzustückeln solltest Du die format-Methode auf Strings benutzen.
maow
User
Beiträge: 29
Registriert: Mittwoch 24. Februar 2016, 16:30

huhu, puh! gar nich so leicht. wisst ihr, das einzige was ich bisher in meinem leben "programmiert" habe ist latex ... und das kann man ja nicht als solches bezeichnen.

Hier habe ich mal das Einrücken verändert. Auch habe ich gesehen das ich statt "red" "rot" geschrieben habe. Die Fehlermeldung bleibt allerdings leider die selbe:

"python pixelcount2.py
File "pixelcount2.py", line 13
SyntaxError: Non-ASCII character '\xc3' in file pixelcount2.py on line 13, but no encoding declared"

An der besagten Stelle ist aber das green=0

Zu meinem Verständnis:

Es ist falsch anzunehmen das folgendes passiert (if-Umgebung):
"Für jedes Pixel in dem Datensatz, wenn pixel == b (also den Wert (0,0,0) hat, dann addiere +1 zum "counter" , den ich anfangs für black 0 gesetzt habe. Wenn es nicht schwarz ist, sondern dafür z.B. rot, dann mache dies bei rot" ?

Hier mal der soweit korrigierte code. Den Teil mit dem String verstehe ich nicht was ich da machen soll ;/ wie gesagt hab heut angefangen damit und net wirklich nen schimmer . danke soweit allerdings für eure Hilfe :):

Code: Alles auswählen

from PIL import Image


img = Image.open("testbild.png")
r = (254,3,4) # Farbwert entspricht Absolutwert (001) entsprechend EBSD-Orientierungsdreieck
bl = (1,3,254) # Farbwert entspricht Absolutwert (111) entsprechend EBSD-Orientierungsdreieck
g = (4,254,4) # Farbwert entspricht Absolutwert (011) entsprechend EBSD-Orientierungsdreieck
b = (0,0,0) # Schwarzfarbauswahl entspricht dem Schwarz der Korngrenzen

red=0    #counter rot ist Null
blue=0   #counter blau ist Null
black=0    #counter schwarz ist Null
green=0    #counter grün ist Null

for pixel in img.getdata():
   if pixel == b:
   	black += 1
   elif pixel == bl:
   	blue += 1
   elif pixel == g:
   	green += 1
   elif pixel == r:
   	red += 1

print("schwarze Pixel:" +str(black)+ "grüne Pixel:" +str(green)+ "rote Pixel:" +str(red)+ "blaue Pixel:" +str(blue))
noch eine zweite Alternative (weiß nich ob du das meintest mit dem ungleich):

Code: Alles auswählen

from PIL import Image


img = Image.open("testbild.png")
r = (254,3,4) # Farbwert entspricht Absolutwert (001) entsprechend EBSD-Orientierungsdreieck
bl = (1,3,254) # Farbwert entspricht Absolutwert (111) entsprechend EBSD-Orientierungsdreieck
g = (4,254,4) # Farbwert entspricht Absolutwert (011) entsprechend EBSD-Orientierungsdreieck
b = (0,0,0) # Schwarzfarbauswahl entspricht dem Schwarz der Korngrenzen

red=0    #counter rot ist Null
blue=0   #counter blau ist Null
black=0    #counter schwarz ist Null
green=0    #counter grün ist Null

# Es erfolgt im Folgenden eine Abfrage, ob das gefundene Pixel dem Farbwert entspricht, falls ja wird der entsprechende counter um 1 erhöht
for pixel in img.getdata():
	if pixel !=r and pixel !=bl and pixel !=g:
		black +=1
	elif pixel !=b and pixel !=g and pixel !=r:
		blue +=1
	elif pixel !=b and pixel !=r and pixel !=bl:
		green +=1
	elif pixel !=b and pixel !=r and pixel !=bl:
		red +=1


print("schwarze Pixel:" +str(black)+ "grüne Pixel:" +str(green)+ "rote Pixel:" +str(red)+ "blaue Pixel:" +str(blue))
BlackJack

@maow: Wenn Du irgendwo im Quelltext etwas ausserhalb von ASCII verwendest, also in der als fehlerhaft gemeldeten Zeile das ü im Kommentar, dann musst Du die Kodierung der Datei als Kodierungskommentar in der ersten oder zweiten Zeile angeben. Die Ausnahme sollte da auch noch etwas mehr Text zeigen:

Code: Alles auswählen

SyntaxError: Non-ASCII character '\xc3' in file pixelcount2.py on line 13, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
Die URL steht dort damit man weiss wo man mehr Informationen zu diesem Fehler bekommt!
maow
User
Beiträge: 29
Registriert: Mittwoch 24. Februar 2016, 16:30

Hallo und nochmal Danke für eure Anregungen!, ich editiere meinen Post einfach mal und das Thema kann geschlossen werden. Ich habe die Lösung gefunden: Anstatt für z.B. Rot den RGB Wert (x,y,z) muss man zusätzlich den Sättigungswert angeben , in meinem Fall liefert also folgender Code das richtige Ergebnis (Ausgabe erfolgt hier zudem untereinander durch /n :

Code: Alles auswählen

from PIL import Image


img = Image.open("testbild.png")
r = (254,3,4,255) # Farbwert entspricht Absolutwert (001) entsprechend EBSD-Orientierungsdreieck
bl = (1,3,254,255) # Farbwert entspricht Absolutwert (111) entsprechend EBSD-Orientierungsdreieck
g = (4,254,4,255) # Farbwert entspricht Absolutwert (011) entsprechend EBSD-Orientierungsdreieck
b = (0,0,0,255) # Schwarzfarbauswahl entspricht dem Schwarz der Korngrenzen

red=0    #counter rot ist Null
blue=0   #counter blau ist Null
black=0    #counter schwarz ist Null
green=0    #counter gruen ist Null

# Es erfolgt im Folgenden eine Abfrage ob das gefundene Pixel dem Farbwert entspricht, falls ja wird der entsprechende counter um 1 erhoeht
for pixel in img.getdata():
	if pixel !=r and pixel !=bl and pixel !=g:
		black +=1
	elif pixel !=b and pixel !=g and pixel !=r:
		blue +=1
	elif pixel !=b and pixel !=r and pixel !=bl:
		green +=1
	elif pixel !=b and pixel !=g and pixel !=bl:
		red +=1


print("schwarze Pixel:" +str(black)+ "\ngruene Pixel:" +str(green)+ "\nrote Pixel:" +str(red)+ "\nblaue Pixel:" +str(blue))
Meine Ausgabe liefert also (jetzt auch mit korrigierter Testdatei, weil 2 schwarze Pixel im blauen Bereich waren) das gewünschte Ergebnis:
schwarze Pixel:10
gruene Pixel:10
rote Pixel:10
blaue Pixel:10
BlackJack

@maow: Das ist kein Sättigungswert sondern der Alphawert. Und man sollte sich nicht darauf verlassen, dass der vorhanden ist, denn PNG kann man mit und ohne Alphakanal speichern. Insbesondere wenn der komplett opaque ist, macht es auch nicht wirklich Sinn den zu speichern. Ich würde ja eher das Bild nach dem laden in ein reines RGB-Bild, ohne Alphakanal umwandeln.

Das mit dem ``!=`` ist viel zu kompliziert und indirekt. Du willst doch vergleichen welche Farbe es ist und nicht welche Farben es nicht sind. Und sollten da irgend wann einmal Pixel vorkommen die eine andere als definierten Farben haben, dann zählt Dein Code die als schwarze Pixel, auch wenn sie Neon-Pink wären.

Die Klammern beim ``print`` gehören da nicht hin, weil das keine Funktion ist in Python 2. Und das verwendest Du, sonst hättest Du den SyntaxError von weiter oben nicht bekommen. Alternativ kannst Du aus dem `__future__`-Modul `print_function` importieren um aus dem Schlüsselwort ``print`` eine Funktion zu machen.

Einfacher wäre es ein `collection.Counter`-Objekt zu zählen zu verwenden:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
from collections import Counter
from PIL import Image

# Farbwert entspricht Absolutwert (001) entsprechend EBSD-Orientierungsdreieck
RED = (254, 3, 4)
# Farbwert entspricht Absolutwert (111) entsprechend EBSD-Orientierungsdreieck
BLUE = (1, 3, 254)
# Farbwert entspricht Absolutwert (011) entsprechend EBSD-Orientierungsdreieck
GREEN = (4, 254, 4)
# Schwarzfarbauswahl entspricht dem Schwarz der Korngrenzen
BLACK = (0, 0, 0)


def main():
    histogram = Counter(Image.open('testbild.png').convert('RGB').getdata())
    for text, color in [
        ('schwarze', BLACK), ('grüne', GREEN), ('rote', RED), ('blaue', BLUE)
    ]:
        print('{0} Pixel: {1}'.format(text, histogram[color]))


if __name__ == '__main__':
    main()
maow
User
Beiträge: 29
Registriert: Mittwoch 24. Februar 2016, 16:30

Hey , und danke dir nochmal für die Antwort. Die halbe Nacht habe ich noch dran gesessen um das weiter zu "verfeinern". Mir ist klar, dass ich als absoluter Einsteiger da noch nichts vernünftiges schreibe ^^, ich werde die Tage aber mir mal deine Tips anschauen , denn mir rennt die Zeit :(

Die eine Zählung die da gemacht wurde sollte auch eigentlich eine sein, die nicht nur schwarze Farben beinhaltet; ich hatte es aber glaube falsch kommentiert. Wenn ich mir deinen code so rasch anschaue , so verstehe ich da noch nicht so recht was da eigentlich passiert und ich glaube ich muss mir das mal ganz in Ruhe zu Gemüte führen.

Was ich gerade eher brauche ist, wie kann ich Bereiche definieren ? . Soweit funktioniert mein Programm ganz gut und klappt auch bei erstellten Testdateien. Da ich das mit dem RGB nicht so recht wusste wie ich das anstellen soll , habe ich auch einfach eine Farbtestdatei nur mit diesen drei Werten ohne Alphakanal(?) erstellt. Damit funktioniert dann auch mein kleines Demonstrationsbeispiel :)

zu der Bereichfrage:

also ich will sagen, dass in einem Farbdreieck die Farbe (man stelle sich ein rotes Farbdreieck vor) , immer dann gegeben ist, wenn sie innerhalb dieser drei Eckpunkte des Dreiecks liegen.

meine Eckpunkte, innerhalb deren Bereich alles rot ist sind: (254,3,4)-(254,38,5)-(252,8,42). ich weiß allerdings nicht wie ich das auf die schnelle schreibe. mir würde es wür das erste ausreichen , wenn ich einfach den Anfang (also wo ich r definiere) entsprechend umschreibe. auch wenn das vielleicht nicht elegant sein mag, für meine derzeitigen zwecke sollte es reichen :)

hier mal mein aktueller code (ich habe deine ideen wie gesagt noch nicht aufgenommen, da ich bei meinen sachen bisher allererste erfolgserlebnisse hatte (hatte ja netmal nen "hello word" programm geschrieben ^^); allerdings muss ich auch sagen, dass ich sie gerne aufnehmen möchte, sobald ich mich dem etwas mehr widmen kann. denn irgendwie macht mir programmieren spaß und vielleicht werd ich da mal etwas weiter mich reinfuchsen :) :

Code: Alles auswählen

from PIL import Image

#Dieses Programm rastert das EBSD-Bild ab und wertet den Anteil absoluter Orientierungen, repraesentiert durch eine Farbe, aus.

img = Image.open("image5.png") # Eingabe der zu untersuchenden Grafikdatei (Datei im selben Ordner wie .py!)
r = (254,3,4) # Farbwert entspricht Absolutwert (001) entsprechend EBSD-Orientierungsdreieck
bl = (1,3,254) # Farbwert entspricht Absolutwert (111) entsprechend EBSD-Orientierungsdreieck
g = (4,254,4) # Farbwert entspricht Absolutwert (011) entsprechend EBSD-Orientierungsdreieck
b = (0,0,0) # Schwarzfarbauswahl entspricht dem Schwarz der Korngrenzen

#k=(0,0,0,255) #ALTERNATIVE KORNGRENZENFARBE, Wert kann beliebig angepasst werden; eine Aufnahme dieses Parameters erfordert allerdings eine zusaetzliche Funktion (trivial)

R=0    #counter rot ist Null
B=0   #counter blau ist Null
ABW=0    #counter abweichende Farbe (R,G,B) ist Null
G=0    #counter gruen ist Null
O=0 #schwarz
# Es erfolgt im Folgenden eine Abfrage ob das gefundene Pixel dem Farbwert entspricht, falls ja wird der entsprechende counter um 1 erhoeht
for pixel in img.getdata():
	if pixel !=r and pixel !=bl and pixel !=g: 
		ABW +=1
	elif pixel !=b and pixel !=g and pixel !=r:
		B +=1
	elif pixel !=b and pixel !=r and pixel !=bl:
		G +=1
	elif pixel !=b and pixel !=g and pixel !=bl:
		R +=1
	if pixel == (0,0,0):
		O +=1
A=ABW+G+R+B 					#Berechnung der Gesamtpixelzahl 
blackArea=(float(ABW)/float(A))*100 		#Berechnung des Flaechenanteils abweichende Farbe
greenArea=(float(G)/float(A))*100 		#Berechnung des Flaechenanteils Gruen
redArea=(float(R)/float(A))*100			#Berechnung des Flaechenanteils Rot
blueArea=(float(B)/float(A))*100 		#Berechnung des Flaechenanteils Blau
P=(float(O)/float(A))*100			#Berechnung des Flaechenanteils schwarz 
print("\n\n")
print("EBSD-Areacalc 1.0                                Autor: noob")
print("\n\n")
print("\n              Gesamtpixelzahl :  "+str(A))
print("\n     Anzahl abweichender Pixel:  " +str(ABW)+ "\n     Anzahl gruener      Pixel:  " +str(G)+ "\n     Anzahl roter        Pixel:  " +str(R)+ "\n     Anzahl blauer       Pixel:  " +str(B))

print("\n\n     Anteil abweichender Orientierungen (inkl. Korngrenzen und zero solutions): \n\n                                 "+str(float(blackArea))+" %"+ " (entspricht "+str(ABW)+ " Pixel der Gesamtflaeche)")

print("\n\n     Anteil der Korngrenzen sowie der zero solutions an der EBSD-Gesamtbildflaeche:")
print("\n                                 "+str(float(P))+" %")

print("\n\n     Anteil der Orientierung an der EBSD-Gesamtbildflaeche:")
print("\n\n            011-Orientierung:    "+str(float(greenArea))+" %")	
print("            001-Orientierung:    "+str(float(redArea))+" %")
print("            111-Orientierung:    "+str(float(blueArea))+" %")	
		

          
maow
User
Beiträge: 29
Registriert: Mittwoch 24. Februar 2016, 16:30

habs eben kurz ausgetestet indem ich r definiert habe als :

r = [([254,3,4],[254,38,5]),([254,3,4],[252,8,42]),([254,38,5],[252,8,42])], aber da zählt er die 254,3,4 nicht mit, welche aber dringend drinnen sein muss :/
BlackJack

@maow: Ich weiss jetzt nicht so ganz ob sich der zweite Absatz auf meine Bemerkung mit dem ``!=`` bezieht, deshalb noch mal: Das ist sehr wahrscheinlich falsch, aber auf jeden Fall viel zu umständlich gelöst, denn selbst wenn man Pixel die keiner der anderen Farben ausser Schwarz entsprechen, zählen möchte, würde man das nicht so eigenartig durch viele verknüpfte ``!=``-Vergleiche machen, sondern den offensichtlichen und kürzeren Weg mit ``==`` gehen und am Ende ein ``else`` für alle durch die vorherigen Vergleiche nicht erfassten Werte schreiben. Du hattest das am Anfang doch mal einfacher ausgedrückt.

Jetzt ist es IMHO auch komisch das schwarze Pixel sowohl in `ABW` als auch in `O` erfasst werden. Und `blackArea` auch nicht-schwarze Pixel beinhaltet währen die Fläche der schwarzen Pixel mit `P` benannt wird. An der Stelle solltest Du auch ganz dringend anfangen sinnvolle Bezeichner zu wählen. Irgendwelche kryptischen Kürzel mit Kommentaren was diese Namen eigentlich bedeuten sollten durch Namen ersetzt werden die im Idealfall keinen erklärenden Kommentar mehr benötigen, jedenfalls nicht was den direkten Namen angeht. Eventuell sollte man statt der Farbnamen auch Namen in Betracht ziehen die Ausdrücken was die Farben bedeuten. Dann kann man sich weitere Kommentare sparen.

Zur Namensschreibweise hat der Style Guide for Python Code etwas. Namen komplett in Grossbuchstaben sind per Konvention für Konstanten vorgesehen und Namen aus mehreren Wörtern werden mit Unterstrichen und klein geschrieben. Also `black_area` statt `blackArea`.

Die Mischung aus dem Gebrauch von `float()` und Klammern bei ``print`` ist immer noch verwirrend. Bei Python 3 wäre `float()` überflüssig und bei Python 2 gehören zur ``print``-Anweisung keine Klammern.

Das mit dem Farbdreieck verstehe ich nicht so ganz. Reden wir von einem Dreieck im RGB-Farbwürfel und die Farben müssen auf der Ebene die durch diese drei Punkte im dreidimensionalen Raum aufgespannt wird, innerhalb des Dreiecks liegen, oder ist es vielleicht eher das man einen Mittelpunkt hat von dem die Farben eine bestimmte Strecke abweichen dürfen? Oder könnte man das Bild auch in den HSV-Farbraum überführen und alles zählen was einen Schwellwert im Value überschreitet und im Hue in einem bestimmten Bereich liegt. Vielleicht möchtest Du das auch gar nicht ”manuell” machen, oder zumindest nicht mit verschachtelten Schleifen in Python, sondern mindestens mit Numpy/Scipy oder gar mit OpenCV‽

Beschreib doch mal das eigentliche Problem nicht in Form eines Lösungsweges sondern tatsächlich das Problem selbst. Du hast ein Bild? Wie sieht das aus? Welche Farben kommen da tatsächlich vor? Wie sind die verteilt? Was bedeuten die?
maow
User
Beiträge: 29
Registriert: Mittwoch 24. Februar 2016, 16:30

Huhu und Danke bereits für deine Antwort :); muss leider gleich los und würde später nochmal ausführlicher schreiben und auch gerne das Programm entsprechend deinen Ideen nochmal einfacher machen , sobald ich die Zeit finde. Daher gehe ich mal schnell nochmal auf das Farbdreieck ein.

Die folgende Datei zeigt ein Dreieck mit 3 Eckpunkten, diese Eckpunkte haben einen Wert. Der komplette Bereich, welcher durch diese drei Punkte aufgespannt wird soll als rot definiert werden (genau das gleiche will ich dann für blau und grün machen, aber das sind ja dann nur andere Werte; muss bloß ers):tmal wissen, wie ich sowas leicht definieren kann.

http://www.directupload.net/file/d/4275 ... 45_png.htm


(Übrigens sind alle Angaben die das Programm ausdrückt, auch wenn ichs umständlich und teils sicher sehr verwirrend geschrieben habe, richtig aufgelistet. Das Programm gibt genau das aus, was es soll. Ich denke auch, es ist besser, es überhaupt einfacher zu schreiben, auf lange Sicht ist es einfach gut sowas sich gleich anzugewöhnen. Ich werde das nachholen wie gesagt )

P.S. Diese Klammern bei print hab ich von dem besagten Informatikkommilitonen gesagt bekommen. Hab es also blind nachgemacht.
baba soweit :)
BlackJack

@maow: Die Zeichnung beantwortet die Frage also dahingehend das das Dreieck im 3D-RGB-Farbraum gemeint ist, und man jedes Pixel darauf prüfen müsste ob der Punkt im Farbwürfel auf der Ebene und innerhalb des Dreiecks liegt, welches durch die drei Punkte beschrieben wird. Also müsstest Du eine Funktion schreiben, welche die drei Eckpunkte bekommt und den Farbwert eines Pixels und die Frage ob der Farbwert die Bedingung erfüllt, entscheidet. Ein bisschen lineare Algebra im ℝ³. :-)
Antworten