このページでは

C

Qt Quick Ultraliteカメラの例

プラットフォーム固有の画像データをQML UIに統合する方法を示します。

概要

このサンプルでは、プラットフォーム固有の画像データの処理方法を示します。Qul::SharedImage を使用してカメラを制御し、そのフレームにアクセスするためのシンプルなユーザーインターフェースを備えています。このサンプルでは、サポートされているボードではカメラのハードウェアを使用し、その他のボードではダミー実装を使用します。

背景画像と「カメラを起動」ボタンが表示されたスタート画面を示すカメラの例。

ライブカメラストリームが有効で、「撮影」ボタンと「停止」ボタンが有効になっているカメラの例。

静止画がキャプチャされ、「最小化」ボタンと「閉じる」ボタンが有効になっているカメラの例。

キャプチャしたフレームが右上隅に最小化され、「最大化」ボタンと「閉じる」ボタンが有効になっているカメラの例。

対象プラットフォーム

プロジェクト構成

このサンプルは、シンプルな UI(camera.qml)、カメラインターフェースの定義(camerainterface.h)、NXP プラットフォーム向けのカメラインターフェースの実装、およびカメラインターフェースのダミー実装(platform ディレクトリ内)で構成されています。さらに、背景画像アセット(bg_qt.png)も含まれています。

CMakeプロジェクトファイル

Qt Quick UltraliteアプリケーションのCMake設定に加え、NXP およびdummy向けのカメラインターフェース実装を含むplatformサブディレクトリが含まれています。

add_subdirectory(platform)

また、QmlProjectファイルでは、Qt Quick Ultraliteがカメラインターフェースを検出できるように、その登録も行われています。

        InterfaceFiles {
                files: [
                        "camerainterface.h"
                ]
        }

platformディレクトリ内のCMakeLists.txtでは、実装を選択する前にプラットフォームを確認しています:

# Copyright (C) 2025 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial
message(STATUS "Board manufacturer: ${BOARD_MANUFACTURER_NAME}")

string(REGEX MATCHALL "([^\-]+|[^\-]+$)" PLATFORM_COMPONENTS ${QUL_PLATFORM})
list(GET PLATFORM_COMPONENTS 0 BOARD_NAME)
string(TOLOWER ${BOARD_NAME} BOARD_NAME)

if(NOT ${BOARD_NAME} STREQUAL "mimxrt1170" AND ${BOARD_MANUFACTURER_NAME} STREQUAL "nxp")
    add_subdirectory(nxp)
else()
    add_subdirectory(dummy)
endif()

このサンプルは、MCUXpresso SDK が提供する一部のコードに依存しています。そのコードをQt Quick Ultralite プラットフォームライブラリに追加する代わりに、サンプルに追加されています。このコードは主に、CSI ピンマルチプレクサの設定およびカメラの I2C 関数を扱っています。さらに、カメラサポートコードとドライバは、MCUXpresso SDK からインクルードされてコンパイルされます。

アプリケーションのUI

ユーザーインターフェースはcamera.qml で実装されています。

アプリケーションは、背景画像と「Start Camera」ボタンを表示して起動します。このボタンをクリックすると、カメラの画像ストリームが開始され、「Shoot」ボタンと「Stop」ボタンが有効になります。「Shoot」ボタンをクリックすると、表示されていたフレームでカメラストリームが停止し、「Minimize」ボタンと「Close」ボタンが有効になります。「Minimize」ボタンは、現在表示されているフレームを画面の右上隅に最小化します。「Close」ボタンは、前の状態に戻します。「Stop」ボタンをクリックすると、カメラストリームが停止し、開始状態に戻ります。

ユーザーインターフェースのコードで注目すべき点は、`cameraView `Image 型です:

    Text {
        id: message
        color: "red"
        font.pixelSize: 14
    }

    Image {
        id: cameraView
        anchors.right: parent.right
        anchors.top: parent.top
        source: CameraInterface.image
        width: 0
        height: 0

        Behavior on width { NumberAnimation { duration: 500; easing.type: Easing.OutCubic } }
        Behavior on height { NumberAnimation { duration: 500; easing.type: Easing.OutCubic } }

        Component.onCompleted: {
            if (!CameraInterface.initCamera()) {
                console.log("Camera initialization failed");
                message.text =
                    "Camera initialization failed.\nConnect a camera and/or check the serial console output.";
            }
        }

        SequentialAnimation on opacity {
            id: shootAnimation
            PropertyAnimation { property: "opacity"; from: 1.0; to: 0.0; duration: 200}
            PropertyAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 200}
        }
    }

これは、カメラインターフェースのimage プロパティを、そのsource プロパティにバインドします。また、イベントハンドラからinitCamera() を呼び出すことで、カメラを初期化します。

カメラインターフェース

カメラインターフェースは、Qul::EventQueue を持つ単純なQul::Singleton インターフェースです。イベントキューは、プラットフォームからQt Quick Ultralite アプリケーションへカメラフレームを非同期で配信するために使用されます。

まず、カメラフレームデータへのポインタを保持する単純な構造体を定義します:

struct FrameEvent
{
    uint8_t *newFrame;
};

この構造体は、Qul::EventQueue のイベントデータ型として使用されます。

以下に、カメラインターフェースの定義を示します:

struct CameraInterface : public Qul::Singleton<CameraInterface>, public Qul::EventQueue<FrameEvent>
{
    Qul::Property<Qul::SharedImage> image;

    bool initCamera();
    void startCamera();
    void stopCamera();

private:
    void onEvent(const FrameEvent &frame) QUL_DECL_OVERRIDE;

    friend struct Qul::Singleton<CameraInterface>;
    CameraInterface() {}
    CameraInterface(const CameraInterface &);
    CameraInterface &operator=(const CameraInterface &);
};

まず、カメラインターフェースでは、Qul::SharedImage型のimageプロパティが導入されています。このプロパティには、プラットフォームのカメラストリームからのフレームデータが含まれます。続いて、カメラを制御するための関数が宣言されます。 プラットフォームカメラを初期化するinitCamera()関数、およびカメラストリームを開始・停止するためのstartCamera() とstopCamera()関数です。画像の更新を処理するために、Qul::EventQueueのonEvent()関数がオーバーライドされています。最後に、外部からのインスタンス化やコピーが防止されています。

カメラインターフェースの実装

カメラインターフェースの実装は、platformディレクトリにあります。dummyサブディレクトリには、インターフェースのスタブ関数を実装したダミー実装が含まれています。これは、サンプルを別のプラットフォームに移植する際の出発点として使用できます:

#include "camerainterface.h"

/* Initialize your platform's camera hardware in this function. */
bool CameraInterface::initCamera()
{
    return false;
}

/* Start camera stream. */
void CameraInterface::startCamera() {}

/* Stop camera stream. */
void CameraInterface::stopCamera() {}

/* When the camera frame is ready, the image property can be updated in this event handler. */
void CameraInterface::onEvent(const FrameEvent &frameEvent)

nxpサブディレクトリにはNXP ボード向けの実装が含まれています。この実装では、NXP のカメラレシーバーAPIを使用しています。initCamera() でカメラレシーバーを初期化し、新しいフレームを受信するためのコールバック関数を設定するとともに、Qul::EventQueue を介してイベントを投稿できるように、this ポインタをユーザーデータとして設定します。

    err = CAMERA_RECEIVER_Init(&cameraReceiver, &cameraConfig, newCameraFrame, this);

また、空のカメラフレームバッファもカメラレシーバーに送信されます。

    for (uint32_t i = 0; i < CAMERA_BUFFER_COUNT; i++) {
        err = CAMERA_RECEIVER_SubmitEmptyBuffer(&cameraReceiver, (uint32_t) (s_cameraBuffers[i]));
        RETURN_FALSE_IF(err != kStatus_Success, "Failed to submit camera buffer!");
    }

カメラレシーバーは、newCameraFrame コールバックを通じて新しいフレームについて通知します。その後、コールバックは、新しいカメラフレームへのポインタを含むFrameEvent を投稿します。

    me->postEventFromInterrupt(FrameEvent{(uint8_t *) cameraFrameAddr});

FrameEventonEvent() で処理され、そこでカスタムクリーンアップ関数を持つQul::Image が構築され、Qul::SharedImage でラップされて、image プロパティの値として設定されます。

    image.setValue(Qul::SharedImage(newFrame));

cleanup 関数は、Qt Quick のUltraliteエンジンがQul::SharedImage への参照を破棄する際に呼び出されます。この関数のmemory 引数は、image プロパティを介してQt Quick のUltraliteエンジンに渡されたバッファを指しています。この空のバッファは、新しいカメラフレームが利用可能になるたびに、それらにアクセスするために再利用されます。

    status_t err = CAMERA_RECEIVER_SubmitEmptyBuffer(&cameraReceiver, (uint32_t) (memory));

ファイル:

画像:

関連項目: Qul::SharedImageQul::ImageQul::EventQueue 、およびQul::Singleton

特定のQtライセンスの下で利用可能です。
詳細はこちらをご覧ください。