-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Jupyter notebook walkthrough of camera
This notebook is part of a Trovi artifact meant to showcase the usage of the pi camera module 3 peripheral on CHI@Edge.
- Loading branch information
Soufiane Jounaid
committed
Jun 3, 2024
1 parent
de539a6
commit 969339b
Showing
1 changed file
with
242 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"id": "c2a5282d-f117-4ac9-acc8-f095d7042ba1", | ||
"metadata": {}, | ||
"source": [ | ||
"# Peripheral showcase: Pi Camera Module 3 in CHI@Edge\n", | ||
"\n", | ||
"Welcome to this Jupyter notebook guide on using the Raspberry Pi Camera Module 3 within CHI@Edge. This artifact will walk you through the steps to access and utilize the camera for your edge computing experiments.. \n", | ||
"\n", | ||
"**Important Note:** There is only one device with the camera attached at the moment. We currently are in the process of staffing several of our raspberrypi 4 devices with pi camera modules; later, this month of June 2024, an official blogpost on peripherals will accompany this artifact presenting a hollistic approach for users to add peripherals to CHI@Edge.\n", | ||
"\n", | ||
"In the following example we'll show how to use the Pi Camera Module 3 on a Raspberry Pi 4 to capture both a png image and an h264 30 fps video. " | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "ad4bcf2d-b458-4436-95ab-4cd99e6321f0", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import chi\n", | ||
"chi.use_site(\"CHI@Edge\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 15, | ||
"id": "20761240-ed5c-4ec8-8d51-33cf950f28e7", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"chi.set(\"project_name\", \"your_project_name_goes_here\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 16, | ||
"id": "84038b03-90e9-4f24-898e-d75c9199f8fc", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from chi import container\n", | ||
"from chi import lease" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "07e8cdcc-c8ce-46e3-b1b6-c6080a5b407a", | ||
"metadata": {}, | ||
"source": [ | ||
"## Creating the Lease\n", | ||
"\n", | ||
"To access the camera, we need to make a lease for the specific device that the camera is currently attached to. The device ```sj-rpi4-02``` is specifically set up with the proper kernel and driver options to enable support for the Pi Camera module 3." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "5d19779e-e688-45e0-90f0-8b336411ec4a", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import os\n", | ||
"\n", | ||
"# get your username, just used to name leases something identifiable\n", | ||
"username = os.environ.get(\"USER\")\n", | ||
"\n", | ||
"# machine name refers to the \"type\" of device\n", | ||
"machine_name = \"raspberrypi4-64\"\n", | ||
"\n", | ||
"# Reserving the specific device to which the Pi Camera Module 3 is attached\n", | ||
"device_name = \"sj-rpi4-02\"\n", | ||
"\n", | ||
"# get dates for lease start and end\n", | ||
"start, end = lease.lease_duration(days=1)\n", | ||
"\n", | ||
"# make a unique name for the lease\n", | ||
"lease_name = f\"{username}-{machine_name}-{start}\"\n", | ||
"\n", | ||
"reservations = []\n", | ||
"lease.add_device_reservation(reservations, count=1, machine_name=machine_name, device_name=device_name)\n", | ||
"container_lease = lease.create_lease(lease_name, reservations, start, end)\n", | ||
"lease_id = container_lease[\"id\"]\n", | ||
"\n", | ||
"print(f\"created lease with name {lease_name} and uuid {lease_id}, waiting for it to start. This can take up to 60s.\")\n", | ||
"lease.wait_for_active(lease_id)\n", | ||
"print(\"Done!\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "7da6af80-1099-4457-82d0-7acbe3728cec", | ||
"metadata": {}, | ||
"source": [ | ||
"## Launching a container with libcamera and the rpicam apps\n", | ||
"\n", | ||
"To take pictures and videos with the camera, we need to launch a container image with all the following pre-requisites:\n", | ||
"\n", | ||
"- pi_camera device profile: a flag to expose all the necessary /dev devices required for the camera support\n", | ||
"- libcamera: A complex camera stack designed to support all kinds of cameras on Linux.\n", | ||
"- rpicam-apps: A set of example applications demonstrating how to use libcamera on Raspberry Pi.\n", | ||
"\n", | ||
"We compile slightly modified custom versions of both dependencies and package them in our docker image ```ghcr.io/chameleoncloud/edge-picamera-image:latest```. This is currently the only verified image working on CHI@Edge, we provide the [Dockerfile](https://github.com/ChameleonCloud/edge-picamera-image/blob/ea0b0c48fa79c438bf28281bceddd5620fee26ac/Dockerfile) for reproducibility and customization." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "77feeef9-9f69-440e-a1b9-d392d9b5db33", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"print(\"Requesting container ... This may take a while as the large (>1GB) container image is being downloaded\")\n", | ||
"\n", | ||
"# Set a name for the container. Because CHI@Edge uses Kubernetes, ensure that underscores aren't in the name\n", | ||
"container_name = f\"tutorial-{machine_name}-picamera\".replace(\"_\",\"-\")\n", | ||
"\n", | ||
"try:\n", | ||
" my_container = container.create_container(\n", | ||
" container_name,\n", | ||
" image=\"ghcr.io/chameleoncloud/edge-picamera-image:latest\",\n", | ||
" workdir=\"/home\",\n", | ||
" device_profiles=[\"pi_camera\"],\n", | ||
" reservation_id=lease.get_device_reservation(lease_id),\n", | ||
" platform_version=2,\n", | ||
" )\n", | ||
"except RuntimeError as ex:\n", | ||
" print(ex)\n", | ||
" print(f\"please stop and/or delete {container_name} and try again\")\n", | ||
"else:\n", | ||
" print(f\"Successfully created container: {container_name}!\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "4d4a1ea4-cf3b-4276-978a-d7a735aed200", | ||
"metadata": {}, | ||
"source": [ | ||
"## Capturing a still 1920x1080 picture with the camera\n", | ||
"\n", | ||
"To capture pictures, we use the rpicam applications ([code](https://github.com/raspberrypi/rpicam-apps)). We use ```rpicam-still```[(docs)](https://www.raspberrypi.com/documentation/computers/camera_software.html#rpicam-still) to capture a 1920x1080 still png using the camera. Please visit the rpicam-apps [documentation](https://www.raspberrypi.com/documentation/computers/camera_software.html#rpicam-apps) to learn how to use other utilities.\n", | ||
"\n", | ||
"**Important notes**: \n", | ||
"\n", | ||
"- Capturing frames can take some time. It is not instant.\n", | ||
"- If you run into dma_heap allocation issues/failure to allocate capture buffers, please lower the quality/size of your image or use the png format. The error occurs because the device to which the camera is attached currently only allocates a very limited amount of 64MB of contiguous memory blocks (cma). Each still capture requires a cma buffer amount that is proportional to the size of the target picture. Development efforts are currently ongoing to allow the allocation of more CMA on boot time to allow for larger frames." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "28caaf2e-afc2-497a-b1f4-795c6a84b2c7", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"cmd = \"rpicam-still -o image.png --width 1920 --height 1080\"\n", | ||
"print(chi.container.execute(my_container.uuid, cmd)[\"output\"])" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "331abaf4-66d2-4824-ab20-3234d6d8a9e7", | ||
"metadata": {}, | ||
"source": [ | ||
"Download the captured image from the running container using our ```container.download()``` utility. (**Note**: it takes a slight moment for the jupyter directory navigation pane to refresh and show the downloaded file)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 37, | ||
"id": "f446130b-ab84-4542-9759-6495c6d1e40d", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"chi.container.download(my_container.uuid, \"/home/image.png\",\".\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "c0786f1e-f5cf-43d6-bb23-120c910974eb", | ||
"metadata": {}, | ||
"source": [ | ||
"## Capturing a 5 second 1080p 60fps H264 video with the camera\n", | ||
"\n", | ||
"To capture an h264 video we use the ```rpicam-vid```[(docs)](https://www.raspberrypi.com/documentation/computers/camera_software.html#rpicam-vid) utility to capture a 5 second 1080p video at a framerate of 60 fps. To playback the video, please download the file through the jupyter interface and use a video playback utility such as ```vlc```." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "bb9c1495-734d-4023-9147-61a65b83b148", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"cmd = \"rpicam-vid -t 5000 --framerate 60 --width 1920 --height 1080 -o video.h264\"\n", | ||
"print(chi.container.execute(my_container.uuid, cmd)[\"output\"])" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "858ab551-8109-4415-9cb3-2209e7dc6602", | ||
"metadata": {}, | ||
"source": [ | ||
"**Important note**: the ```container.download()``` utility is primarily meant for smaller size files. Please resort to other methods such as cloud storage or scp to download larger files." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 38, | ||
"id": "f08334e4-e3ef-4f1f-ac11-320db998a8fe", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"chi.container.download(my_container.uuid, \"/home/video.h264\",\".\")" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3 (ipykernel)", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.10.9" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 5 | ||
} |