Update, August 2021: I’ve refactored some of this code to instead control a mounted iPhone. See some of the changes I’ve made to Photo Booth 2.0.
Photo booths are expensive to rent. But if you have a camera and an old monitor lying around, you can make a much more versatile photo booth for less than $150!
I recently hosted a big milestone birthday party for my wife. I thought it’d be fun to have a photo booth at the party, so I called a couple of rental places a few months ago. I was surprised to learn that here in Seattle, photo booths can cost anywhere from $800 to $1,500 per night for a full setup!
And even with that expense, the quality of the photos you’ll get is generally worse than that delivered by a standard webcam. The technology built into these photo booths is often cheap and dated. And as for output, they might print out a throwaway strip, but I’ve never seen one where you could get the photos where most people want them: on their phones.
Finally, the resolution, bokeh, etc. of these rented booths is quite inferior to what my own mirrorless camera is able to take. I already own a good-quality camera (Fuji X-T2 — I love it!)
So why not make a photo booth?
Added Features: SMS Sharing, Big Screen Slideshow
Rather than generating printed leave-behinds, I wanted people to be able to walk away with the “originals” on their own cellphones, maybe even easily share them to Instagram or social media.
This seemed pretty easy to enable if I could build a photo booth that connected to the Internet. I figured a QR code could send users to the “live album”, where they could see the photos and download them onto their devices.
The venue also happened to have a big-screen projector in the bar area. I wanted to be able to put some of the best photos up on the big screen during the evening. So what I really wanted was an automated photo booth PLUS a back-end internet service which stored photos and let people see them quickly, and also let an “administrator” favorite the best ones for featuring in the slideshow.
So, back in May, I set out to build my own photo booth using a Raspberry Pi, my mirrorless Fuji X-T2 camera, and a custom web app hosted on Azure.
Perhaps the biggest difficulty was that this was a surprise — so all this assembly and testing work had to be done out of sight. So, fair warning: some of what you’ll see here is kind of slapdash. But it all came together pretty well — and it all worked beautifully unattended!
There are three basic options for Raspberry Pi controlled image capture:
- OPTION A: Use a DSLR or mirrorless camera, and make use of gphoto2 to drive it
- OPTION B: Connect a Webcam to the USB input of the Raspberry Pi and capture images with fswebcam. I tried both the Logitech 9200 and the Logitech BRIO, and both worked fine with fswebcam and ffmpeg, but I still felt the image quality of my mirrorless camera was far superior, particularly in low lighting.
- OPTION C: Use the official Raspberry Pi Camera (now in version 2), and capture images with fswebcam
I chose Option A because it’s by far the best image quality in low lighting, it allows for an auto-focus camera, and it allowed me to use the lenses and equipment I already own.
But before I go on, let me say that Options B and C have major benefits too, and there were a few times that I seriously considered abandoning the mirrorless camera altogether. A webcam-based photo booth is far easier and much more reliable: In my own tests with a high resolution Logitech BRIO, fswebcam appears to capture pictures and transfers data quite reliably, has perfectly adequate photos, and doesn’t have any of the fussy driver error/connections that I encountered, nor does it have the power management problems inherent in a separate camera. (With Option A, you need to ensure your camera either has enough battery life for the evening, or is connected to a power source and won’t go into “sleep” mode.) Option B also works well to capture short video segments if you prefer that approach — for instance, if you want to capture a short video, you can issue the command:
ffmpeg -t 120 -f v4l2 -framerate 25 -video_size 640x80 -i /dev/video0 output.mkv
… assuming your webcam is on /dev/video0.
OK, back to Option A: using gphoto2 to control a digital camera.
- A digital camera controllable via a USB cable — be sure to choose one compliant with gphoto2. There’s a long list.
- Empty SD card(s) for your camera: WARNING — the code in the Github repository below DELETES all the images on your camera’s SD card when starting up, by design. This is to allow faster file transfer and error recovery.
- Display Monitor — I used an old HD LCD monitor with DVI input, and an HDMI to DVI cable.
- Raspberry Pi 3B+ and power supply
- 110v Relay Switch – this is used to turn on and off the LED ring light used for the photos
- Case for Raspberry Pi — optional, but helps to keep the project neat and tidy
- Lighting (I chose this inexpensive LED Ring Light)
- Extension cord
- Illuminated Arcade Button
- Power strip (to mount inside the enclosure)
- AC power for your camera (you’ll want to have your camera powered on throughout the evening)
- USB cable (to connect the Raspberry Pi to your camera)
- A wood enclosure (Thanks to friend Tim and his workshop for this!), paint, finishing hardware and carrying handle
- Camera tripod or mounting bracket
- Speaker tripod (to hold the monitor — I found a cheap one for about $40 at a local music supply center.)
- Speaker mount
- Extension cord
- Props for Photo Booth – hats, signs, etc.
Don’t expect this post to be fully comprehensive; I just want to provide enough detail to give you a basic feel of how to build one of these things. Anyone with basic working understanding of Raspberry Pi and Python should be able to take this code and some of the ideas here and build a fully functional system.
The back-end service is optional; you can always recover the photos at the end of the evening. If you plan to do so, I’d advise commenting out the “delete all photos” code is in the photo booth’s startup routine.
I’d love to hear your ideas and comments, so drop them in the comments section below.
The brains of the Photo Booth is a Raspberry Pi 3B+.
Install gphoto2 to your Raspberry Pi:
sudo apt-get install gphoto2 -s
But there’s a fair amount of steps to get gphoto2 to work. Follow the instructions at this detailed post to get gphoto2 working, and verify it manually works before continuing.
A wifi connection is used to upload the photos to an Internet service which I created (popsee.com.) At present, I’m not making popsee.com available to the public — it’s part of a larger project which lets people request and submit videos — but I might consider some kind of simple public access as time goes on.
But you can easily take the code written here and POST the images to your own destination from the Raspberry Pi, like Dropbox or Google Photos.
Customize the file postimage.py to intercept the posting of images and the messages to display to remote users.
The basic responsibilities of the back-end popsee app are:
- Receive images to be POSTed
- Provide a real-time messaging to the user or administrator (done via SignalR — e.g., users using the app will see “photo uploading”, etc. status messages, and also see the new photos.) I built a POST endpoint into the app which lets the Raspberry Pi broadcast messages to the outside world about its status.
- Let administrator favorite or delete photos for the slideshow
- Display a slideshow of “favorited” photos in an “album”, which updates in real-time as new favorited photos are added
- Let users review photos and send the ones they want to their cellphone (done via Twilio)
Once the photo built is assembled (below), set up the photo booth and accompanying props in a high visibility area. Put a backdrop up (I didn’t have much time for this step.) It’s best to choose an area where it’s unlikely to get bumped or jostled. You’ll also want to orient the LED ring light away from the main crowd, as it can be distracting during the evening, turning on and off all the time. So an alcove of some kind is perfect. Station props nearby.
A guest walks up and presses the flashing blue button. The guests are told to “GET READY”, and they get three photo countdowns. The first is five seconds, and the second and third round are 3 seconds each.
With each countdown, the Photo Booth CPU turns on lighting (the LED ring light in this case), snaps the photo, loads it from the camera to the Raspberry Pi, presents it on-screen, uploads it in the background to the web. It repeats this process two more times. After finishing, it returns to kiosk mode.
I set this up at a party with about 150 people, and, though it was really dark and the backdrop could have been improved, the photos turned out pretty well:
Let’s Get Started
I strongly recommend you begin by trying to get the Raspberry Pi to “talk” to your digital camera via a Terminal and gphoto2 commands. The connection of buttons to trigger the countdown and the customization of the python scripts are pretty straightforward once you cross that item off your list.
Set up Raspberry Pi
Begin by getting your Raspberry Pi hooked up to a keyboard and mouse with Raspbian and on the Internet. (One gotcha I encountered: if you are using a MicroSD card that’s bigger than 32Gb, be sure to format it as FAT, not ExFAT, or else your Raspberry Pi won’t boot.)
Get your Raspberry Pi set to 1440×960 resolution via:
You’ll find screen resolution under the advanced options > Screen Resolution menu.
Next, Get “gphoto2” Working on Raspberry Pi
Before going further, the most crucial step is to ensure that your Raspberry Pi can communicate with your camera to take photos, download images, delete images, and reset the USB (which in my case sometimes became necessary due to gphoto2 not being fully bug-free when communicating with my Fuji X-T2.)
gphoto2 is an essential library which allows your Raspberry Pi to speak to a digital camera. Many digital cameras today have USB inputs which let you control the camera (take photos, download the images, etc.) The Picture Transfer Protocol (PTP) interface has become a widely used standard on many makes and models.
The entire Photo Booth controller is written in Python, and makes use of the gphoto2 library to control it.
First, get your Raspberry Pi set up with the Raspbian operating system. I strongly recommend you use a keyboard and monitor to connect to it rather than using a headless browser. I purchased the dedicated cheap Raspberry Pi keyboard and mouse for this purpose and am keeping it with the photo booth enclosure.
Double-check that Python runs on it by opening up a terminal and typing “python”. You should see the python prompt. Type quit() to exit out of it.
Next, let’s get gphoto2 set up, so your Raspberry Pi can communicate with your camera. It takes several steps, involving cloning the library from Github and compiling them for your specific Raspberry Pi. Let’s start by ensuring your Pi is up to date:
sudo apt-get update sudo apt-get upgrade
Now that we have everything up to date we will need to download the packages that we need for compiling the gphoto2 software that we will be utilizing.
Run the following command to install all the packages that we will be needing:
sudo apt-get install git make autoconf libltdl-dev libusb-dev libexif-dev libpopt-dev libxml2-dev libjpeg-dev libgd-dev gettext autopoint
Once all the packages have finished installing, get the libgphoto2 source code and compile it. Get the latest available version straight off the libgphoto2 Github by running the following command to clone it:
git clone https://github.com/gphoto/libgphoto2.git cd ~/libgphoto2 autoreconf --install --symlink ./configure make sudo make install
Now you need to compile the gphoto2 wrapper library:
cd ~ git clone https://github.com/gphoto/gphoto2.git cd ~/gphoto2 autoreconf --install --symlink ./configure make sudo make install
With the gphoto2 software now compiled we need to ensure that it can find the library that we compiled in the previous steps.
To start , we will first ensure that the configuration file referencing the “/usr/local/lib” folder exists.
Open up the file by running the following command on your Raspberry Pi:
sudo nano /etc/ld.so.conf.d/libc.conf
Inside this file, you should find the following text, if it does not exist already then enter it:
# libc default configuration /usr/local/lib
Now that we have ensured that the “/usr/local/lib” directory is being included we need to refresh the config cache so that the directory will be searched by the operating system when linking libraries.
To do this, we need to run the ldconfig tool by running the command below.
In the next few steps, we have to generate the udev rules for the cameras that you might be connecting. Without this, the gphoto2 application may not be able to talk with your camera.
Let’s generate the required udev list by running the following command. We will pipe the command directly into a rules file that the udev service will automatically read.
/usr/local/lib/libgphoto2/print-camera-list udev-rules version 201 group plugdev mode 0660 | sudo tee /etc/udev/rules.d/90-libgphoto2.rules
Finally, we need to generate the hardware database file for udev.
We can do this by running the following command. This command will automatically create the file in the correct location.
/usr/local/lib/libgphoto2/print-camera-list hwdb | sudo tee /etc/udev/hwdb.d/20-gphoto.hwdb
Now run the following command to test that gphoto2 is setup correctly:
Shortcut to Installing the full Gphoto2 Per Above
There’s a very nice script that user gonzalo has created, which will install the latest version of gphoto2:
The code also depends upon “usbreset”, which can be found here: https://raspberrypi.stackexchange.com/questions/9264/how-do-i-reset-a-usb-device-using-a-script
Ensure that the gphoto2 volume monitor doesn’t get run at every startup, because this interferes with the claiming of USB.
Remove execute privileges, for this photo monitor — run this at a terminal:
sudo chmod 644 /usr/lib/gvfs/gvfs-gphoto2-volume-monitor
Get the “photobooth.py” software from Github as a starter, and Customize
The code I wrote is up on Github, and should be a good starting point for your code:
cd ~ git clone https://github.com/stevemurch/photobooth
The main entrypoint is “photobooth.py“. You’ll want to rig your Raspberry Pi to run that program on startup.
UPDATE: Because I wanted to be able to use this same booth at different parties with different startup screens, the code now reaches out to the popsee server to get the configuration data at startup. You can disable this code by commenting out the call to get_current_config().
Install Other Dependencies
I wanted some sound with my photo booth, so photobooth.py requires mpg321, a sound player. Install it as follows:
sudo apt-get install mpg321
Photo Booth Setup
If you’ve got a Raspberry Pi communicating with your camera, ensure your USB cable is connected, and try running these statements at the command line:
gphoto2 --capture-image-and-download gphoto2 --capture-image gphoto2 --reset gphoto2 --list-files
If these run, congratulations! You’ve got the brains of the Photo Booth already working. It’s all downhill from here.
What I wanted my photo booth to do was to start in Kiosk Mode, flash the physical GO button on the enclosure and then, when the button was pushed, do this three times: (a) tell the audience to get ready, (b) turn on the LED ring light, (c) count down, (d) snap the photo, (e) turn off the LED ring light, (f) fetch the image from the camera and present it to the user, and (g) upload it to my back-end web service (popsee.com.)
Thus, for hardware inputs and outputs, there’s an input arcade-style button with a flashing LED light, a monitor (with sound), and a 110v GPIO-activated relay switch which temporarily turns on and off the photographic light.
- GO BUTTON (called BUTTON_BCM_PIN in the code; I connected this to physical pin 15)
- RESET BUTTON (used in testing but I didn’t end up using in deployment)
- LED LIGHT for GO BUTTON (called LED_BCM_PIN in the code; I connected this to physical pin 22)
- RELAY (called RELAY_CONTROL_PIN in the code; physical pin 12) to turn on 110V extension cord — the LED ring light is plugged into this cord
You can see the current setting of these in the photobooth.py code on Github.
Server: How Photos are Seen & Shared
Rather than printing out photos, since everyone has a mobile phone these days, I wanted to use that as a way to share the photos. The photo booth shows you a QR code, which leads the user to a website I created (popsee.com) with the “album” of the evening. There, they can review the photos and send the ones they want to their own phone.
In addition, an administrator can “favorite” the photos, marking them to be shown in the big-screen slideshow (projected from another computer.)
This was a simple Angular application hosted on Azure which takes POSTed photos for a given “album”. This will be the subject of a future post.
For now, you can disable this POSTing of photos by commenting out the functions in the “postimage.py” code.
At present writing, I don’t plan on opening up popsee.com to the general public, but may consider doing so in the future. If you’ve gotten this far, it should be relatively simple to wire up your own photo posting and review service — or you might even consider rewriting the code to post them to Twitter, Google Photos or Dropbox.
Steve’s a Seattle-based entrepreneur and software leader, husband and father of three. He’s American-Canadian, and east-coast born and raised. Steve has made the Pacific Northwest his home since 1991, when he moved here to work for Microsoft. He’s started and sold multiple Internet companies. Politically independent, he writes on occasion about city politics and national issues, and created voter-candidate matchmaker Alignvote in the 2019 election cycle. He holds a BS in Applied Math (Computer Science) and Business from Carnegie Mellon University, a Masters in Computer Science from Stanford University in Symbolic and Heuristic Computation, and an MBA from the Harvard Business School, where he graduated a George F. Baker Scholar. Steve volunteers when time allows with Habitat for Humanity, University District Food Bank, Technology Access Foundation (TAF) and other organizations in Seattle.