Skip to content

Commit 73aafb2

Browse files
authored
Add Camera peripheral (#11)
1 parent 20cef0c commit 73aafb2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+5810
-355
lines changed

.github/workflows/calculate-size-delta.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55

66
permissions:
77
contents: read
8+
pull-requests: read
89

910
jobs:
1011
build:

containers/ei-models-runner/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# SPDX-License-Identifier: MPL-2.0
44

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

77
# Create the user and group needed to run the container as non-root
88
RUN set -ex; \

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ dev = [
3131
"setuptools",
3232
"build",
3333
"pytest",
34+
"pytest-asyncio",
3435
"websocket-client",
3536
"ruff",
3637
"docstring_parser>=0.16",

src/arduino/app_bricks/camera_code_detection/README.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ This Brick enables real-time barcode and QR code scanning from a camera video st
66

77
The Camera Code Detection Brick allows you to:
88

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

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

2323
## Prerequisites
2424

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

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

@@ -37,9 +37,25 @@ def render_frame(frame):
3737
def handle_detected_code(frame, detection):
3838
...
3939

40-
# Select the camera you want to use, its resolution and the max fps
41-
detection = CameraCodeDetection(camera=0, resolution=(640, 360), fps=10)
40+
detection = CameraCodeDetection()
4241
detection.on_frame(render_frame)
4342
detection.on_detection(handle_detected_code)
44-
detection.start()
43+
44+
App.run()
4545
```
46+
47+
You can also select a specific camera to use:
48+
49+
```python
50+
from arduino.app_bricks.camera_code_detection import CameraCodeDetection
51+
52+
def handle_detected_code(frame, detection):
53+
...
54+
55+
# Select the camera you want to use, its resolution and the max fps
56+
camera = Camera(camera="rtsp://...", resolution=(640, 360), fps=10)
57+
detection = CameraCodeDetection(camera)
58+
detection.on_detection(handle_detected_code)
59+
60+
App.run()
61+
```

src/arduino/app_bricks/camera_code_detection/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#
33
# SPDX-License-Identifier: MPL-2.0
44

5-
from .detection import Detection, CameraCodeDetection
6-
from .utils import draw_bounding_boxes, draw_bounding_box
5+
from .detection import CameraCodeDetection, Detection
76

8-
__all__ = ["CameraCodeDetection", "Detection", "draw_bounding_boxes", "draw_bounding_box"]
7+
__all__ = ["CameraCodeDetection", "Detection"]

src/arduino/app_bricks/camera_code_detection/detection.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
import threading
77
from typing import Callable
88

9-
import cv2
109
from pyzbar.pyzbar import decode, ZBarSymbol, PyZbarError
1110
import numpy as np
12-
from PIL.Image import Image
11+
from PIL.Image import Image, fromarray
1312

14-
from arduino.app_peripherals.usb_camera import USBCamera
13+
from arduino.app_peripherals.camera import Camera, BaseCamera
14+
from arduino.app_utils.image import greyscale
1515
from arduino.app_utils import brick, Logger
1616

1717
logger = Logger("CameraCodeDetection")
@@ -44,7 +44,7 @@ class CameraCodeDetection:
4444
"""Scans a camera video feed for QR codes and/or barcodes.
4545
4646
Args:
47-
camera (USBCamera): The USB camera instance. If None, a default camera will be initialized.
47+
camera (BaseCamera): The camera instance to use for capturing video. If None, a default camera will be initialized.
4848
detect_qr (bool): Whether to detect QR codes. Defaults to True.
4949
detect_barcode (bool): Whether to detect barcodes. Defaults to True.
5050
@@ -55,18 +55,20 @@ class CameraCodeDetection:
5555

5656
def __init__(
5757
self,
58-
camera: USBCamera = None,
58+
camera: BaseCamera = None,
5959
detect_qr: bool = True,
6060
detect_barcode: bool = True,
6161
):
6262
"""Initialize the CameraCodeDetection brick."""
6363
if detect_qr is False and detect_barcode is False:
6464
raise ValueError("At least one of 'detect_qr' or 'detect_barcode' must be True.")
6565

66+
self._camera = camera if camera else Camera()
67+
6668
self._detect_qr = detect_qr
6769
self._detect_barcode = detect_barcode
6870

69-
# These callbacks do not require locks as long as we're running on CPython
71+
# These callbacks don't require locking as long as we're running on CPython
7072
self._on_frame_cb = None
7173
self._on_error_cb = None
7274

@@ -76,8 +78,6 @@ def __init__(
7678

7779
self.already_seen_codes = set()
7880

79-
self._camera = camera if camera else USBCamera()
80-
8181
def start(self):
8282
"""Start the detector and begin scanning for codes."""
8383
self._camera.start()
@@ -154,13 +154,13 @@ def loop(self):
154154
self._on_error(e)
155155
return
156156

157-
# Use grayscale for barcode/QR code detection
158-
gs_frame = cv2.cvtColor(np.asarray(frame), cv2.COLOR_RGB2GRAY)
159-
160-
self._on_frame(frame)
157+
pil_frame = fromarray(frame)
158+
self._on_frame(pil_frame)
161159

160+
# Use grayscale for barcode/QR code detection
161+
gs_frame = greyscale(frame)
162162
detections = self._scan_frame(gs_frame)
163-
self._on_detect(frame, detections)
163+
self._on_detect(pil_frame, detections)
164164

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

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

src/arduino/app_bricks/camera_code_detection/examples/2_detection_list.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ def on_codes_detected(frame: Image, detections: list[Detection]):
1919
detector = CameraCodeDetection()
2020
detector.on_detect(on_codes_detected)
2121

22-
App.run() # This will block until the app is stopped
22+
App.run()

src/arduino/app_bricks/camera_code_detection/examples/3_detection_with_overrides.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# EXAMPLE_REQUIRES = "Requires an USB webcam connected to the Arduino board."
77
from PIL.Image import Image
88
from arduino.app_utils.app import App
9-
from arduino.app_peripherals.usb_camera import USBCamera
9+
from arduino.app_peripherals.usb_camera import Camera
1010
from arduino.app_bricks.camera_code_detection import CameraCodeDetection, Detection
1111

1212

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

1919

20-
camera = USBCamera(camera=0, resolution=(640, 360), fps=10)
20+
camera = Camera(camera=2, resolution=(640, 360), fps=10)
2121
detector = CameraCodeDetection(camera)
2222
detector.on_detect(on_code_detected)
2323

src/arduino/app_bricks/object_detection/README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,24 @@ The Object Detection Brick allows you to:
2323
```python
2424
import os
2525
from arduino.app_bricks.object_detection import ObjectDetection
26+
from arduino.app_utils.image import draw_bounding_boxes
2627

2728
object_detection = ObjectDetection()
2829

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

32-
out = object_detection.detect(frame)
33-
# is it possible to customize image type, confidence level and box overlap
34-
# out = object_detection.detect(frame, image_type = "png", confidence = 0.35, overlap = 0.5)
33+
out = object_detection.detect(img)
34+
# You can also provide a confidence level
35+
# out = object_detection.detect(frame, confidence = 0.35)
3536
if out and "detection" in out:
3637
for i, obj_det in enumerate(out["detection"]):
37-
# For every object detected, get its details
38+
# For every object detected, print its details
3839
detected_object = obj_det.get("class_name", None)
39-
bounding_box = obj_det.get("bounding_box_xyxy", None)
4040
confidence = obj_det.get("confidence", None)
41+
bounding_box = obj_det.get("bounding_box_xyxy", None)
4142

42-
# draw the bounding box and key points on the image
43-
out_image = object_detection.draw_bounding_boxes(frame, out)
43+
# Draw the bounding boxes
44+
out_image = draw_bounding_boxes(img, out)
4445
```
4546

src/arduino/app_bricks/object_detection/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from typing import Any
55

66
from PIL import Image
7-
from arduino.app_utils import brick, Logger, draw_bounding_boxes, Shape
7+
from arduino.app_utils import brick, Logger
8+
from arduino.app_utils.image import draw_bounding_boxes, Shape
89
from arduino.app_internal.core import EdgeImpulseRunnerFacade
910

1011
logger = Logger("ObjectDetection")

0 commit comments

Comments
 (0)