Raspberry Pi Photobooth

Kathrin_und_Maltes_Hochzeit_363.jpg

Im Rahmen meiner anstehenden Hochzeit suchte ich nach günstigen, zunächst mietbaren, Photobooth Boxen. Diverese Hochzeitsfotografen bieten diese Boxen an, jedoch für einen relativ hohen Preis. Dafür bekommt man jedoch hochqualitative Fotos, denn häufig beinhalten die Boxen teure Spiegelreflexkameras, teure Software und/oder eingebaute Fotodrucker.
Da mir dies jedoch alles zu teuer war, suchte ich nach DIY Alternativen und stieß relativ schnell auf die Seite von Chris Evans (KLICK). Er hatte auf Basis des Raspberry Pi, Raspbian und einem kleinen Pythonprogramm eine wirklich schlanke und einfache Photobooth Lösung gebaut, die meiner Vorstellung einer solchen Box schon recht nah kam. Einen Raspberry hatte ich noch in der Schublade, es fehlte nur noch das Raspberry Kameramodul. Diesbezüglich war ich mir zunächst nicht ganz sicher, denn ich hatte gelesen, dass die Kamera insbesondere bei wenig Licht sehr stark rauschen würde und die Qualität auch nicht wirklich toll sein sollte. Meiner Ansicht nach, ist die Qualität der Fotos jedoch nicht das einzige bzw. ausschlaggebende Argument, welches es bei einer Box zu beachten gibt.
Ich bin der Ansicht, dass das Hauptaugenmerk auf dem Spass und witzigen Fotos liegen sollte, statt auf perfekt ausgeleuchteten, rauscharmen Fotos mit höchster Pixelzahl. Also bestellte ich die Kamera und ich muss sagen, die Qualität ist völlig in Ordnung! Natürlich kann man keine Wunder erwarten, aber für ein paar Fotos bei normalem Licht reicht die Kamera vollkommen aus und wichtiger noch: Sie ist schnell und einfach programmier- und bedienbar!

1. Modifikationen gegenüber der Originalbox im Überblick
1.1 Email und Tumblr Upload deaktiviert
1.2 Wasserzeichen im Bild
1.3 Countdown Overlay im Livebild
1.4 4-Fachdarstellung der geschossenen Bilder (Speicherung aller Einzelbilder und der 4er-Bilder)
1.5 Standby-Replay Modus (wenn keine Fotos gemacht wird, werden nach Zufallsprinzip gemachte Bilder gezeigt)
1.6 RGB LED Beleuchtung
1.7 Mini Webgallerie auf lokalem Webserver, erreichbar über
1.8 WiFi Accesspoint (WLAN Modul)
1.9 Shutdown/Reset Prevention Routine (System Shutdown/Reboot nur über Button-Longpress aktivierbar)
1.10 Externer Buzzer
1.11 Beleuchtete Auslöseschalter
1.12 Speicherung der Fotos auf USB Stick statt SD Karte



1.1 Email und Tumblr Upload deaktiviert
Anders als bei Chris, wollte ich die Bilder nicht zu Tumblr oder irgendeiner anderen Bildplattform hochladen und so konnte der gesamte Teil in meiner neuen Fotobox Software entfallen. Zudem wollte ich den Raspberry auch nicht mit mobilem Internetzugang auststatten.

1.2 Wasserzeichen im Bild
Um den Bildern einen professionellen Touch zu geben, soll ein kleines Wasserzeichen bzw. Logo in der unteren linken Ecke der Bilder angezeigt werden. Um den Rechenprozess beim Erstellen der 4-fach Ansicht zu beschleunigen, werden die Fotos direkt nach der Aufnahme und während des Countdowns im Hintergrund mit dem Logo versehen. Dies geschieht mittels eines System-Call des ImageMagick Programms montage:

    graphicsmagick = "composite -gravity southwest /home/pi/watermark3.png " + filename + " " + filename + "&"
    os.system(graphicsmagick)


Wichtig ist hierbei besonders das "&" Symbol am Ende, welches die Hintergrundausführung des composite Kommandos ermöglicht, also während bereits neue Fotos gemacht werden.



1.3 Countdown Overlay im Livebild
Anders als in der originalen Version der Box wollte ich noch einen Countdown, der als Overlay über das Live-Kamerabild gelegt wird, sodass die Nutzer auch sehen können, wann das Foto geschossen wird. Da im Originalcode sowieso eine kurze Pause zwischen den einzelnen Aufnahmen liegt, musste nur noch ein Bild zur richtigen Zeit ein- und ausgeblendet werden. Hierzu erstellte ich einige Grafiken, die dann halbtransparent über das Kamera-Livebild gelegt werden. Als ich diesen Teil programmierte enthielt die picamera Bibliothek (1.8) noch einen Bug, der ein Memory Leak durch mehrfaches Hinzufügen und Entfernen von Overlays produzierte (Fixed a nasty memory leak in overlay renderers which caused the camera to run out of memory when overlays were repeatedly created and destroyed (#174)). Glücklicherweise wurde dieser mit Veröffentlichung der neuen Version behoben.

def countdown_overlay( camera ):
    n=4
    for i  in range(1,n):
	gc.collect()
    	img = Image.open(str(i)+'.png')
    	pad = Image.new('RGB', (
        	((img.size[0] + 31) // 32) * 32,
        	((img.size[1] + 15) // 16) * 16,
        	))
    	pad.paste(img, (0, 0))
	o = camera.add_overlay(pad.tostring(), size=img.size)
	o.alpha = 100 #128
    	o.layer = 3
	sleep(1)
	camera.remove_overlay(o)
   	del img
   	del pad



1.4 4-Fachdarstellung der geschossenen Bilder (Speicherung aller Einzelbilder und der 4er-Bilder)
Um den gesamten Fotoprozess zu beschleunigen und so mehreren Leuten die Möglichkeit zum Fotografieren zu geben, entschied ich mich, anders als bei Chris die Bilder nicht einzeln sondern alle 4 Bilder gleichzeitig nach der Session auf dem Bildschirm darzustellen. Auch hier kommt wieder Imagemagick ins Spiel und kombiniert die 4 Einzelbilder zu einem:

    #Aus den 4 Einzelbildern 1 Bild montieren
    graphicsmagick = "montage "+ file_path + now + "-01.jpg " + file_path + now + "-02.jpg " + file_path + now + "-03.jpg " + file_path + now + "-04.jpg -geometry 640x512+2+2 "+ file_path + now + "-montage.jpg "
    os.system(graphicsmagick)
    #Kopieren der Einzelbilder nach ./single und in Anschluss löschen
    bilder_wech="cp "+ file_path + now + "-01.jpg " + file_path + now + "-02.jpg " + file_path + now + "-03.jpg " + file_path + now + "-04.jpg "+ file_path + "single/"
    os.system(bilder_wech)
    bilder_wech="rm -f "+ file_path + now + "-01.jpg " + file_path + now + "-02.jpg " + file_path + now + "-03.jpg " + file_path + now + "-04.jpg " 
    os.system(bilder_wech)

8.JPG

1.5 Standby-Replay Modus
Um den Bildschirm optimal auszunutzen sollen während der Fotopausen, d.h. wenn gerade keine Bilder gemacht werden, nach dem Zufallsprinzip Bilder angezeigt werden. Hierzu wird bei jedem Aufruf der Funktion das Bildverzeichnis eingelesen und dann aus dieser Menge fortlaufend zufällig Bilder ausgewählt und angezeigt, bis ein Benutzer den Auslöseknopf drückt. So können sich Benutzer einfach bereits gemachte Bilder anschauen und sich weitere Ideen für neue Fotos holen.

while not GPIO.event_detected(button1_pin) :
		piclist = list()
		x = 0
		for infile in glob.glob(os.path.join(file_path,'*.jpg')):
			piclist.append(infile)
		print random.choice(piclist)
		pygame.display.set_caption('Photo Booth Pics')
		pygame.mouse.set_visible(False) #hide the mouse cursor
		filename = random.choice(piclist)
		del piclist
		img=pygame.image.load(filename)
		img = pygame.transform.scale(img,(transform_x,transfrom_y))
		screen.blit(img,(offset_x,offset_y))
		pygame.display.flip() # update the display
		sleep(3)
		#print "next pic..."
		gc.collect()	

	pygame.quit()
	print "killed random image process"
	GPIO.remove_event_detect(button1_pin)
	start_again = True
	GPIO.output(led2_pin,False)



1.6 RGB LED Beleuchtung
Eine schöne optische Verbesserung mit positivem Nebeneffekt bietet der (die) RGB-LED Strip. Zum einen macht die Beleuchtung natürlich einen tollen Eindruck und unterstützt gleichzeitig in den Abendstunden oder bei schlechten Lichtverhältnissen beim Fotografieren. Fernbedienung und IR Empfänger sind seitlich in der Wartungsklappe untergebracht, was einen schnellen Farbwechsel oder eine Anpassung der Helligkeit ermöglicht. Um noch mehr Lichtleistung in den schmalen Schlitz zu bekommen, entschied ich mich 2 LED Streifen einzubauen. Einen, der nach oben strahlt und auf eine weiße und somit reflektierende Fläche trifft und einen anderen, der direkt nach vorne strahlt. Durch das auf der Rückseite aufgerauhte Plexiglas wird die Scheibe diffus und matt und bietet so ein recht gleichmäßiges relativ blendfreies Licht.

4.JPG

9.JPG




1.7 Mini Webgallerie auf lokalem Webserver
Um den Gästen die Möglichkeit zu geben sich die Bilder mit dem Smartphone oder Tablet anzusehen, benötigte ich neben einem Webserver eine Galleriesoftware, die möglichst wenig Ressourcen benötigt und möglichst ohne große Konfiguration und zusätzliche Bibliotheken oder Datenbanken auskommt. Nach einiger Suche stieß ich auf MiniGal (http://www.minigal.dk/) Perfekt! Nachdem der Server und die Gallerie aufgesetzt waren, stellte ich jedoch ein Problem fest welches mich davon abbrachte, diese Konfiguration produktiv einzusetzen: Die Generierung der Vorschaubilder in der Gallerie geschieht scheinbar ebenfalls mit Imagemagick - Eigentlich kein Problem, doch bei einer Vorschau von 8 Bildern, wurden ebenfalls auch 8 Prozesse gestartet, die die kleine CPU des Raspberry für kurze Zeit vollständig auslasteten. Da gerade bei vielen gleichzeitigen Zugriffen auf den Webserver die Lauffähigkeit des Photobooth Programms nicht sichergestellt werden kann, entschied ich mich dieses Feature zu deaktivieren.

1.8 WiFi Accesspoint
Eigentlich der Tatsache geschuldet, dass der Ethernetanschluss des Pi nur schlecht zu erreichen ist richtete ich einen WLAN Accesspoint, DHCP und DNS Server auf dem Raspberry ein. So ist eine schnelle und unkomplizierte Wartung per WLAN und Laptop, Handy oder Tablet möglich. Leider läuft der Accesspoint nicht wirklich stabil und ich habe häufiger Probleme mich mit dem WLAN zu verbinden. Nach ein paar Neustarts ist das Problem jedoch meist behoben. Ursache könnte der verwendete Stick oder aber ein Softwareproblem sein. Da der Zugriff aber i.d.R. nur bei Problemen oder Wartungen von Nöten ist, ist dies kein Problem.

1.9 Shutdown/Reset Prevention Routine
Nach einigen Stunden des Testens, stellte ich immer wieder fest, dass die Hardwarebuttons scheinbar ohne ersichtlichen Grund von Zeit zu Zeit schließen bzw. auslösen. Beim Auslösebutton ist dies zwar nicht besonders schlimm (man hat eben nur ein leeres Foto), bei den Knöpfen für Shutdown oder Reboot liegt das Problem jedoch auf der Hand. Leider konnte ich nicht wirklich herausfinden, was der Grund für das ungewollte auslösen der Buttons ist. In Supportforen habe ich Leute mit einem ähnlichen Problem, aber ohne eine vernünftige Lösung gefunden. Um nun also dieses ungewollte Drücken zu unterbinden, habe ich eine kleine Routine programmiert, die den Shutdown oder Reboot Befehl erst dann durchführt, wenn der Button längere Zeit gedrückt wird. Diese Lösung ist allerdings programmiertechnisch nicht sauber und eher experimentell, aber sie funktioniert (irgendwie… ;-) ).

def reset_event_detection_shutdown():
	sleep(0.5)
	GPIO.remove_event_detect(button2_pin)
	sleep(0.1)
	GPIO.add_event_detect(button2_pin, GPIO.FALLING, callback=shut_it_down, bouncetime=300) 

def shut_it_down(channel):
	sleep(0.5)
	counter=0
	while GPIO.input(channel) == GPIO.LOW :
		counter=counter+1
		sleep(0.1)
	     
	if (counter >= 8): 
		print str(counter) + "counter"
		print "Shutting down..." 
		GPIO.remove_event_detect(button2_pin)
		lightshow(1)
		#GPIO.output(led1_pin,True);
		#GPIO.output(led2_pin,True);
		#GPIO.output(led3_pin,True);
		#GPIO.output(led4_pin,True);
		time.sleep(3)
		os.system("sudo shutdown now -h")
    	
	else:
		print "Press longer to shutdown!"
		print str(counter) + "counter"
		reset_event_detection_shutdown()


3.JPG

1.10 Externer Buzzer
Neben dem Auslöser an der Box wollte ich gerne noch eine Möglichkeit eines stehenden Buzzers realisieren, der etwas von der Box entfernt stehen sollte. Da ich beabsichtigt hatte den Buzzer später auch zu beleuchten, brauchte ich also eine 4-adriges Kabel und eine Möglichkeit ihn einfach von der Box an und abzukoppeln. Hier entschied ich mich auf ein USB Kabel zurückzugreifen, was sich m.E. hierfür prima eignet.
6.JPG

1.11 Beleuchtete Auslöseschalter
Um die Gäste zu animieren und das Aussehen optisch zu verbessern entschied ich mich die Buttons noch zu beleuchten. Standardmäßig sind die Arcardebuttons mit 12V Glühbirnchen versehen, was eine (An-)Steuerung mittels Raspberry und GPIO erschwerte, da dieser nur 5V liefert. Also entschloss ich mich die Beleuchtung komplett autonom zu steuern und verpasste dem Lampensystem ein eigenes 12V Netzteil welches ich mit einem Wechselblinker (Bausatz) koppelte. Sofern der Buzzer angeschlossen ist, blinkt der Auslöser am Gehäuse und der Buzzer im Wechsel, ansonsten ist die Lampe dauerhaft beleuchtet.



1.12 Speicherung der Fotos auf USB Stick statt SD Karte
Um zum einen Schreibzugriffe auf die SD Karte zu minimieren und das Kopieren der Fotos zu vereinfachen, habe ich einen USB Stick installiert, welcher beim Systemstart automatisch gemountet wird. Dieser ist FAT32 formatiert und kann also auch problemlos von Fremdbetriebsystemen wie MacOS oder Windows gelesen werden. Der Stick kann beim Systemstart mit folgendem Eintrag in der /etc/fstab automatisch gemundet werden:
UUID=<UUID des USBSTICK> /var/www/photos vfat defaults,auto,umask=022,users,rw 0
Die UUID kann mit dem Befehl blkid festgestellt werden.

Ich begann zunächst mit der Installation und Einrichtung des Raspbian Systems und begann dann mit dem Auf- und Nachbau der Elektronik auf einem Breadboard. Erste Tests funktionierten gut und so konnte ich mich dem Code widmen. Da ich nur wenig Erfahrung mit der Programmierung mit Python habe, war die Programmierung etwas holperig. Glücklicherweise findet sich überall gute Dokumentation im Netz und ich brauchte nicht viel neu zu programmieren und konnte so weite Teile von Chris‘ Code einfach recyclen.
Glücklicherweise verfügt mein verwendeter Monitor über eingebaute USB Schnittstellen, weswegen ein externes Netzteil für den Raspberry enfällt. Intern verwende ich eine 3fach Steckdose die mit Monitor, Lampennetzteil und LED Netzteil voll belegt ist. Durch die interne Verwendung der 3er Dose hat die Box nur ein Stromkabel welches nach aussen geht.
2.JPG 1.JPG



Probleme

  • Fehlendes Internet, daher keine Zeitsynchronisation --> keine bzw. falsche Zeitstempel bei Fotos
  • Aufgrund (vermutlich) langer Kabel willkürliches ungewolltes Drücken der Buttons (siehe 1.9)
  • WLAN Verbindungsprobleme (Verbindung mit Photobooth schlägt fehl)



Ideen für zukünftige Verbesserungen

  • Mobiles Internet mit DynDNS Adresse für Wartungszwecke
  • Ethernet Wartungsanschluss
  • Sound (Auslösegeräusch, Countdown Ton)

5.JPG

7.JPG

Der komplette Code: photobooth.py

Kommentare

1. Am Freitag, September 25 2015, 14:10 von martin

Hallo!

Cooles Projekt!

Hätte nur noch eine Frage zur Qualität der Fotos. Wenn ich das 4er-Bild erstelle und darstelle, ist die Qualität eigentlich viel schlechter als bei den Einzelbildern.
Werden die Bilder vor der Erstellung der 4er-Bilder noch komprimiert?

Danke!
Martin

2. Am Montag, Dezember 7 2015, 13:24 von Malte

Hallo Martin,

die Bilder werden in dem Sinne nicht komprimiert, sondern einfach nur herunterskaliert. Das passiert mit dem montage Befehl aus dem imagemagick Paket:
montage 01.jpg 02.jpg 03.jpg 04.jpg -geometry 640x512+2+2 montage.jpg
Das bedeutet jedes der Einzelbilder hat effektiv eine Größe von 640x512 Pixeln. Es kommt halt immer darauf an was man möchte, ich finde die Qualität ok und würde sagen sie ist auf dem Monitor nicht wirklich sichtbar... Die Ursprungsbilder sind davon ja nicht betroffen und bleiben einzeln erhalten.

Gruss
Malte

3. Am Dienstag, Februar 9 2016, 13:20 von THOMAS

Hallo malte ich heirate auch bald und habe mir in den kopf gesetzt auch eine fotobox zu bauen.
aber ich kenne mich leider viel zu wenig mit dem programmieren aus, das ich das verstehen könnte was ich wo eintragen muss zb.werden die bilder bei mir nicht geschspeichert,wo muss ich denn den pfad eintragen,wenn ich den grossen roten knopf betätige kommt ganz kurz ein bild und dan tut das progamm beenden

i@pi:~ $ cd Desktop/
pi@pi:~/Desktop $

sudo python foto.py
Photo booth app running...

OK

(Drücke grossen roten knopf)

Get Ready
Traceback (most recent call last):

File "foto.py", line 407, in <module>

start_photobooth()

File "foto.py", line 273, in start_photobooth

countdown_overlay(camera)
File "foto.py", line 203, in countdown_overlay

img = Image.open(str(i)+'.png')

File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 2251, in open

fp = builtins.open(fp, "rb")
IOError:
[Errno 2] No such file or directory: '1.png'
Ended abruptly
pi@pi:~/Desktop $

4. Am Samstag, Februar 13 2016, 17:49 von Benni

Es fehlen die Fotos die in Programmierung abgefragt werden.
File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 2251, in open
Generiere in Paint ein paar Fotos und lege die in der /usr/lib/python2.7/dist-packages/PIL/

5. Am Sonntag, Februar 21 2016, 10:37 von Thomas

Danke Benni ,das hat funktioniert

6. Am Dienstag, August 16 2016, 23:26 von mathias

Hi ! Ich würde mir auch gerne eine Photobooth bauen... Den Raspberry habe ich soweit vorbereitet und dein script erstmal so wie es ist übernommen; nun stoße ich bei einem ersten Test auf folgendes Problem: Ich starte das Script mit "sudo python photobooth.py", dann werden vier Fotos geschossen, doch dann hängt sich das Script mit folgenden Meldungen auf:
Taking Pics
/var/www/photos/20160816231135-01.jpg
sh: 1: composite: not found
/var/www/photos/20160816231135-02.jpg
sh: 1: composite: not found
/var/www/photos/20160816231135-03.jpg
sh: 1: composite: not found
/var/www/photos/20160816231135-04.jpg
sh: 1: composite: not found
Processing Pics...
sh: 1: montage: not found
Traceback (most recent call last):
File "photobooth.py", line 407, in <module>
start_photobooth()
File "photobooth.py", line 313, in start_photobooth
traceback.print_exception(e.__class__, e, tb)
NameError: global name 'traceback' is not defined
Ended abruptly

Wäre super wenn du mir weiterhelfen könntest !!!

7. Am Donnerstag, August 18 2016, 12:20 von perry

Hi Matthias,

hatte die selbe Meldung. Nach dem installieren
von "graphicsmagick-imagemagick-compat"
mittels

"sudo apt-get install graphicsmagick-imagemagick-compat"

funktionierte es dann...

mfg PerryR

8. Am Mittwoch, November 23 2016, 17:59 von Hanner

Hallo Benni,

Ich hab auch das gleiche Problem wie Thomas mit dem fehlenden 1.png Bild.
Leider hilft nicht dass ich ein Bild mit 1.png in den PIL Ordner lege.
Wie sollen die Dateien heissen und wie viele sollen es sein?
Danke für deine Hilfe im Voraus.

9. Am Donnerstag, November 24 2016, 11:33 von Hanner

Hallo,
Habs geschafft!
Die Bilder 1.png, 2.png und 3.png gehören ins Verzeichnis /home/pi

LG

10. Am Sonntag, Dezember 18 2016, 20:48 von Robby

Hallo vielen dank für das unschlagbare Skript !

gibt es auch die Möglichkeit die 4 bilder neben bzw untereinder anzeigen zu lessen als 2x2 sozusagen ?

gruß Robby

11. Am Sonntag, Dezember 18 2016, 20:49 von Robby

Ich entschuldige mich mal für die Rechtschreibung . Zustand nach Weihnachtsmarkt :D

12. Am Montag, Februar 20 2017, 15:25 von Malte

Ich habe völlig übersehen, dass sich hier noch soviel Feedback angesammelt hat :)
Ihr habts ja letztendlich glücklicherweise auch so hinbekommen!

13. Am Montag, Juli 31 2017, 11:56 von nsfive

Hi Malte, Super Projekt, wollte es auch mal Testen für eine Party, habe aber noch folgende Fehlermeldung und bin kein Programierer.

Photo booth app running...
OK
Get Ready
Traceback (most recent call last):
File "photobooth.py", line 407, in <module>
start_photobooth()
File "photobooth.py", line 273, in start_photobooth
countdown_overlay(camera)
File "photobooth.py", line 214, in countdown_overlay
o = camera.add_overlay(pad.tostring(), size=img.size)
File "/usr/local/lib/python2.7/dist-packages/PIL/Image.py", line 712, in tostring
raise NotImplementedError("tostring() has been removed. "
NotImplementedError: tostring() has been removed. Please call tobytes() instead.
Ended abruptly

14. Am Mittwoch, November 1 2017, 11:06 von Malte

Hi nsfive,
ich kann jetzt nicht direkt sagen was es ist... es scheint aber, dass die Funktion tostring() in der Form nicht mehr gibt. Google mal... es gibt diverse Einträge die das Thema behandeln :)

Kommentar eintragen

HTML-Code wird als normaler Text angezeigt, Links und Email-Adressen werden automatisch umgewandelt.

Die Kommentare dieses Eintrags als Atom-Feed abonnieren