Implement an Actcast application

Implement an Actcast application #

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
import actfw_core
from PIL import Image
from actfw_core.task import Pipe, Consumer
from actfw_core.capture import V4LCameraCapture
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
    cap = V4LCameraCapture(
        size=capture_size,
        framerate=framerate,
        format_selector=V4LCameraCapture.FormatSelector.PROPER,
    )
    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 = 2000
            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, add python3-numpy, libv4l-0 and libv4lconvert0 to the part apt of .actdk/dependencies.json

{
  "apt": [
    "libv4l-0",
    "libv4lconvert0",
    "python3",
    "python3-pil",
    "python3-numpy"
  ],
  "pip": [],
  "raspberrypi": {
    "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