Loading repository data…
Loading repository data…
ZkMV / repository
A wrapper library between libcamera and C++/Python applications, providing near real-time RPi camera status monitoring via GPIO.
High-performance RAW camera capture library for Raspberry Pi
SpiderCamera is a C++ wrapper around libcamera designed for high-speed RAW frame capture with Python bindings via pybind11. It targets Raspberry Pi boards and provides in-memory burst capture with planned support for hot parameter updates and GPIO triggers.
get_burst_frames().get_last_series_fps() (eliminates Python timing jitter).libcamera-devlibgpiod-dev (for v0.4+)pybind11opencv-python-headless (for processing/saving frames in Python)SpiderCamera/ ├── include/ │ └── spider_camera.hpp # C++ API interface ├── src/ │ ├── spider_camera.cpp # Core implementation │ ├── pisp_decompress.cpp # (DEPRECATED: Old v0.2 RAW logic) │ └── frame_buffer.cpp # (DEPRECATED: Old v0.2 RAW logic) ├── bindings/ │ └── pybind_spider.cpp # Python bindings (pybind11) ├── examples/ │ ├── demo_python.py # Test script for v0.3 (YUV Burst) │ └── demo_config.json # v0.3 config file (ISO, Exp, Res, Focus) ├── build.sh # Build script └── Specification.md # Technical specification
# Clone repository
git clone https://github.com/YOUR_USERNAME/SpiderCamera.git
cd SpiderCamera
# Setup virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Install dependencies
pip install pybind11 numpy opencv-python-headless
# Build
chmod +x build.sh
./build.sh
# Test
python3 examples/demo_python.py
Starting from v0.6, the library performs a raw memory copy to prevent segmentation faults on Raspberry Pi 5 (due to ISP alignment/padding). The byte arrays returned by get_burst_frames() contain padding bytes at the end of every row.
Correct way to process frames:
# 1. Get properties including Stride
width, height, fmt, stride = cam.get_frame_properties()
# 2. Calculate dimensions
# For YUV420/NV12, physical height in memory is 1.5x the image height
yuv_height = int(height * 1.5)
for flat_frame in frames:
# A. Determine how many stride-aligned rows are in the buffer
rows = flat_frame.size // stride
# B. Reshape using Stride (NOT width)
# This aligns the data correctly in 2D space
view_2d = flat_frame[:rows*stride].reshape((rows, stride))
# C. Crop the valid data
# Remove padding on the right (:width) and extra rows at bottom (:yuv_height)
image_data = view_2d[:yuv_height, :width]
# D. Ensure memory is contiguous for OpenCV
import numpy as np
image_contiguous = np.ascontiguousarray(image_data)
# E. Convert
bgr = cv2.cvtColor(image_contiguous, cv2.COLOR_YUV2BGR_I420)
The primary goal of this library is to enable advanced surface analysis by combining high-speed burst capture with synchronized lighting.
The intended pipeline consists of two stages:
Capture Stage (Real-time, ~1 sec):
YUV 3840x2400 frames while in motion.Processing Stage (Offline, ~5-10 sec):
~7680x4800).set_cam(id) — select camera by index.
get_cam() — get current camera ID.
be_ready() — prepare camera (state transition: 0 → 1).
stop() — stop and release camera (state transition: * → 0).
get_state() — get current state:
0 — off1 — ready2 — streaming4 — errorgo() — start YUV frame capture (state: 1 → 2).pause() — pause streaming, keep camera configured (state: 2 → 1).get_burst_frames() -> list[np.ndarray] — return all buffered frames as a list of flat NumPy arrays (includes hardware padding/stride).get_frame_properties() -> tuple — (UPDATED in v0.6) returns metadata required to reconstruction the image:
(width, height, format, stride)stride (int): The actual number of bytes per row in memory (including hardware padding). Critical for reshaping.get_last_series_fps() -> float — (NEW in v0.7) Returns the precise average FPS of the last capture burst, calculated using C++ hardware timestamps (excludes warmup frames).Implementation: These setters store values which are applied during be_ready() and go().
set_iso(iso: int) — Sets target ISO (e.g., 4000). C++ calculates AnalogueGain.set_exposure(us: int) — Sets shutter time in microseconds (e.g., 100).set_resolution(w: int, h: int) — Sets target resolution (e.g., 3840, 2400).set_focus(value: float) — Sets manual focus value (e.g., 0.0 for infinity).Status: ✅ Complete and tested
Features:
set_frame_trigger_pin(pin: int): Configures the BCM GPIO pin for output (e.g., pin 21 on gpiochip4 for RPi 5).enable_frame_trigger(enabled: bool): Enables/disables the trigger logic.handle_request_complete (end of frame N exposure).handle_request_complete (immediately before queuing frame N+1).gpiod.h) for libgpiod to ensure compatibility and avoid "undefined symbol" linking errors.SpiderCamera/
├── include/
│ └── spider_camera.hpp # C++ API interface
├── src/
│ ├── spider_camera.cpp # Core implementation
│ ├── pisp_decompress.cpp # (DEPRECATED: Old v0.2 RAW logic)
│ └── frame_buffer.cpp # (DEPRECATED: Old v0.2 RAW logic)
├── bindings/
│ └── pybind_spider.cpp # Python bindings (pybind11)
├── examples/
│ ├── demo_python.py # CLI Burst Capture (Headless)
│ ├── demo_python_preview.py # Headless Preview (saves to temp/spider_preview.jpg)
│ ├── spider_preview_gui.py # GUI Control (PyQt5) with real-time preview
│ └── demo_config.json # Shared configuration file
├── build.sh # Build script
└── Specification.md # Technical specification
The library includes three Python scripts to verify functionality and performance:
demo_python.py (Burst Benchmark)
temp/.python3 examples/demo_python.pydemo_python_preview.py (Headless Preview)
temp/spider_preview.jpg). Useful for checking focus/framing via a file browser or web server.python3 examples/demo_python_preview.pyspider_preview_gui.py (GUI Control Panel)
demo_config.json.python3 examples/spider_preview_gui.pypython3-pyqt5Status: ✅ Complete and tested
Features:
set_cam().Status: ✅ Complete and tested
Features:
go() / pause() methods for streaming control.get_burst_frames() — C++-side decompression and delivery of all buffered frames to Python as a list of NumPy arrays.-bufferCount 8) to prevent pipeline stalls.Status: ✅ Complete and tested
Features:
set_iso, set_exposure, set_focus, set_resolution.go() to use these variables instead of hard-coded values.AeEnable=false with full AnalogueGain (e.g., 40.0) and DigitalGain=1.0, successfully "exorcising" the auto-exposure "poltergeist".100us (verified with/without external light).Status: ✅ Complete and tested
Features:
Status: ✅ Complete and tested
Features:
Status: ✅ Complete and tested
Features:
memcpy of the entire buffer (including padding) instead of attempting to strip it row-by-row. This significantly improves stability.get_frame_properties() now returns a 4-tuple: (width, height, format, stride).demo_python.py, demo_python_preview.py, spider_preview_gui.py) updated to implement Stride-aware reshaping and cropping.Status: ✅ Complete and tested
Features:
std::chrono::steady_clock).