The libcamera-based Python interface to Raspberry Pi cameras, based on the original Picamera library
—
Advanced camera control system for setting exposure, gain, white balance, focus, and other camera parameters. The controls system provides both immediate parameter adjustment and thread-safe access for real-time applications.
Set camera controls individually or in groups with immediate effect.
def set_controls(self, controls: dict):
"""
Set multiple camera controls.
Parameters:
- controls: dict, control name to value mapping
Common controls include:
- ExposureTime: int, exposure time in microseconds
- AnalogueGain: float, analog gain multiplier
- DigitalGain: float, digital gain multiplier
- Brightness: float, brightness adjustment (-1.0 to 1.0)
- Contrast: float, contrast adjustment (0.0 to 10.0)
- Saturation: float, saturation adjustment (0.0 to 10.0)
- AwbEnable: bool, automatic white balance enable
- AwbMode: int, white balance mode
- AeEnable: bool, automatic exposure enable
- AeExposureMode: int, exposure mode
- AfMode: int, autofocus mode
- AfTrigger: int, autofocus trigger
Raises:
- RuntimeError: If control values are invalid or out of range
"""Thread-safe controls interface for real-time parameter adjustment.
class Controls:
"""Thread-safe camera controls interface."""
def __init__(self, picam2: Picamera2, controls: dict = None):
"""
Initialize Controls object.
Parameters:
- picam2: Picamera2 instance
- controls: dict, initial control values
"""
def set_controls(self, controls: dict):
"""
Update multiple controls from dictionary.
Parameters:
- controls: dict or Controls object with new values
"""
def __setattr__(self, name: str, value):
"""
Set individual control using attribute syntax.
Parameters:
- name: str, control name
- value: control value
Example:
controls.ExposureTime = 10000
controls.AnalogueGain = 2.0
"""
def __getattribute__(self, name: str):
"""
Get control value using attribute syntax.
Returns:
Current control value or raises AttributeError if not found
"""
def __enter__(self):
"""Context manager entry for thread-safe access."""
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""Context manager exit for thread-safe access."""
def get_libcamera_controls(self) -> dict:
"""
Convert to libcamera control format.
Returns:
dict: Controls in libcamera format
"""
def make_dict(self) -> dict:
"""
Convert to standard dictionary.
Returns:
dict: Control name to value mapping
"""Special control fields that provide convenient access to complex parameters.
# FrameRate virtual field
@property
def FrameRate(self) -> float:
"""
Frame rate in frames per second (virtual field).
Maps to FrameDurationLimits with automatic conversion.
Setting this adjusts both minimum and maximum frame durations.
"""
@FrameRate.setter
def FrameRate(self, fps: float):
"""Set frame rate, converting to FrameDurationLimits."""# Exposure time in microseconds
ExposureTime: int # Range typically 10-60000000 depending on sensor
# Automatic exposure enable
AeEnable: bool # True for auto, False for manual
# Exposure mode
AeExposureMode: int
# Common values:
# 0: Normal
# 1: Short
# 2: Long
# 3: Custom
# Exposure compensation
ExposureValue: float # Range typically -8.0 to 8.0 in EV units
# Metering mode
AeMeteringMode: int
# Common values:
# 0: Centre-weighted
# 1: Spot
# 2: Matrix# Analog gain multiplier
AnalogueGain: float # Range typically 1.0-16.0
# Digital gain multiplier
DigitalGain: float # Range typically 1.0-64.0
# Overall gain
Gain: float # Combined analog and digital gain# Automatic white balance enable
AwbEnable: bool
# White balance mode
AwbMode: int
# Common values:
# 0: Auto
# 1: Incandescent
# 2: Tungsten
# 3: Fluorescent
# 4: Indoor
# 5: Daylight
# 6: Cloudy
# Manual color gains (when AwbEnable=False)
ColourGains: tuple[float, float] # (red_gain, blue_gain)# Autofocus mode
AfMode: int
# Common values:
# 0: Manual
# 1: Auto
# 2: Continuous
# Autofocus trigger
AfTrigger: int
# Values:
# 0: Idle
# 1: Start
# 2: Cancel
# Manual focus position (when AfMode=0)
LensPosition: float # Range 0.0-10.0 typically# Brightness adjustment
Brightness: float # Range -1.0 to 1.0
# Contrast adjustment
Contrast: float # Range 0.0 to 10.0, 1.0 = normal
# Saturation adjustment
Saturation: float # Range 0.0 to 10.0, 1.0 = normal
# Sharpness adjustment
Sharpness: float # Range 0.0 to 10.0, 1.0 = normalfrom picamera2 import Picamera2
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration())
picam2.start()
# Set controls using dictionary
picam2.set_controls({
"ExposureTime": 20000, # 20ms exposure
"AnalogueGain": 2.0, # 2x gain
"AwbEnable": False, # Manual white balance
"ColourGains": (1.2, 1.8) # Red and blue gains
})
# Check available controls
print("Available controls:")
for control, info in picam2.camera_controls.items():
print(f" {control}: {info}")
picam2.close()from picamera2 import Picamera2, Controls
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration())
picam2.start()
# Create controls object
controls = Controls(picam2)
# Set controls using attribute syntax
controls.ExposureTime = 10000
controls.AnalogueGain = 1.5
controls.Brightness = 0.1
# Apply all changes
picam2.set_controls(controls)
# Or use context manager for thread safety
with controls:
controls.ExposureTime = 30000
controls.AnalogueGain = 3.0
# Changes applied automatically on exit
picam2.close()from picamera2 import Picamera2
import time
picam2 = Picamera2()
picam2.configure(picam2.create_still_configuration())
picam2.start()
# Disable automatic exposure
picam2.set_controls({
"AeEnable": False,
"ExposureTime": 5000, # 5ms
"AnalogueGain": 1.0
})
# Take bracket of exposures
exposures = [1000, 5000, 10000, 20000, 50000]
for i, exp_time in enumerate(exposures):
picam2.set_controls({"ExposureTime": exp_time})
time.sleep(0.1) # Allow settling
picam2.capture_file(f"exposure_{exp_time}us.jpg")
picam2.close()from picamera2 import Picamera2
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration())
picam2.start()
# Try different white balance modes
wb_modes = {
"auto": {"AwbEnable": True, "AwbMode": 0},
"daylight": {"AwbEnable": True, "AwbMode": 5},
"tungsten": {"AwbEnable": True, "AwbMode": 2},
"manual_warm": {"AwbEnable": False, "ColourGains": (1.5, 1.2)},
"manual_cool": {"AwbEnable": False, "ColourGains": (1.0, 2.0)}
}
for name, settings in wb_modes.items():
picam2.set_controls(settings)
time.sleep(1) # Allow white balance to settle
picam2.capture_file(f"wb_{name}.jpg")
picam2.close()from picamera2 import Picamera2
import time
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration())
picam2.start()
# Enable continuous autofocus
picam2.set_controls({
"AfMode": 2, # Continuous AF
"AfTrigger": 0 # Idle
})
# Wait for focus to settle
time.sleep(2)
# Trigger single autofocus
picam2.set_controls({"AfTrigger": 1}) # Start AF
time.sleep(1) # Wait for focus
picam2.capture_file("autofocus.jpg")
# Manual focus sweep
picam2.set_controls({"AfMode": 0}) # Manual focus
focus_positions = [0.5, 1.0, 2.0, 5.0, 10.0]
for pos in focus_positions:
picam2.set_controls({"LensPosition": pos})
time.sleep(0.5)
picam2.capture_file(f"focus_{pos:.1f}.jpg")
picam2.close()from picamera2 import Picamera2, Controls
import time
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration())
picam2.start()
controls = Controls(picam2)
# Slowly increase exposure
for exp in range(1000, 50000, 1000):
controls.ExposureTime = exp
picam2.set_controls(controls)
time.sleep(0.1)
# Could capture frame or analyze preview here
print(f"Exposure: {exp}us")
picam2.close()from picamera2 import Picamera2, Controls
picam2 = Picamera2()
config = picam2.create_video_configuration()
picam2.configure(config)
picam2.start()
controls = Controls(picam2)
# Set frame rate using virtual field
controls.FrameRate = 30.0 # 30 fps
picam2.set_controls(controls)
# Or set manually using frame duration
picam2.set_controls({
"FrameDurationLimits": (33333, 33333) # 30fps (33.33ms per frame)
})
picam2.close()Install with Tessl CLI
npx tessl i tessl/pypi-picamera2