Skip to content

Commit 2e85b52

Browse files
committed
ci(runner): Save image from camera
1 parent 46d3ca0 commit 2e85b52

File tree

5 files changed

+177
-82
lines changed

5 files changed

+177
-82
lines changed

.github/ci/runner_camera.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
import cv2
5+
6+
# This will return video from the first webcam on your computer.
7+
cap = cv2.VideoCapture(0)
8+
9+
# reads frames from a camera
10+
# ret checks return at each frame
11+
ret, frame = cap.read()
12+
if ret:
13+
# Save image
14+
image_path = "snapshot.jpg"
15+
cv2.imwrite(image_path, frame)
16+
print(f"Image saved {image_path}")
17+
else:
18+
print("Cannot save image.")
19+
20+
# Close the window / Release webcam
21+
cap.release()

.github/workflows/build-run-applications.yml

Lines changed: 82 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build ESP-BSP apps
1+
name: Build and Run ESP-BSP apps
22

33
# This job builds all examples and test_applications in this repo
44
# Applications are selected for build based on changes files and dependencies defined in .build-test-rules.yml
@@ -47,30 +47,30 @@ jobs:
4747
- idf_ver: "latest"
4848
parallel_count: 5
4949
parallel_index: 5
50-
- idf_ver: "release-v5.1"
51-
parallel_count: 2
52-
parallel_index: 1
53-
- idf_ver: "release-v5.1"
54-
parallel_count: 2
55-
parallel_index: 2
56-
- idf_ver: "release-v5.2"
57-
parallel_count: 2
58-
parallel_index: 1
59-
- idf_ver: "release-v5.2"
60-
parallel_count: 2
61-
parallel_index: 2
62-
- idf_ver: "release-v5.3"
63-
parallel_count: 2
64-
parallel_index: 1
65-
- idf_ver: "release-v5.3"
66-
parallel_count: 2
67-
parallel_index: 2
68-
- idf_ver: "release-v5.4"
69-
parallel_count: 2
70-
parallel_index: 1
71-
- idf_ver: "release-v5.4"
72-
parallel_count: 2
73-
parallel_index: 2
50+
#- idf_ver: "release-v5.1"
51+
# parallel_count: 2
52+
# parallel_index: 1
53+
#- idf_ver: "release-v5.1"
54+
# parallel_count: 2
55+
# parallel_index: 2
56+
#- idf_ver: "release-v5.2"
57+
# parallel_count: 2
58+
# parallel_index: 1
59+
#- idf_ver: "release-v5.2"
60+
# parallel_count: 2
61+
# parallel_index: 2
62+
#- idf_ver: "release-v5.3"
63+
# parallel_count: 2
64+
# parallel_index: 1
65+
#- idf_ver: "release-v5.3"
66+
# parallel_count: 2
67+
# parallel_index: 2
68+
#- idf_ver: "release-v5.4"
69+
# parallel_count: 2
70+
# parallel_index: 1
71+
#- idf_ver: "release-v5.4"
72+
# parallel_count: 2
73+
# parallel_index: 2
7474
runs-on: ubuntu-latest
7575
container: espressif/idf:${{ matrix.idf_ver }}
7676
steps:
@@ -124,60 +124,60 @@ jobs:
124124
- runs-on: "esp-box-3"
125125
marker: "esp_box_3"
126126
target: "esp32s3"
127-
- runs-on: "esp32_c3_lcdkit"
128-
marker: "esp32_c3_lcdkit"
129-
target: "esp32c3"
130-
- runs-on: "esp32_p4_box"
131-
marker: "esp32_p4_box"
132-
target: "esp32p4"
133-
- runs-on: "esp32_p4_function_ev_board"
134-
marker: "esp32_p4_function_ev_board"
135-
target: "esp32p4"
136-
- runs-on: "esp32_s3_eye"
137-
marker: "esp32_s3_eye"
138-
target: "esp32s3"
139-
- runs-on: "esp32_s3_lcd_ev_board"
140-
marker: "esp32_s3_lcd_ev_board"
141-
target: "esp32s3"
142-
- runs-on: "esp32_s3_lcd_ev_board"
143-
marker: "esp32_s3_lcd_ev_board_2"
144-
target: "esp32s3"
145-
- runs-on: "esp32_s3_usb_otg"
146-
marker: "esp32_s3_usb_otg"
147-
target: "esp32s3"
148-
- runs-on: "esp_wrover_kit"
149-
marker: "esp_wrover_kit"
150-
target: "esp32"
151-
- runs-on: "m5dial"
152-
marker: "m5dial"
153-
target: "esp32s3"
154-
- runs-on: "m5stack_core"
155-
marker: "m5stack_core"
156-
target: "esp32"
157-
- runs-on: "m5stack_core_2"
158-
marker: "m5stack_core_2"
159-
target: "esp32"
160-
- runs-on: "m5stack_core_s3"
161-
marker: "m5stack_core_s3"
162-
target: "esp32s3"
163-
- runs-on: "m5stack_core_s3"
164-
marker: "m5stack_core_s3_se"
165-
target: "esp32s3"
166-
- runs-on: "esp32_azure_iot_kit"
167-
marker: "esp32_azure_iot_kit"
168-
target: "esp32"
169-
- runs-on: "esp_bsp_devkit"
170-
marker: "esp_bsp_devkit"
171-
target: "esp32s3"
172-
- runs-on: "esp_bsp_generic"
173-
marker: "esp_bsp_generic"
174-
target: "esp32s3"
175-
- runs-on: "esp32_s3_korvo_2"
176-
marker: "esp32_s3_korvo_2"
177-
target: "esp32s3"
178-
- runs-on: "m5_atom_s3"
179-
marker: "m5_atom_s3"
180-
target: "esp32s3"
127+
#- runs-on: "esp32_c3_lcdkit"
128+
# marker: "esp32_c3_lcdkit"
129+
# target: "esp32c3"
130+
#- runs-on: "esp32_p4_box"
131+
# marker: "esp32_p4_box"
132+
# target: "esp32p4"
133+
#- runs-on: "esp32_p4_function_ev_board"
134+
# marker: "esp32_p4_function_ev_board"
135+
# target: "esp32p4"
136+
#- runs-on: "esp32_s3_eye"
137+
# marker: "esp32_s3_eye"
138+
# target: "esp32s3"
139+
#- runs-on: "esp32_s3_lcd_ev_board"
140+
# marker: "esp32_s3_lcd_ev_board"
141+
# target: "esp32s3"
142+
#- runs-on: "esp32_s3_lcd_ev_board"
143+
# marker: "esp32_s3_lcd_ev_board_2"
144+
# target: "esp32s3"
145+
#- runs-on: "esp32_s3_usb_otg"
146+
# marker: "esp32_s3_usb_otg"
147+
# target: "esp32s3"
148+
#- runs-on: "esp_wrover_kit"
149+
# marker: "esp_wrover_kit"
150+
# target: "esp32"
151+
#- runs-on: "m5dial"
152+
# marker: "m5dial"
153+
# target: "esp32s3"
154+
#- runs-on: "m5stack_core"
155+
# marker: "m5stack_core"
156+
# target: "esp32"
157+
#- runs-on: "m5stack_core_2"
158+
# marker: "m5stack_core_2"
159+
# target: "esp32"
160+
#- runs-on: "m5stack_core_s3"
161+
# marker: "m5stack_core_s3"
162+
# target: "esp32s3"
163+
#- runs-on: "m5stack_core_s3"
164+
# marker: "m5stack_core_s3_se"
165+
# target: "esp32s3"
166+
#- runs-on: "esp32_azure_iot_kit"
167+
# marker: "esp32_azure_iot_kit"
168+
# target: "esp32"
169+
#- runs-on: "esp_bsp_devkit"
170+
# marker: "esp_bsp_devkit"
171+
# target: "esp32s3"
172+
#- runs-on: "esp_bsp_generic"
173+
# marker: "esp_bsp_generic"
174+
# target: "esp32s3"
175+
#- runs-on: "esp32_s3_korvo_2"
176+
# marker: "esp32_s3_korvo_2"
177+
# target: "esp32s3"
178+
#- runs-on: "m5_atom_s3"
179+
# marker: "m5_atom_s3"
180+
# target: "esp32s3"
181181
env:
182182
TEST_RESULT_NAME: test_results_${{ matrix.runner.target }}_${{ matrix.runner.marker }}_${{ matrix.idf_ver }}
183183
BENCHMARK_RESULT_NAME: benchmark_${{ matrix.runner.target }}_${{ matrix.runner.marker }}_${{ matrix.idf_ver }}
@@ -197,7 +197,8 @@ jobs:
197197
env:
198198
PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/"
199199
run: |
200-
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code
200+
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code opencv-python numpy
201+
apt-get update && apt-get install -y libgl1
201202
- name: Download latest results
202203
uses: actions/download-artifact@v4
203204
with:
@@ -216,6 +217,7 @@ jobs:
216217
benchmark_*.md
217218
benchmark_*.json
218219
benchmark.json
220+
*.jpg
219221
- name: Check if benchmark files exist
220222
id: check_files
221223
run: |

conftest.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
1+
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
22
# SPDX-License-Identifier: Apache-2.0
33
import pytest
4+
import cv2
5+
from pathlib import Path
46

57

68
def pytest_generate_tests(metafunc):
@@ -38,3 +40,45 @@ def pytest_collection_modifyitems(config, items):
3840
marker_option = "[" + config.getoption("-m") + "]"
3941
if marker_option not in item.nodeid:
4042
item.add_marker(pytest.mark.skip(reason="Not for selected params"))
43+
44+
45+
def bsp_capture_image(image_path, board):
46+
# Return video from the first webcam on your computer.
47+
cap = cv2.VideoCapture(0)
48+
# Set FullHD resolution (1920x1080)
49+
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
50+
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
51+
52+
# TODO: Camera calibration
53+
54+
# reads frames from a camera
55+
# ret checks return at each frame
56+
ret, frame = cap.read()
57+
if ret:
58+
# TODO: Camera calibration / Perspective transform
59+
# TODO: Change size image
60+
# TODO: Crop image for {board}
61+
62+
# Save image
63+
cv2.imwrite(image_path, frame)
64+
print(f"Image saved {image_path}")
65+
else:
66+
print("Cannot save image.")
67+
68+
# Close the window / Release webcam
69+
cap.release()
70+
71+
72+
def bsp_test_image(board, example, expectation):
73+
image_file = f"snapshot_{board}_{example}.jpg"
74+
bsp_capture_image(image_file, board)
75+
76+
77+
@pytest.fixture(autouse=True)
78+
def bsp_test(request):
79+
board = request.node.callspec.id
80+
path = Path(str(request.node.fspath))
81+
test_name = path.parent.name
82+
yield
83+
print(f"Capturing image for: {board}")
84+
bsp_test_image(board, test_name, "")

examples/display/pytest_display.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
1+
# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
22
# SPDX-License-Identifier: CC0-1.0
33

44
import pytest

examples/pytest_helpers.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
2+
# SPDX-License-Identifier: Apache-2.0
3+
import cv2
4+
5+
6+
def bsp_capture_image(image_path):
7+
# Return video from the first webcam on your computer.
8+
cap = cv2.VideoCapture(0)
9+
# reads frames from a camera
10+
# ret checks return at each frame
11+
ret, frame = cap.read()
12+
if ret:
13+
# TODO: Change size image
14+
# TODO: Crop image
15+
16+
# Save image
17+
cv2.imwrite(image_path, frame)
18+
print(f"Image saved {image_path}")
19+
else:
20+
print("Cannot save image.")
21+
22+
# Close the window / Release webcam
23+
cap.release()
24+
25+
26+
def bsp_test_image(board, example, expectation):
27+
image_file = f"snapshot_{example}_{board}.jpg"
28+
bsp_capture_image(image_file)

0 commit comments

Comments
 (0)