Skip to main content

Camera

Continuously captures frames from a document camera in a background thread.

Constructor

Camera(
    device_index: int | None = None,
    frame_width: int | None = None,
    frame_height: int | None = None,
    rotation: str | None = None,
)
device_index
int | None
default:"None"
Camera device index. Uses config.camera_device_index if None
frame_width
int | None
default:"None"
Frame width in pixels. Uses config.camera_frame_width if None
frame_height
int | None
default:"None"
Frame height in pixels. Uses config.camera_frame_height if None
rotation
str | None
default:"None"
Rotation mode: “auto”, “none”, “90”, “180”, “270”. Uses config.camera_rotation if None
Location: camera.py:62-87

Methods

start()

Open the camera and begin background frame capture.
def start() -> None:
Raises RuntimeError if camera cannot be opened or device index is invalid. Location: camera.py:89-118

get_frame()

Return the most recent frame as a BGR numpy array, or None.
def get_frame() -> np.ndarray | None:
frame
np.ndarray | None
BGR image array (OpenCV format), or None if no frame captured yet
Location: camera.py:133-138

get_frame_rgb()

Return the most recent frame converted to RGB.
def get_frame_rgb() -> np.ndarray | None:
frame
np.ndarray | None
RGB image array, or None if no frame captured yet
Location: camera.py:140-145

capture_base64_jpeg()

Grab the current frame and return it as a base64-encoded JPEG string.
def capture_base64_jpeg(quality: int = 85) -> str | None:
quality
int
default:"85"
JPEG compression quality (0-100)
jpeg_base64
str | None
Base64-encoded JPEG string, or None if no frame available
Location: camera.py:147-153

capture_thumbnail_bytes()

Return a small JPEG thumbnail as raw bytes (for the chat feed).
def capture_thumbnail_bytes(max_width: int = 320) -> bytes | None:
max_width
int
default:"320"
Maximum width in pixels (height scaled proportionally)
jpeg_bytes
bytes | None
JPEG-encoded thumbnail bytes, or None if no frame available
Location: camera.py:155-165

stop()

Stop the capture thread and release the camera.
def stop() -> None:
Location: camera.py:167-175

Properties

is_running
bool
Whether the camera is actively capturing
device_index
int
Current camera device index
Location: camera.py:177-183

Utility Functions

enumerate_cameras()

Return available cameras as dicts for backward compatibility.
def enumerate_cameras(max_index: int = 10) -> list[dict]:
max_index
int
default:"10"
Maximum device index to probe
cameras
list[dict]
List of camera info dicts with keys: index, name, width, height
Location: camera.py:22-34 Delegates to device_catalog.list_camera_devices() and converts to dict format.

Camera Rotation

The Camera class supports automatic rotation for portrait-oriented document cameras:
  • "auto" (default): Detects portrait frames (height > width) and rotates 90° clockwise
  • "none": No rotation
  • "90", "180", "270": Fixed rotation angles
Rotation setting is resolved at camera startup (camera.py:46-56) and applied during frame capture (camera.py:126-127).

Platform Notes

  • Uses OpenCV (cv2.VideoCapture) with CAP_DSHOW backend on Windows, CAP_ANY elsewhere
  • Camera enumeration on macOS uses AVFoundation (via device_catalog) for friendly device names
  • Background capture thread runs as daemon
Location: camera.py:19

Build docs developers (and LLMs) love