Raspberry Pi: use the Camera Module v3 with libcamera and Picamera2
Wire a Camera Module v3 to a Raspberry Pi, capture stills and video from the command line with libcamera, and write Python with the modern Picamera2 library.
The Raspberry Pi Camera Module v3 is a 12-megapixel camera that costs about $35, plugs into the Pi’s CSI port, and runs on every Pi from the Zero 2 W to the Pi 5. It is the camera I reach for when I need “a real camera” for a project, not a USB webcam.
The software side changed a few years ago. The old raspistill and
raspivid commands are deprecated. The new system is libcamera, with
command-line tools (libcamera-still, libcamera-vid) and a Python
library called picamera2. This tutorial covers the modern stack.
What you need
- Raspberry Pi 4 or Pi 5 (Pi 3 works but is slow; Pi Zero 2 W works but is slow for video)
- Camera Module v3 (the v2 still works with this tutorial, the v3 has autofocus)
- The ribbon cable that ships with the camera
- Raspberry Pi OS Bookworm (64-bit) with desktop, or Lite plus
libcamera-appsandpython3-picamera2
The legacy raspistill vs current libcamera
The old way was the raspistill and raspivid commands, which used
Broadcom’s proprietary GPU code. The new way is libcamera, an
open-source stack that works on more hardware and is not tied to the
Pi.
If you see a tutorial from before 2022, it will say raspistill. That
command is gone. The replacement is libcamera-still with mostly
the same flags.
# Old
raspistill -o image.jpg
# New
libcamera-still -o image.jpg
The flag names are similar. The image quality is similar. The internal plumbing is completely different.
Install libcamera
On a fresh Raspberry Pi OS Bookworm install, libcamera-apps is
already installed. If not:
sudo apt update
sudo apt install -y libcamera-apps python3-picamera2
Verify:
libcamera-hello
You should see a preview window for 5 seconds (on a desktop install) or a confirmation message (on a Lite install).
The camera interface is enabled by default on recent Raspberry Pi OS. If
libcamera-hellosays “no cameras found,” enable the interface withsudo raspi-config>>Interface Options>>Camera>>Yes, then reboot.
Wiring: the ribbon cable
The Camera Module has a ribbon cable that plugs into the CSI port on the Pi. The port is between the HDMI ports and the GPIO header on a Pi 4, and near the GPIO header on a Pi 5.
The cable is fragile. The two things that go wrong:
- The cable is upside down. The blue side of the cable should face the Ethernet ports (Pi 4) or the board (Pi 5). If it is facing the other way, the camera is not detected.
- The cable is not fully inserted. The connector is a friction lock. Push the cable in until the lock clicks. If you have to force it, the cable is in the wrong orientation.
The “no camera detected” error is almost always one of those two things. Verify with:
libcamera-hello --list-cameras
If the camera is detected, the output shows the sensor model and capabilities.
Still capture
libcamera-still -o image.jpg
This captures a single still image. Default resolution is the camera’s maximum (12 MP for v3, 8 MP for v2). The image saves to the specified file.
Useful flags:
-o image.jpgoutput file--width 1920 --height 1080specific resolution--rotation 180rotate (mounting orientation)--quality 90JPEG quality (0-100)--awb autoauto white balance--exposure sportexposure mode (long, normal, short, sport)
For timelapse:
libcamera-still -o frame_%04d.jpg --timelapse 5000 --timeout 60000
Captures one frame every 5 seconds for 60 seconds.
Video capture
libcamera-vid -o video.h264
This captures 1080p30 video in H.264 format. H.264 is the right format if you are going to play it back or upload it; the file size is reasonable.
Useful flags:
-o video.h264output file--width 1920 --height 1080resolution--framerate 30frames per second--bitrate 80000008 Mbps (default 17 Mbps for 1080p)--timeout 10000stop after 10 seconds
To convert H.264 to MP4 (most players want the container):
ffmpeg -i video.h264 -c copy video.mp4
The Picamera2 Python library
picamera2 is the Python library that replaces the old picamera.
The old library does not work on Bookworm and the new Pi models. The
new library does.
from picamera2 import Picamera2
picam2 = Picamera2()
config = picam2.create_still_configuration()
picam2.configure(config)
picam2.start()
# Let auto-exposure settle
import time
time.sleep(2)
picam2.capture_file("image.jpg")
The time.sleep(2) is the part most people skip. The camera’s
auto-exposure needs a couple of seconds to settle. Without it, the
first frame is under- or over-exposed.
For a preview loop:
import time
from picamera2 import Picamera2
picam2 = Picamera2()
config = picam2.create_preview_configuration()
picam2.configure(config)
picam2.start()
while True:
frame = picam2.capture_array()
# frame is a numpy array, shape (height, width, 3)
# process or display it
time.sleep(0.1)
The capture_array method returns the image as a numpy array. This
is the right method if you are doing image processing (OpenCV,
Pillow, scikit-image).
The autofocus trick (v3 only)
The Camera Module v3 has autofocus. The v2 has a fixed focus lens. The v3’s autofocus is controlled from Picamera2:
from picamera2 import Picamera2
import time
picam2 = Picamera2()
config = picam2.create_still_configuration()
picam2.configure(config)
picam2.start()
# Continuous autofocus
picam2.set_controls({"AfMode": 2}) # 2 = continuous, 1 = manual, 0 = off
time.sleep(5) # let it focus
picam2.capture_file("focused.jpg")
The autofocus is slow (about 1-2 seconds to lock). For a project that needs fast capture, set the focus manually:
# Manual focus at a specific lens position (0.0 = far, 10.0 = close)
picam2.set_controls({"AfMode": 0, "LensPosition": 5.0})
The v3 also has a wider field of view than the v2 (about 66 degrees horizontal vs 62), and it supports HDR. For most projects, the autofocus alone is the reason to pick the v3.
Exposure modes and AWB
The camera has two auto-adjustment systems running in parallel:
- Exposure (the brightness of the image). The camera picks a shutter speed and ISO to make the image well-exposed.
- AWB (auto white balance). The camera picks color gains so that white things look white under the current lighting.
Both are “auto” by default. You can override:
picam2.set_controls({
"ExposureTime": 10000, # 10 ms in microseconds
"AnalogueGain": 1.0, # ISO 100 equivalent
"ColourGains": (1.5, 1.2), # red gain, blue gain
})
The values are tricky to pick by hand. The rule: leave the camera in auto mode, override only if the auto is consistently wrong (a window scene with a bright sky, a lab with fluorescent lights, etc.).
Streaming over RTSP
For “show the camera feed to multiple viewers,” RTSP is the standard
protocol. There is a libcamera-vid mode for it:
libcamera-vid -t 0 --inline -o - | cvlc stream:///dev/stdin --sout '#rtp{sdp=rtsp://:8554/stream}' :demux=h264
This is more involved than I want to put in a beginner tutorial. The
short version: VLC, GStreamer, or mediaMTX (formerly rtsp-simple- server) can all take the H.264 stream from libcamera-vid and
expose it as RTSP. The viewers use VLC or a web player.
For a simpler “view the camera in a browser,” use rpicam-vid (the
newer name for libcamera-vid) with the --inline and HTTP serving.
Or skip the streaming and just push JPEGs to a web server with a
Python script.
ESP32-CAM vs Pi Camera
The ESP32-CAM is a $10 board with an OV2640 camera. It runs over Wi-Fi, draws very little power, and is the right pick for a battery- powered, always-on camera.
The Pi Camera wins on:
- Image quality. The v3 is 12 MP, the OV2640 is 2 MP.
- Autofocus. The v3 has it, the OV2640 does not.
- Processing. The Pi can do real-time image processing (face detection, object recognition). The ESP32-CAM struggles.
- Flexibility. The Pi runs full Linux, you can install any library.
The ESP32-CAM wins on:
- Cost. About $10 vs $35 for the camera, plus the Pi.
- Power. 200 mA vs 600-1000 mA for a Pi.
- Integration. The ESP32-CAM has the camera on the same board as the microcontroller.
Rule of thumb: if the camera is the main thing and the project runs on battery, ESP32-CAM. If the camera is one of several things and the Pi is already there, Pi Camera.
What you learned
- The modern camera stack on the Pi is
libcamera(CLI tools) andpicamera2(Python). - The Camera Module v3 has autofocus; the v2 has a fixed-focus lens.
libcamera-stillfor photos,libcamera-vidfor video,picamera2for Python.- The “no camera detected” error is almost always a ribbon cable orientation problem.
When something breaks
libcamera-hello says “no cameras available”. The ribbon cable is
upside down or not fully inserted. Power off, reseat the cable.
The preview is green or pink. The cable is not fully inserted or the cable is damaged. Try a different cable.
The autofocus hunts forever. The lens is too close to the subject
or the lighting is too low. Use manual focus with LensPosition.
ModuleNotFoundError: No module named 'picamera2'. The package is
not installed. Run sudo apt install -y python3-picamera2.
The image is upside down. The camera is mounted upside down. Add
picam2.set_controls({"Rotation": 180}) or use the
--rotation 180 flag on the CLI tools.
The Python script crashes after a few minutes. The camera is
running out of resources. Add picam2.close() at the end of the
script, or use a context manager:
with Picamera2() as picam2:
picam2.start()
picam2.capture_file("image.jpg")
What to build next
- A wildlife camera with motion detection.
- A time-lapse rig for a plant growing.
- A security camera with RTSP streaming.
- A doorbell camera that sends a snapshot to your phone when pressed.
The time-lapse rig is the easiest first project. The RTSP security camera is the most useful.