Hallo Leute,
wie vllt. einige schon mitbekommen haben, programmiere ich gerade an einer Software, die eine handelübliche Webcam zur Durchführung einer Bewegungerkennung nutzt. Eine Zusatzfunktion des Programms soll es sein, falls eine Bewegung erkannt wurde, das entsprechende Bild via Netzwerk an einen Client zu versenden. Das Bild liegt als PIL Instanz vor (weil ich damit schnell die Differenz und somit Bewegung zw. zwei Bildern berechnen kann). Wie kann ich dieses Bild nun am einfachsten mit socket an einen Client schicken und dann dieses Bild v.a. wieder in der Tkinter GUI des Clients anziegen?
Schonmal Danke im Vorraus für eure Antworten ;D
PIL Image über Netzwerk an Client GUI versenden
@Bonzo1993: Man könnte das `PIL`-Image in ein `StringIO.StringIO`-Objekt speichern und die Bytes davon dann verschicken.
also ich hab jetzt mal folgendes probiert:
== Server-Seite ==
das PIL-Image-Objekt wird in einen String umgewandelt:
in form eines strings wird das bild dann über socket.send versandt
==Client-Seite==
Jetzt wird dieser String wie in dem anderen Thread bereits beschrieben in eine warteschlange als element hinzugefügt um danach ausgelesen werden zu könnnen. Dabei wird der String gleich in ein StringIO.StringIO-Objekt umgewandelt (denn das kann PIL gleich als image wieder lesen, siehe dazu: http://www.pythonware.com/library/pil/h ... n-function)
Danach wird das PIL-Image-Objekt in ein PIL-PhotoImage-Objekt konvertiert, welches dann auch von Tkiner genutzt werden kann siehe dazu u.a.: http://www.hackerboard.de/code-kitchen/ ... ellen.html).
und dann soll das bild erstaml in dem label landen ^^
soweit die theorie, aber in der praxis spuckt python auf der client seite folgenden Fehler aus:
und das bild erscheint natürlich auch net ...
Christoph ;D
== Server-Seite ==
das PIL-Image-Objekt wird in einen String umgewandelt:
Code: Alles auswählen
image_string = image.tostring()
Code: Alles auswählen
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, 50000))
s.send(image_string)
Jetzt wird dieser String wie in dem anderen Thread bereits beschrieben in eine warteschlange als element hinzugefügt um danach ausgelesen werden zu könnnen. Dabei wird der String gleich in ein StringIO.StringIO-Objekt umgewandelt (denn das kann PIL gleich als image wieder lesen, siehe dazu: http://www.pythonware.com/library/pil/h ... n-function)
Code: Alles auswählen
image = Image.open(StringIO.StringIO(self.queue.get()))
Code: Alles auswählen
tkimage = ImageTk.PhotoImage(image)
self.status["image"] = tkimage
soweit die theorie, aber in der praxis spuckt python auf der client seite folgenden Fehler aus:
Code: Alles auswählen
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\Python26\lib\lib-tk\Tkinter.py", line 495, in callit
func(*args)
File "C:\Users\Christoph\workspace\bewegungserkennung\src\Client.py", line 80, in updateLabel
image = Image.open(StringIO.StringIO(self.queue.get()))
File "C:\Python26\lib\site-packages\PIL\Image.py", line 1916, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
Christoph ;D
Zuletzt geändert von Bonzo1993 am Donnerstag 26. August 2010, 19:47, insgesamt 1-mal geändert.
Image.tostring tut sicher etwas ganz anderes als Image.save mit einem StringIO.StringIO-Objekt. Also entweder Beides über StringIO oder du versuchst es mal mit Image.fromstring.
Edit: Ok, die PIL-Dokumentation ist zu Image.fromstring sehr eindeutig:
Edit: Ok, die PIL-Dokumentation ist zu Image.fromstring sehr eindeutig:
Note that this function decodes pixel data, not entire images. If you have an entire image file in a string, wrap it in a StringIO object, and use open to load it.
Das Leben ist wie ein Tennisball.
aber ich hab ja trotzdem keine wirkliche "entire image file", sondern nur ein PIL-Image-Objekt wie soll ich das dann in ein StringIO.StringIO bringen und wieder zurück zu einem PIl-Image-Objekt?
edit:
bzw. wenn ich's einfach nur über über tostring -> fromstring
Server:
senden, queue, usw...
passiert gar nix? Also weder Fehler noch Veränderung beim label...
kann ich überhaupt das label via self.status["image"] verändern?
bzw. brauch ich bei fromstring noch anderen argumente wie extra decoder oder so?
Christoph
edit:
bzw. wenn ich's einfach nur über über tostring -> fromstring
Server:
Code: Alles auswählen
image = image.tostring()
Code: Alles auswählen
image = Image.fromstring(self.queue.get())
tkimage = ImageTk.PhotoImage(image)
self.status["image"] = tkimage
kann ich überhaupt das label via self.status["image"] verändern?
bzw. brauch ich bei fromstring noch anderen argumente wie extra decoder oder so?
Christoph
Indem man in die Dokumentation schaut. Da sind sieben Minuten manchmal nicht genug Zeit.
Code: Alles auswählen
>>> import StringIO
>>> import Image
>>> spam = Image.open("spam.jpg")
>>> fp = StringIO.StringIO()
>>> spam.save(fp, "png")
>>> data = fp.getvalue()
>>> fp.close()
>>> fp = StringIO.StringIO(data)
>>> eggs = Image.open(fp)
>>> eggs.save("eggs.jpg")
>>> fp.close()
Das Leben ist wie ein Tennisball.
danke, aber das hatte ich schon mal geanu eins zu eins umgesetzt und folgende Fehlermeldung erhalten
Auch das Speichern des Bild (wie in Doku) auf dem Client Rechner führt zu diesem Fehler
(Alle imports wurden gemacht, socket richtig geöffnet, verbindung aufgebaut)
==Server==
==Client==
Auch das Speichern des Bild (wie in Doku) auf dem Client Rechner führt zu diesem Fehler
zur Umsetzung:Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\Python26\lib\lib-tk\Tkinter.py", line 495, in callit
func(*args)
File "C:\Users\Christoph\workspace\bewegungserkennung\src\Client.py", line 83, in updateLabel
tkimage = ImageTk.PhotoImage(image)
File "C:\Python26\lib\site-packages\PIL\ImageTk.py", line 116, in __init__
self.paste(image)
File "C:\Python26\lib\site-packages\PIL\ImageTk.py", line 166, in paste
im.load()
File "C:\Python26\lib\site-packages\PIL\ImageFile.py", line 189, in load
s = read(self.decodermaxblock)
File "C:\Python26\lib\site-packages\PIL\PngImagePlugin.py", line 349, in load_read
cid, pos, len = self.png.read()
File "C:\Python26\lib\site-packages\PIL\PngImagePlugin.py", line 92, in read
len = i32(s)
File "C:\Python26\lib\site-packages\PIL\PngImagePlugin.py", line 40, in i32
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
IndexError: string index out of range
(Alle imports wurden gemacht, socket richtig geöffnet, verbindung aufgebaut)
==Server==
Code: Alles auswählen
fp = StringIO.StringIO()
self.imageCurrent.save(fp, "png") #imageCurrent ist das PIL-Image-Objekt
data = fp.getvalue()
fp.close()
s.send(data)
Code: Alles auswählen
fp = StringIO.StringIO(self.queue.get())
image = Image.open(fp)
#passiert nix
tkimage = ImageTk.PhotoImage(image)
self.status["image"] = tkimage
fp.close()
#Alternative 2 (wie in doku) kein Bild in ordner
image.save("bild.jpg")
fp.close()
@Bonzo1993: Wie sieht denn Dein senden und empfangen aus? Wie stellst Du da sicher das alle Daten übertragen werden und vollständig sind bevor Du sie in die Queue steckst?
@BlackJack über einen TCP-Socket
Server:
Client:
Auch wenn ich eine checksum nocht nicht implementiert habe, kann man bei einem TCP-Socket auf den localhost davon ausgehen, dass keine (schon gar nicht mehrmals hintereinander) beim "Versand" verlorengehen.
Oder meinst du, dass die s.send()-Funktion die Daten verändert? Das könnte vllt. sein, sollte aber nicht.
Server:
Code: Alles auswählen
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, 50000)) #ip ist derzeit der localhost also 127.0.0.1
s.send(data)
s.close()
Client:
Code: Alles auswählen
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", 50000))
s.listen(1)
...
com, addr = s.accept()
data = com.recv(1024)
....
s.close()
Oder meinst du, dass die s.send()-Funktion die Daten verändert? Das könnte vllt. sein, sollte aber nicht.
@Bonzo1993: Das Bild ist kleiner oder gleich 1024 Bytes? Und Du bist sicher, dass es in einem Stück ankommt? Das ist nämlich nicht garantiert. Wenn Du Daten über TCP mit diesen Low-Level-Funktionen verschickst, musst Du Dir ein Protokoll ausdenken. Entweder erst die Länge der Daten in einer festen Anzahl von Bytes kodiert übertragen, damit der Empfänger weiss, wann er alles komplett empfangen hat, oder ein Endkennzeichen übertragen, das garantiert nicht im regulären Datenstrom vorkommen kann.
ok danke ich schau mal ^^
gibt's da auch ein modul für diese aufgabe?
also sodass ich mir selbst kein eigenes Protokoll schreiben muss?
edit:
also das problem ist, dass die Bilder zwar unter 1024 sind, das aber gar keine rolle spielt, denn sie müsse ja exakt 1024byte groß sein (bzw. es muss jeweils genau die entsprechende Bildgröße empfangen werden).
Das heißt (wie du schon gesagt hast), dass ich ein eigenes Protokoll schreiben müsste. Weil ich das Projekt nur so etwas hobbymäßig verfolge, stellt sich dann natürlich die Frage ob das in vertretbaren Aufwand möglich ist? Bzw. wäre es möglich die Bilder z.B. alle 10 Minuten als Anhang einer E-Mail zu verschicken. Oder vielmehr: Ist das leichter zu realisieren wie dieses Client-Server Modell? Denn wenn ja würde ich einfach diese Idee weiterverfolge und die Idee mit dem Client verwerfen.
Viele Grüße,
Christoph
gibt's da auch ein modul für diese aufgabe?
also sodass ich mir selbst kein eigenes Protokoll schreiben muss?
edit:
also das problem ist, dass die Bilder zwar unter 1024 sind, das aber gar keine rolle spielt, denn sie müsse ja exakt 1024byte groß sein (bzw. es muss jeweils genau die entsprechende Bildgröße empfangen werden).
Das heißt (wie du schon gesagt hast), dass ich ein eigenes Protokoll schreiben müsste. Weil ich das Projekt nur so etwas hobbymäßig verfolge, stellt sich dann natürlich die Frage ob das in vertretbaren Aufwand möglich ist? Bzw. wäre es möglich die Bilder z.B. alle 10 Minuten als Anhang einer E-Mail zu verschicken. Oder vielmehr: Ist das leichter zu realisieren wie dieses Client-Server Modell? Denn wenn ja würde ich einfach diese Idee weiterverfolge und die Idee mit dem Client verwerfen.
Viele Grüße,
Christoph