Implement an Actcast application

Implement an Actcast application #

This tutorial is intended for ActcastOS 3 or later versions.

ActcastOS 1 and ActcastOS 2 will no longer be supported at the end of 2024.

Create an application that converts CSI camera video to grayscale and displays it. In this step, we will implement an Actcast application that converts the captured image to grayscale and displays it on the screen. For more details about each file, see also ActDK Project Structure.

The code for this tutorial is available at here.

Create a main file under the app directory, and paste the following code:

#!/usr/bin/python3
import numpy as np
from PIL import Image
import actfw_core
from actfw_core.task import Pipe, Consumer
from actfw_core.system import find_csi_camera_device
from actfw_core.unicam_isp_capture import UnicamIspCapture
from actfw_raspberrypi.vc4 import Display


# capture image size
(CAPTURE_WIDTH, CAPTURE_HEIGHT) = (320, 240)

# display area size
(DISPLAY_WIDTH, DISPLAY_HEIGHT) = (640, 480)


class Converter(Pipe):
    """Convert RGB camera image to grayscale image"""

    def __init__(self, capture_size):
        super(Converter, self).__init__()
        self.capture_size = capture_size

    def proc(self, frame):
        rgb_image = Image.frombuffer(
            "RGB", self.capture_size, frame.getvalue(), "raw", "RGB"
        )
        gray_image = rgb_image.convert("L")
        return gray_image


class Presenter(Consumer):
    """Display grayscale image on preview window and take photo view"""

    def __init__(self, preview_window, cmd):
        super(Presenter, self).__init__()
        self.preview_window = preview_window
        self.cmd = cmd

    def proc(self, gray_image):
        # update `Take Photo` image
        self.cmd.update_image(gray_image)

        # if preview window is available, display grayscale image
        if self.preview_window is not None:
            # convert grayscale image to RGB image for display in preview window
            gray_image = gray_image.convert("RGB")
            self.preview_window.blit(np.asarray(gray_image).tobytes())
            self.preview_window.update()

        actfw_core.heartbeat()


def run(app, preview_window=None):
    # CommandServer (for `Take Photo` command)
    cmd = actfw_core.CommandServer()
    app.register_task(cmd)

    # register capture task
    capture_size = (CAPTURE_WIDTH, CAPTURE_HEIGHT)
    framerate = 30
    device = find_csi_camera_device()
    cap = UnicamIspCapture(unicam=device, size=capture_size, framerate=framerate)
    app.register_task(cap)

    # register converter task
    conv = Converter(cap.capture_size())
    app.register_task(conv)

    # register presenter task
    pres = Presenter(preview_window, cmd)
    app.register_task(pres)

    # Make task connection
    cap.connect(conv)  # from `cap` to `conv`
    conv.connect(pres)  # from `conv` to `pres`

    # Start application
    app.run()


def main():
    # Actcast application
    app = actfw_core.Application()

    # Load act setting
    settings = app.get_settings({"display": False})

    if settings["display"]:
        with Display() as display:
            preview_area = (0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT)
            capture_size = (CAPTURE_WIDTH, CAPTURE_HEIGHT)
            layer = 16
            with display.open_window(
                preview_area, capture_size, layer
            ) as preview_window:
                run(app, preview_window)
    else:
        run(app)


if __name__ == "__main__":
    main()

Then, create a healthchecker file under the app directory, and paste the following code:

#!/bin/bash

HEARTBEAT_FILE='/root/heartbeat'

[ "$(find "${HEARTBEAT_FILE}" -mmin -1)" == "${HEARTBEAT_FILE}" ]

Then, in the apt part of .actdk/dependencies.json, add libv4l-0 and libv4lconvert0 used by actfw_core.unicam_isp_capture.UnicamIspCapture, and main add python3-numpy, which main` depends on.

{
  "apt": [
    "libv4l-0",
    "libv4lconvert0",
    "python3",
    "python3-pil",
    "python3-numpy"
  ],
  "pip": [],
  "raspberrypi-bullseye": {
    "apt": [
      "libraspberrypi0"
    ],
    "pip": [
      "actfw-raspberrypi"
    ]
  }
}

if you want to output the result to the display connected to the device, set setting_schema.json as follows.

{
  "$schema": "https://actcast.io/schema/v8/setting_schema_schema.json",
  "type": "object",
  "properties": {
    "display": {
      "title": "display",
      "description": "display grayscale image",
      "type": "boolean",
      "default": false
    }
  },
  "required": []
}

Then, run actdk generate act_settings and set the generated act_settings.json as follows.

{
  "display": true
}

Next: Setup Actsim

Previous: Create a Project


Back to App Development Tutorial