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});
FrameEvent はonEvent() で処理され、そこでカスタムクリーンアップ関数を持つ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));
ファイル:
- camera/CMakeLists.txt
- camera/camera.qml
- camera/camerainterface.h
- camera/mcu_camera.qmlproject
- camera/platform/CMakeLists.txt
- camera/platform/dummy/CMakeLists.txt
- camera/platform/dummy/camerainterface.cpp
- camera/platform/nxp/CMakeLists.txt
- camera/platform/nxp/camerainterface.cpp
- camera/platform/nxp/pin_mux_csi.c
- camera/platform/nxp/pin_mux_csi.h
画像:
関連項目: Qul::SharedImage 、Qul::Image 、Qul::EventQueue 、およびQul::Singleton 。
特定のQtライセンスの下で利用可能です。
詳細はこちらをご覧ください。