01 Overview
Portable, custom-built photo booths are traditionally bulky and rely on expensive computer hardware. This tutorial walks you through building an ultra-compact, touchscreen pocket photo booth using the CrowPanel ESP32 3.5 HMI Display module.
By combining an integrated ESP32 microcontroller, a high-resolution camera, and a local Wi-Fi web server, this system creates a self-contained photo-capturing device that lets users preview, capture, apply custom retro filters, and instantly download photos directly to their smartphones and computer.
Project Use Case
This project is built for makers, event hosts, and hobbyists who want a self-contained, battery-friendly photo booth without dragging along a laptop or DSLR rig. It is well suited for parties, small gatherings, or maker-fair demo booths, where guests can frame a shot, apply a retro filter, and pull the photo straight onto their phone over the device's own Wi-Fi network.
Core Technologies
- ESP32 SoC — A low-cost, low-power system-on-a-chip with integrated Wi-Fi and dual-mode Bluetooth.
- HMI Display — Human-Machine Interface screens designed to visualize data and accept user touch inputs.
- CH340 USB-Serial Bridge — Converts USB signals to serial UART, allowing the computer to communicate with the ESP32.
Module Workflows
The ESP32 enters a serial bootloader mode upon reset if specific GPIO pins are pulled low, allowing new firmware to write to flash memory. Data travels asynchronously over TX (transmit) and RX (receive) lines at a matching baud rate.
02 Hardware and Software Components
Gather everything below before you start.
Hardware Components
| Component | Description |
|---|---|
| CrowPanel-ESP32 Terminal 3.5" | Main controller and touchscreen display with built-in Wi-Fi |
| OV2640 Camera | 2MP camera module for live preview and photo capture |
| MicroSD Card | Local storage for saving photos and assets |
Software Tools
| Software | Version / Details |
|---|---|
| Arduino IDE | Latest stable release |
| LovyanGFX | Fast graphics driver for ILI9488 LCD |
| WiFiManager | Auto Wi-Fi configuration portal |
| esp_camera | Official Espressif ESP32 camera driver |
03 Application Discussion
Here is what each component does and why it is part of this project.
CrowPanel-ESP32 Terminal 3.5"
The CrowPanel-ESP32 Terminal 3.5" is the main brain and screen of the photo booth. It runs the software, registers screen touches, and displays the user menu. Its built-in Wi-Fi allows users to download photos directly to their phones using the device's IP address.
OV2640 Camera
The OV2640 Camera takes the photos for the booth. It continuously streams a live video feed to the screen so users can frame their shots. When a user taps the screen, the camera instantly captures a clear, high-resolution picture.
MicroSD Card
The MicroSD Card acts as permanent storage memory. It saves all taken photos in organized folders so they are not lost when the device turns off. It also stores menu graphics and digital photo frames used to decorate pictures.
04 Hardware Setup
Wire the camera, storage, display, and feedback components to the board using the tables below.
Full System Connection Details
| Component | Interface | Purpose |
|---|---|---|
| OV2640 Camera | 8-bit Parallel Bus + I²C/SCCB | Live image streaming and camera settings |
| MicroSD Card Slot | SPI / SDIO | Save and store captured photos |
| Audible Buzzer | Digital GPIO (NPN transistor) | Shutter click sound feedback |
| 3.5" TFT LCD Screen | High-speed SPI / Parallel Bus | Live camera preview and UI menus |
| Capacitive Touch Controller | I²C (SCL/SDA) + INT line | Finger tap detection and touch events |
| Type-C USB | 5 V Power + USB-Serial | Power supply and firmware flashing |
Pin Definitions
| Signal | GPIO | Function |
|---|---|---|
| TOUCH_SDA | 2 | I²C data for touch controller |
| TOUCH_SCL | 1 | I²C clock for touch controller |
| LCD_MOSI | 13 | SPI data out to LCD |
| LCD_MISO | 14 | SPI data in from LCD |
| LCD_SCK | 12 | SPI clock |
| LCD_CS | 3 | LCD chip select |
| LCD_DC | 42 | Data/command select |
| LCD_BL | 46 | Backlight PWM control |
| SD_CS | 10 | MicroSD chip select (shared SPI bus) |
| BUZZER_PIN | 45 | NPN transistor shutter click |
| CAM_XCLK | 7 | Camera clock signal |
Assembly Instructions
- Mount the OV2640 camera module to its parallel-bus and I²C/SCCB header on the back of the CrowPanel board.
- Insert a formatted MicroSD card into the onboard slot, which shares the SPI bus used for the display.
- Confirm the buzzer is connected through its NPN transistor stage to
BUZZER_PIN(GPIO 45) for shutter-click feedback. - Snap the acrylic shell into place once wiring is confirmed, leaving the USB-C port and camera lens accessible.
- Connect the board to your computer via USB-C for power and firmware flashing.
LCD_CS and SD_CS are wired to separate, correctly defined chip-select pins to avoid bus conflicts.05 Software Setup
Follow these steps in order to prepare the Arduino IDE before flashing the firmware.
Step 1 — Install the Arduino IDE and ESP32 Board Core
- Install the latest stable release of the Arduino IDE.
- Add the Espressif ESP32 board package through the Boards Manager so the IDE can compile for the Tensilica Xtensa processor used on the CrowPanel.
Step 2 — Board Settings
Use exactly these settings in your IDE. Wrong settings will cause upload failures.
| Setting | Value |
|---|---|
| Board | ESP32 (match the CrowPanel's specific chip core — WROOM, WROVER, or S3) |
| PSRAM | Enabled (QSPI or OPI, as required for the large LCD framebuffer) |
| Upload Driver | CH340 USB-Serial driver installed on the host computer |
Step 3 — Install Libraries
Install the following libraries via the Library Manager:
- LovyanGFX — fast graphics driver for the ILI9488 LCD
- WiFiManager — auto Wi-Fi configuration portal
- esp_camera — official Espressif ESP32 camera driver
- Wire, SPI, and SD — bundled with the ESP32 board core
Step 4 — Upload the Code
- Connect the CrowPanel to your computer via USB-C.
- Select the correct COM port and the board settings from Step 2.
- Click Upload.
06 Code
The firmware is organized into logical blocks. Copy each block below into the correct location in your sketch, and read the Code Breakdown section to understand what each part does. The full code can be seen in number 6.
1 — Hardware & Pin Definitions
All pins and dimensions are defined in one place for easy reconfiguration.
#define TOUCH_SDA 2
#define TOUCH_SCL 1
#define TOUCH_ADDR 0x38
#define LCD_MOSI 13, LCD_MISO 14, LCD_SCK 12
#define LCD_CS 3, LCD_DC 42, LCD_BL 46
#define SD_CS 10
#define BUZZER_PIN 45
// Camera
#define CAM_XCLK 7, CAM_SIOD 2, CAM_SIOC 1
// ... all data & control pins
#define CAM_W 320, CAM_H 240
#define LCD_W 480, LCD_H 320
2 — UI & State Management
Defines the filter enum, a reusable button struct, and all program state flags.
enum FilterMode {
FILTER_NONE, FILTER_GRAYSCALE,
FILTER_SEPIA, FILTER_INVERT, FILTER_MIRROR
};
struct Button { int x, y, w, h; const char* label; };
// State variables
bool cameraRunning = false;
bool photoCaptured = false;
bool editingPhoto = false;
int editBrightness = 0, editContrast = 0, editHighlights = 0;
3 — Camera & Image Processing
Handles camera init, image buffers, filter application, and capture/reprocessing.
bool initCamera(pixformat_t fmt);
// Image buffers
uint16_t* rgbBuf; // working buffer for processing
uint16_t* originalBuf; // unmodified original (non-destructive edits)
uint8_t* capturedJpeg; // final JPEG for display/saving
void applyFilter(uint16_t* buf, int w, int h);
void applyAdjustments(uint16_t* buf, int w, int h,
int brightness, int contrast, int highlights);
void swapAllBytes(uint16_t* buf, int count); // fixes byte order
bool capturePhoto(); // takes photo and saves original
bool reprocessCapture(); // re-applies filters/edits from original
4 — Storage & Web Server
// SD Card
bool mountSD();
bool saveToSD();
// Web server — serves HTML interface and JPEG image
void startPhotoServer();
static esp_err_t index_handler(httpd_req_t* req);
static esp_err_t photo_handler(httpd_req_t* req);
// Wi-Fi
bool connectWiFi(); // uses WiFiManager to auto-reconnect
void reconfigureWiFi(); // opens setup portal via button
5 — Display & UI Drawing
void drawHomeScreen();
void drawLiveUI();
void drawCaptureUI();
void drawEditScreen();
void drawButton(Button& b, uint16_t color);
6 — Full Code
The complete Arduino source code is provided as a separate file.
📥 Download FullCode.ino07 Code Breakdown
Here is what each part of the code does. Read this after uploading.
Libraries
| Library | Purpose |
|---|---|
| LovyanGFX | Fast graphics rendering for the ILI9488 LCD |
| Wire | I²C communication for the touch controller |
| esp_camera | Official ESP32 camera driver (Espressif) |
| WiFi + WiFiManager | Auto-connect and on-demand Wi-Fi setup portal |
| SPI + SD | SD card file system access |
| HTTP Server | Serves the web interface and JPEG download endpoint |
Key Functions
initCamera()
Configures the OV2640 sensor with the correct pin mapping, pixel format, frame size, and orientation. If initialization fails, an error is printed to Serial.
capturePhoto() / reprocessCapture()
capturePhoto() grabs a frame and stores the raw original. reprocessCapture() re-applies the current filter and brightness/contrast adjustments non-destructively from that saved original.
applyFilter() / applyAdjustments()
Operates on raw RGB565 pixel buffers. applyFilter() handles Grayscale, Sepia, Invert, and Mirror modes. applyAdjustments() modifies brightness, contrast, and highlights per pixel.
startPhotoServer()
Starts an HTTP server on the ESP32. index_handler serves the Photo Booth Viewer HTML page; photo_handler serves the latest JPEG as a binary response for download.
connectWiFi() / reconfigureWiFi()
connectWiFi() uses WiFiManager to auto-reconnect to saved credentials. reconfigureWiFi() opens the captive portal manually when the WIFI SETUP button is tapped.
General Program Workflow
- setup() — Initializes serial, pins, buffers, LCD, camera, and touch controller; shows the home screen.
- Home Screen — Waits for START or WIFI SETUP button tap.
- Live Preview — Streams camera frames to the LCD, applies the selected filter in real time.
- Capture Review — Displays the captured photo with SAVE WEB, EDIT, SAVE SD, HOME, and REDO options.
-
Edit Mode — Adjusts brightness, contrast, and highlights; calls
reprocessCapture()on each change.
08 Testing and Calibration
After uploading, verify each of the following to confirm the system is working correctly.
Home Screen Status Check
Power on the device and confirm the home screen reports Board Status: OK, Touch Status: OK, and Camera Status: READY. If any status fails, recheck the corresponding wiring from Section 04 before continuing.
Wi-Fi Connection Test
Tap WIFI SETUP and confirm the device broadcasts a hotspot with on-device instructions for connecting your phone.
Camera Preview and Filter Test
Confirm the live camera preview streams smoothly to the display and that all four filter buttons — GRAY, SEPIA, INV, and MIR — change the live image as expected.
09 System Demonstration
The images below show the working system end-to-end, from capture to download. Use these to verify your output matches what is expected.
Captured Photo & Save Options
After tapping SHOT, the captured image is displayed with action buttons.
| Button | Action |
|---|---|
| Save Web | Pushes the photo to the built-in web server for download via browser |
| Edit | Adjust contrast, brightness, and highlights before saving |
| Save SD | Saves the photo directly to the MicroSD card |
| Home | Return to the home screen |
| Redo | Discard capture and return to live preview |
Browser Web Interface
After tapping Save Web, open a browser on any device connected to the same Wi-Fi and navigate to the device's IP address. The Photo Booth Viewer page lets you load and download the latest captured photo.
Video Demonstration
10 Conclusion
This project shows that a fully self-contained, touchscreen photo booth can be built around a single ESP32 HMI module without any external computer. Pairing the OV2640 camera with non-destructive on-device filtering and a built-in Wi-Fi web server gives users an instant, phone-friendly way to capture and retrieve photos. The build highlights how carefully aligning chip core, drivers, and power supply is what separates a smooth bring-up from a frustrating one.
Findings
- Setting up the CrowPanel requires aligning the specific ESP32 chip core (WROOM, WROVER, or S3) with the target screen hardware size.
- Correct driver installation (CH340) and matching baud rates are crucial to avoiding connection failures and corrupted serial output.
- Using correct and sufficient voltage on the power supply port is essential to avoid permanently damaging internal components.
Possible Improvements and Future Enhancements
- Add a countdown timer mode for hands-free selfie captures.
- Implement JPEG quality selection so users can choose file size vs. image quality.
- Add an overlay / frame gallery stored on the MicroSD card for decorating photos.
- Integrate cloud upload (e.g., Supabase or Google Drive) directly from the device.
11 References
- ELECROW CrowPanel ESP32 Terminal Documentation — elecrow.com
- Espressif ESP32 Arduino Core — github.com/espressif/arduino-esp32
- LovyanGFX Library — github.com/lovyan03/LovyanGFX
- WiFiManager Library — github.com/tzapu/WiFiManager
- © Copyright 2012–2026 ELECROW
12 Project Authors
- FRANZ ALDRICH P. CADUNGOG
- JHOLAICA M. GUIAMAL
