メインコンテンツまでスキップ
バージョン: v24.05

画像の表示

このチュートリアルでは、ion-kitを使用してデバイスから画像データを取得し、OpenCVで表示する方法を学びます。

前提条件

  • OpenCV(sensing-dev SDKと一緒に-InstallOpenCVオプションでインストール)
  • ion-kit(sensing-dev SDKと共にインストール)

チュートリアル

デバイス情報の取得

ionpyを使用して画像を表示するには、デバイスの以下の情報を取得する必要があります。

  • 高さ
  • ピクセルフォーマット

前回のチュートリアルまたは arv-tool-0.8 がこれらの値を取得するのに役立ちます。

パイプラインの構築

イントロで学んだように、画像の入出力と処理のためのパイプラインを構築して実行します。

ion-kitおよびOpenCVのAPIを使用するために、次のヘッダーを含める必要があります:

#include <ion/ion.h>

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

このチュートリアルでは、非常に単純なパイプラインを構築します。このパイプラインは、U3Vカメラから画像を取得する唯一のビルディングブロックを持っています。

次のion APIがパイプラインを設定します。

// パイプラインの設定
Builder b;
b.set_target(ion::get_host_target());
b.with_bb_module("ion-bb");

set_targetは、ビルダーによって構築されたパイプラインが実行されるハードウェアを指定します。

ion-bb.dllで定義されたBBを使用したいので、with_bb_module関数でモジュールをロードする必要があります。

使用するBBはimage_io_u3v_cameraN_u8x2で、これは各ピクセルデータが8ビット深度で2次元のU3Vカメラ向けに設計されています(例:Mono8)。

デバイスのピクセルフォーマットがMono10またはMono12の場合、10ビットおよび12ビットのピクセルデータを格納するために16ビット深度のピクセルが必要なので、image_io_u3v_cameraN_u16x2が必要です。

ピクセルフォーマットがRGB8の場合、ビットの深度は8で、次元は3です(幅と高さに加えて、カラーチャネルがあります)、そのためimage_io_u3v_cameraN_u8x3を使用します。

BBの名前ビットの深さ次元PixelFormatの例
image_io_u3v_cameraN_u8x282Mono8
image_io_u3v_cameraN_u8x383RGB8, BGR8
image_io_u3v_cameraN_u16x2162Mono10, Mono12

BBに設定するための静的な入力値を設定するには、次のようにParamを定義する必要があります。

// パラメータの設定
Param num_devices("num_devices", num_device),
Param frame_sync("frame_sync", true),
Param realtime_display_mode("realtime_display_mode", true)
Paramのキー値のタイプ説明
num_devicesIntegerプログラムで使用するデバイスの数
frame_syncBooleanデバイスの数が1以上の場合、デバイス間でフレームカウントを同期させる
realtime_display_modeBooleanフレームドロップを許可しますが、遅延はありません

これで、ノードとポート、およびパラメータを持つBBをパイプラインに追加できます。

// パイプラインにノードを追加
Node n = b.add(bb_name)()
.set_param(
Param("num_devices", num_device),
Param("frame_sync", true),
Param("realtime_display_mode", false)
);

これがパイプラインとBB、ポートの構造です:

tutorial1-pipeline

ポートから出力データを取得するために、出力用のバッファを準備し、ポートをバッファにバインドします。

// 出力ポートから出力バッファへのポートマッピング
std::vector< int > buf_size = std::vector < int >{ width, height };
if (pixel_format == "RGB8"){
buf_size.push_back(3);
}
std::vector<Halide::Buffer<T>> output;
for (int i = 0; i < num_device; ++i){
output.push_back(Halide::Buffer<T>(buf_size));
}
n["output"].bind(output);

注意:ここでのbuf_sizeは2Dイメージ用に設計されています。ピクセルフォーマットがRGB8の場合、カラーチャネルを追加するには(width、height、3)を設定する必要があります。

Tは出力バッファのタイプです。たとえば、Mono8およびRGB8用にuint8_t、Mono10およびMono12用にuint16_tです。

パイプラインの実行

パイプラインは実行の準備ができました。 run()を呼び出すたびに、ベクトルまたはoutput内のバッファが出力画像を受け取ります。

b.run();

OpenCVで表示

出力データ(つまり画像データ)がBufferのベクトル outputとバインドされているため、これをOpenCVバッファにコピーして画像処理または表示できます。

注意:OpenCVはバッファ上のチャネル(次元)の順序が異なる可能性があります。

int coef =  positive_pow(2, num_bit_shift_map[pixel_format]);

// i番目のデバイス用
cv::Mat img(height, width, opencv_mat_type[pixel_format]);
std::memcpy(img.ptr(), output[i].data(), output[i].size_in_bytes());
img *= coef;

opencv_mat_type[pixel_format]は画像データのPixelFormat(ビットの深さと次元)に依存します。例えば、Mono8の場合はCV_8UC1、RGB8の場合はCV_8UC3、Mono10およびMono12の場合はCV_16UC1です。

output[i]をOpenCV Matオブジェクトにコピーして表示できます。

cv::imshow("image" + std::to_string(i), img);
user_input = cv::waitKeyEx(1);

注意:outputはBufferのベクトルです(つまり、複数のデバイスを制御するためにnum_deviceを設定できます)。画像データを取得するにはoutpus[0]にアクセスします。

連続した画像を取得するには、cv::waitKeyEx(1)を使用してwhileループを設定します。これにより、プログラムは1ミリ秒間保持され、ユーザーがキーを入力すると-1以外の値が返されます。次のコードは、ユーザーがキーを入力するまで無限ループします。

while(user_input == -1)
{
// Builderを使用してパイプラインをJITコンパイルおよび実行します。
b.run();

// 取得したバッファオブジェクトをOpenCVバッファ形式に変換します。
for (int i = 0; i < num_device; ++i){
cv::Mat img(height, width, opencv_mat_type[pixel_format]);
std::memcpy(img.ptr(), output[i].data(), output[i].size_in_bytes());
img *= coef;
cv::imshow("image" + std::to_string(i), img);
}

// 1ms待機
user_input = cv::waitKeyEx(1);
}
カメラインスタンスが正確に解放されるのは

カメラインスタンスの寿命はビルディングブロックインスタンスによって制限されています。つまり、プログラムが終了するとともに自動的に破棄されます。正確なタイミングを観察するには、ユーザーはWindowsコマンドラインでset ION_LOG_LEVEL=debug、またはUnixターミナルでexport ION_LOG_LEVEL=debugを設定できます。ユーザーは、ターミナルで以下の行が表示された場合、aravis経由でカメラにアクセスできます:

[2024-02-14 08:17:19.560] [ion] [info]  Device/USB 0::Command : AcquisitionStart
[2024-02-14 08:17:27.789] [ion] [debug] U3V::release_instance() :: is called
[2024-02-14 08:17:27.790] [ion] [debug] U3V::dispose() :: is called
[2024-02-14 08:17:27.791] [ion] [debug] U3V::dispose() :: AcquisitionStop
[2024-02-14 08:17:28.035] [ion] [debug] U3V::dispose() :: g_object_unref took 244 ms
[2024-02-14 08:17:28.109] [ion] [debug] U3V::dispose() :: g_object_unref took 72 ms
[2024-02-14 08:17:28.110] [ion] [debug] U3V::dispose() :: Instance is deleted
[2024-02-14 08:17:28.111] [ion] [debug] U3V::release_instance() :: is finished

上記のデバッグ情報から、ユーザーはカメラインスタンスの解放にかかる時間を知ることができます。 詳細ははデバッグのヒントを参照してください。

完全なコード

このチュートリアルで使用される完全なコードはこちらです。

動かない時は
  • もしお使いのOpenCVがSensing-Devインストール時に-InstallOpenCVオプションをつけてインストールしたものでない場合、プログラムに正しくリンクされているかを確認してください。