Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
53a459f
feat: add new Camera factory
robgee86 Oct 16, 2025
a259616
refactor: IPCamera
robgee86 Oct 20, 2025
f5d35b7
refactor: streamer example
robgee86 Oct 20, 2025
c1c9cb9
perf
robgee86 Oct 20, 2025
c578614
refactor: BaseCamera
robgee86 Oct 21, 2025
b3bf6c1
refactor
robgee86 Oct 21, 2025
20e21a3
refactor: image manipulation
robgee86 Oct 24, 2025
964ce99
fix: pipelining
robgee86 Oct 27, 2025
50d781a
refactor: remove adjust/adjusted functions
robgee86 Oct 27, 2025
5b2d154
feat: better support BGR, BGRA and uint8, uint16, uint32
robgee86 Oct 28, 2025
3c2961b
refactor: deprecate USBCamera in favor of Camera and make it compatible
robgee86 Oct 29, 2025
ba82d87
doc: update docstrings
robgee86 Oct 29, 2025
da354c8
tidy-up
robgee86 Oct 29, 2025
f4a9a53
refactor: clearer APIs and doc
robgee86 Oct 29, 2025
91f4219
add examples
robgee86 Oct 29, 2025
6805208
refactor: directly use V4LCamera
robgee86 Oct 29, 2025
902a644
remove test examples
robgee86 Oct 29, 2025
17e6878
fix: race condition
robgee86 Oct 29, 2025
0c0fdec
doc: update readme
robgee86 Oct 29, 2025
df27fbf
refactor
robgee86 Oct 29, 2025
4fff7cd
doc: explain adjustments argument
robgee86 Oct 29, 2025
a18fd89
run fmt
robgee86 Oct 30, 2025
bb4e814
run linter
robgee86 Oct 30, 2025
14a229a
fix: wrong import
robgee86 Oct 30, 2025
596c019
perf
robgee86 Oct 30, 2025
8979656
fix: numeric issue
robgee86 Oct 30, 2025
f6eead8
refactor: change default image serialization format
robgee86 Oct 30, 2025
28e3530
perf: reduce buffer size to lower latency
robgee86 Oct 30, 2025
f163f23
doc: better clarify supported image formats
robgee86 Oct 31, 2025
f20eaf1
feat: allow also image formats with higher bit depth and preserve all…
robgee86 Oct 31, 2025
4b61da7
chore: run fmt
robgee86 Oct 31, 2025
f49076f
refactor: Camera args
robgee86 Oct 31, 2025
f4f9249
perf: make resize a no-op if frame has already target size
robgee86 Nov 3, 2025
e0eb538
refactor
robgee86 Nov 4, 2025
dcccd8e
feat: update EI container to add TCP streaming mode
robgee86 Nov 4, 2025
af52307
refactor: migrate camera_code_detection
robgee86 Nov 4, 2025
a4f07a5
refactor: migrate vide_objectdetection
robgee86 Nov 4, 2025
2752a57
refactor: migrate video_objectdetection
robgee86 Nov 4, 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
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:39bcebb78de783cb602e1b361b71d6dafbc959b4

# Create the user and group needed to run the container as non-root
RUN set -ex; \
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"]
24 changes: 12 additions & 12 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
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 (Camera): 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,7 +55,7 @@ class CameraCodeDetection:

def __init__(
self,
camera: USBCamera = None,
camera: Camera = None,
detect_qr: bool = True,
detect_barcode: bool = True,
):
Expand All @@ -76,7 +76,7 @@ def __init__(

self.already_seen_codes = set()

self._camera = camera if camera else USBCamera()
self._camera = camera if camera else Camera()

def start(self):
"""Start the detector and begin scanning for codes."""
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)
```

16 changes: 1 addition & 15 deletions src/arduino/app_bricks/object_detection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
#
# SPDX-License-Identifier: MPL-2.0

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

logger = Logger("ObjectDetection")
Expand Down Expand Up @@ -54,19 +53,6 @@ def detect(self, image_bytes, image_type: str = "jpg", confidence: float = None)
ret = super().infer_from_image(image_bytes, image_type)
return self._extract_detection(ret, confidence)

def draw_bounding_boxes(self, image: Image.Image | bytes, detections: dict) -> Image.Image | None:
"""Draw bounding boxes on an image enclosing detected objects using PIL.

Args:
image: The input image to annotate. Can be a PIL Image object or raw image bytes.
detections: Detection results containing object labels and bounding boxes.

Returns:
Image with bounding boxes and key points drawn.
None if no detection or invalid image.
"""
return draw_bounding_boxes(image, detections)

def _extract_detection(self, item, confidence: float = None):
if not item:
return None
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