Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
c5fb4cf
feat: add new Camera factory
robgee86 Oct 16, 2025
858f4ef
refactor: IPCamera
robgee86 Oct 20, 2025
1f3b6d8
refactor: streamer example
robgee86 Oct 20, 2025
ba69905
perf
robgee86 Oct 20, 2025
2db4f72
refactor: BaseCamera
robgee86 Oct 21, 2025
2599a80
refactor
robgee86 Oct 21, 2025
7776505
refactor: image manipulation
robgee86 Oct 24, 2025
60c951b
fix: pipelining
robgee86 Oct 27, 2025
1b1f99c
refactor: remove adjust/adjusted functions
robgee86 Oct 27, 2025
5b757b4
feat: better support BGR, BGRA and uint8, uint16, uint32
robgee86 Oct 28, 2025
c2db6c8
refactor: deprecate USBCamera in favor of Camera and make it compatible
robgee86 Oct 29, 2025
010dee0
doc: update docstrings
robgee86 Oct 29, 2025
c87c94c
tidy-up
robgee86 Oct 29, 2025
fc9fb8f
refactor: clearer APIs and doc
robgee86 Oct 29, 2025
91a833b
add examples
robgee86 Oct 29, 2025
0ccf633
refactor: directly use V4LCamera
robgee86 Oct 29, 2025
14d4b25
remove test examples
robgee86 Oct 29, 2025
ab9949e
fix: race condition
robgee86 Oct 29, 2025
f2b6adb
doc: update readme
robgee86 Oct 29, 2025
1e37c02
refactor
robgee86 Oct 29, 2025
3fbb184
doc: explain adjustments argument
robgee86 Oct 29, 2025
de31fc6
run fmt
robgee86 Oct 30, 2025
3342bf1
run linter
robgee86 Oct 30, 2025
a20e228
fix: wrong import
robgee86 Oct 30, 2025
b76043b
perf
robgee86 Oct 30, 2025
9c03e5a
fix: numeric issue
robgee86 Oct 30, 2025
c51605a
refactor: change default image serialization format
robgee86 Oct 30, 2025
6ce8351
perf: reduce buffer size to lower latency
robgee86 Oct 30, 2025
2c184f4
doc: better clarify supported image formats
robgee86 Oct 31, 2025
c715cc0
feat: allow also image formats with higher bit depth and preserve all…
robgee86 Oct 31, 2025
24840a3
chore: run fmt
robgee86 Oct 31, 2025
c478315
refactor: Camera args
robgee86 Oct 31, 2025
a8d86a9
perf: make resize a no-op if frame has already target size
robgee86 Nov 3, 2025
da12623
refactor
robgee86 Nov 4, 2025
7273712
feat: update EI container to add TCP streaming mode
robgee86 Nov 4, 2025
d1674d9
refactor: migrate camera_code_detection
robgee86 Nov 4, 2025
abc1bc1
refactor: migrate vide_objectdetection
robgee86 Nov 4, 2025
339f32c
refactor: migrate video_objectdetection
robgee86 Nov 4, 2025
fc8381f
refactor
robgee86 Nov 6, 2025
9ac1651
fix
robgee86 Nov 10, 2025
4c49698
refactors
robgee86 Nov 13, 2025
2b6de9b
add tests dependency
robgee86 Nov 13, 2025
c16f778
test: add tests for camera module
robgee86 Nov 13, 2025
963f5a9
fixes
robgee86 Nov 13, 2025
b651b66
fix: API
robgee86 Nov 13, 2025
6e2477a
fix: linting
robgee86 Nov 13, 2025
32eeb73
chore: bump EI base image version
robgee86 Nov 13, 2025
cc24921
fix: missing job permissions
robgee86 Nov 13, 2025
35d6133
fix: port must be an int
robgee86 Nov 13, 2025
6a1aeb4
feat: add automatic reconnection
robgee86 Nov 14, 2025
d4cf0bb
feat: resolve device to stable links for more reliable reconnections
robgee86 Nov 15, 2025
4cb6724
refactor
robgee86 Nov 15, 2025
aafefec
fix: test race condition
robgee86 Nov 15, 2025
dd9645e
return exception when capturing if camera has not been started
robgee86 Nov 15, 2025
d4804e3
refactor
robgee86 Nov 15, 2025
1289ea6
refactor
robgee86 Nov 15, 2025
e87597e
fix tests
robgee86 Nov 15, 2025
5815750
fix: split frame capture and forwarding
robgee86 Nov 16, 2025
230a468
Revert "fix: split frame capture and forwarding"
robgee86 Nov 16, 2025
1371be2
fix: race condition
robgee86 Nov 16, 2025
a4e6de1
refactor
robgee86 Nov 16, 2025
f83dbfe
feat: allow to subscribe to camera lifecycle events
robgee86 Nov 18, 2025
9694aac
feat: add support for 'paused' and 'resumed' events
robgee86 Nov 18, 2025
c3f2276
refactor
robgee86 Nov 18, 2025
60778ce
fix: linting
robgee86 Nov 18, 2025
9ee0a38
feat: implement a (simple) state machine for state management
robgee86 Nov 18, 2025
f360c84
fix
robgee86 Nov 18, 2025
a7218c5
refactor: remove host from WebSocketCamera
robgee86 Nov 18, 2025
3e45fe0
refactor: rename address -> url
robgee86 Nov 18, 2025
dc5aaf0
validate frame_format
robgee86 Nov 18, 2025
37f91b0
fix signature
robgee86 Nov 19, 2025
bb29a02
feat: add recording to camera
robgee86 Nov 20, 2025
e795bc7
fix: fmt
robgee86 Nov 20, 2025
9879fab
feat: add support to authentication and encryption
robgee86 Nov 22, 2025
d0d3ef1
chore: update EI container version
robgee86 Nov 22, 2025
1da1869
feat: add utilities for flipping images
robgee86 Nov 23, 2025
bb8afc9
feat: change protocol implementation
robgee86 Nov 26, 2025
771bf8e
fix: prime the EI pipeline at startup
robgee86 Nov 26, 2025
38f9e0c
refactor: better error logging
robgee86 Nov 26, 2025
71d1404
fix: linting
robgee86 Nov 26, 2025
cdaf342
chore: update license header
robgee86 Nov 26, 2025
452ccb3
fix: imports
robgee86 Nov 26, 2025
a814004
refactor: align websocket camera with other peripheral implementations
robgee86 Nov 27, 2025
13f3362
feat: add TLS support
robgee86 Nov 29, 2025
4e1c23d
refactor: better error reporting
robgee86 Dec 1, 2025
c35b47b
fix: fmt
robgee86 Dec 1, 2025
24bb5ff
refactor
robgee86 Dec 15, 2025
ed2f931
chore: bump EI base container version
robgee86 Dec 15, 2025
ffe6f7c
tidy-up
robgee86 Dec 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/calculate-size-delta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:

permissions:
contents: read
pull-requests: read

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion containers/ei-models-runner/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: MPL-2.0

FROM public.ecr.aws/z9b3d4t5/inference-container-qc-adreno-702:4d7979284677b6bdb557abe8948fa1395dc89a63
FROM public.ecr.aws/z9b3d4t5/inference-container-qc-adreno-702:74a13c376947193d0426257cd5659e449749052a

# Create the user and group needed to run the container as non-root
RUN set -ex; \
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dev = [
"setuptools",
"build",
"pytest",
"pytest-asyncio",
"websocket-client",
"ruff",
"docstring_parser>=0.16",
Expand Down
28 changes: 22 additions & 6 deletions src/arduino/app_bricks/camera_code_detection/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ This Brick enables real-time barcode and QR code scanning from a camera video st

The Camera Code Detection Brick allows you to:

- Capture frames from a USB camera.
- Configure camera settings (resolution and frame rate).
- Capture frames from a Camera (see Camera peripheral for supported cameras).
- Configure Camera settings (resolution and frame rate).
- Define the type of code to detect: barcodes and/or QR codes.
- Process detections with customizable callbacks.

Expand All @@ -22,7 +22,7 @@ The Camera Code Detection Brick allows you to:

## Prerequisites

To use this Brick you should have a USB camera connected to your board.
To use this Brick you can choose to plug a camera to your board or use a network-connected camera.

**Tip**: Use a USB-C® Hub with USB-A connectors to support commercial web cameras.

Expand All @@ -37,9 +37,25 @@ def render_frame(frame):
def handle_detected_code(frame, detection):
...

# Select the camera you want to use, its resolution and the max fps
detection = CameraCodeDetection(camera=0, resolution=(640, 360), fps=10)
detection = CameraCodeDetection()
detection.on_frame(render_frame)
detection.on_detection(handle_detected_code)
detection.start()

App.run()
```

You can also select a specific camera to use:

```python
from arduino.app_bricks.camera_code_detection import CameraCodeDetection

def handle_detected_code(frame, detection):
...

# Select the camera you want to use, its resolution and the max fps
camera = Camera(camera="rtsp://...", resolution=(640, 360), fps=10)
detection = CameraCodeDetection(camera)
detection.on_detection(handle_detected_code)

App.run()
```
5 changes: 2 additions & 3 deletions src/arduino/app_bricks/camera_code_detection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#
# SPDX-License-Identifier: MPL-2.0

from .detection import Detection, CameraCodeDetection
from .utils import draw_bounding_boxes, draw_bounding_box
from .detection import CameraCodeDetection, Detection

__all__ = ["CameraCodeDetection", "Detection", "draw_bounding_boxes", "draw_bounding_box"]
__all__ = ["CameraCodeDetection", "Detection"]
28 changes: 14 additions & 14 deletions src/arduino/app_bricks/camera_code_detection/detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import threading
from typing import Callable

import cv2
from pyzbar.pyzbar import decode, ZBarSymbol, PyZbarError
import numpy as np
from PIL.Image import Image
from PIL.Image import Image, fromarray

from arduino.app_peripherals.usb_camera import USBCamera
from arduino.app_peripherals.camera import Camera, BaseCamera
from arduino.app_utils.image import greyscale
from arduino.app_utils import brick, Logger

logger = Logger("CameraCodeDetection")
Expand Down Expand Up @@ -44,7 +44,7 @@ class CameraCodeDetection:
"""Scans a camera video feed for QR codes and/or barcodes.

Args:
camera (USBCamera): The USB camera instance. If None, a default camera will be initialized.
camera (BaseCamera): The camera instance to use for capturing video. If None, a default camera will be initialized.
detect_qr (bool): Whether to detect QR codes. Defaults to True.
detect_barcode (bool): Whether to detect barcodes. Defaults to True.

Expand All @@ -55,18 +55,20 @@ class CameraCodeDetection:

def __init__(
self,
camera: USBCamera = None,
camera: BaseCamera = None,
detect_qr: bool = True,
detect_barcode: bool = True,
):
"""Initialize the CameraCodeDetection brick."""
if detect_qr is False and detect_barcode is False:
raise ValueError("At least one of 'detect_qr' or 'detect_barcode' must be True.")

self._camera = camera if camera else Camera()

self._detect_qr = detect_qr
self._detect_barcode = detect_barcode

# These callbacks do not require locks as long as we're running on CPython
# These callbacks don't require locking as long as we're running on CPython
self._on_frame_cb = None
self._on_error_cb = None

Expand All @@ -76,8 +78,6 @@ def __init__(

self.already_seen_codes = set()

self._camera = camera if camera else USBCamera()

def start(self):
"""Start the detector and begin scanning for codes."""
self._camera.start()
Expand Down Expand Up @@ -154,13 +154,13 @@ def loop(self):
self._on_error(e)
return

# Use grayscale for barcode/QR code detection
gs_frame = cv2.cvtColor(np.asarray(frame), cv2.COLOR_RGB2GRAY)

self._on_frame(frame)
pil_frame = fromarray(frame)
self._on_frame(pil_frame)

# Use grayscale for barcode/QR code detection
gs_frame = greyscale(frame)
detections = self._scan_frame(gs_frame)
self._on_detect(frame, detections)
self._on_detect(pil_frame, detections)

def _on_frame(self, frame: Image):
if self._on_frame_cb:
Expand All @@ -170,7 +170,7 @@ def _on_frame(self, frame: Image):
logger.error(f"Failed to run on_frame callback: {e}")
self._on_error(e)

def _scan_frame(self, frame: cv2.typing.MatLike) -> list[Detection]:
def _scan_frame(self, frame: np.ndarray) -> list[Detection]:
"""Scan the frame for a single barcode or QR code."""
detections = []

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ def on_codes_detected(frame: Image, detections: list[Detection]):
detector = CameraCodeDetection()
detector.on_detect(on_codes_detected)

App.run() # This will block until the app is stopped
App.run()
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# EXAMPLE_REQUIRES = "Requires an USB webcam connected to the Arduino board."
from PIL.Image import Image
from arduino.app_utils.app import App
from arduino.app_peripherals.usb_camera import USBCamera
from arduino.app_peripherals.usb_camera import Camera
from arduino.app_bricks.camera_code_detection import CameraCodeDetection, Detection


Expand All @@ -17,7 +17,7 @@ def on_code_detected(frame: Image, detection: Detection):
# e.g., draw a bounding box, save it to a database or log it.


camera = USBCamera(camera=0, resolution=(640, 360), fps=10)
camera = Camera(camera=2, resolution=(640, 360), fps=10)
detector = CameraCodeDetection(camera)
detector.on_detect(on_code_detected)

Expand Down
19 changes: 10 additions & 9 deletions src/arduino/app_bricks/object_detection/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,24 @@ The Object Detection Brick allows you to:
```python
import os
from arduino.app_bricks.object_detection import ObjectDetection
from arduino.app_utils.image import draw_bounding_boxes

object_detection = ObjectDetection()

# Image frame can be as bytes or PIL image
frame = os.read("path/to/your/image.jpg")
# Image can be provided as bytes or PIL.Image
img = os.read("path/to/your/image.jpg")

out = object_detection.detect(frame)
# is it possible to customize image type, confidence level and box overlap
# out = object_detection.detect(frame, image_type = "png", confidence = 0.35, overlap = 0.5)
out = object_detection.detect(img)
# You can also provide a confidence level
# out = object_detection.detect(frame, confidence = 0.35)
if out and "detection" in out:
for i, obj_det in enumerate(out["detection"]):
# For every object detected, get its details
# For every object detected, print its details
detected_object = obj_det.get("class_name", None)
bounding_box = obj_det.get("bounding_box_xyxy", None)
confidence = obj_det.get("confidence", None)
bounding_box = obj_det.get("bounding_box_xyxy", None)

# draw the bounding box and key points on the image
out_image = object_detection.draw_bounding_boxes(frame, out)
# Draw the bounding boxes
out_image = draw_bounding_boxes(img, out)
```

3 changes: 2 additions & 1 deletion src/arduino/app_bricks/object_detection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from typing import Any

from PIL import Image
from arduino.app_utils import brick, Logger, draw_bounding_boxes, Shape
from arduino.app_utils import brick, Logger
from arduino.app_utils.image import draw_bounding_boxes, Shape
from arduino.app_internal.core import EdgeImpulseRunnerFacade

logger = Logger("ObjectDetection")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@
# SPDX-License-Identifier: MPL-2.0

# EXAMPLE_NAME = "Object Detection"
import os
from arduino.app_bricks.object_detection import ObjectDetection
from arduino.app_utils.image import draw_bounding_boxes

object_detection = ObjectDetection()

# Image frame can be as bytes or PIL image
with open("image.png", "rb") as f:
frame = f.read()
# Image can be provided as bytes or PIL.Image
img = os.read("path/to/your/image.jpg")

out = object_detection.detect(frame)
# is it possible to customize image type, confidence level and box overlap
# out = object_detection.detect(frame, image_type = "png", confidence = 0.35, overlap = 0.5)
out = object_detection.detect(img)
# You can also provide a confidence level
# out = object_detection.detect(frame, confidence = 0.35)
if out and "detection" in out:
for i, obj_det in enumerate(out["detection"]):
# For every object detected, get its details
# For every object detected, print its details
detected_object = obj_det.get("class_name", None)
bounding_box = obj_det.get("bounding_box_xyxy", None)
confidence = obj_det.get("confidence", None)
bounding_box = obj_det.get("bounding_box_xyxy", None)

# draw the bounding box and key points on the image
out_image = object_detection.draw_bounding_boxes(frame, out)
# Draw the bounding boxes
out_image = draw_bounding_boxes(img, out)
Loading