tks_yoshinagaの日記

KinectやLeap motion, VRやARなどの技術を使ってやったことのメモとか

C#で始めるAzure Kinect開発④:カラー画像とDepth画像の位置合わせ

1.はじめに

これまでの記事ではC#のFormアプリケーション開発するためのSDKの導入、Kinectの起動、カラー画像の表示、Depth画像の表示についてそれぞれ解説しました。(過去記事はこのページの最後にリンクがあります。)

これらのチュートリアルを組み合わせることで同一ウインドウ内にカラー画像とDepth画像を並べて表示するということも可能になります。ただし、それぞれの画像は異なるカメラによって撮影されているため位置や画素数、画角など様々なパラメータが異り、奥行きと色を対応付けるには座標変換(位置合わせ)が必要になります。
そこで今回はSDKが提供するTransformationを利用した各画像の位置合わせについて紹介します。なお、本記事で使用するプログラムは下記の記事①の内容の続きとなります。

 
2.UIの準備

1) Form1.cs[デザイン]タブを開く
2) ツールボックスからPictureBoxを選択し、Form1にドラッグ&ドロップ

f:id:tks_yoshinaga:20191205125412p:plain


3) Form1上に配置したPictureBoxをクリック
4) プロパティ内で下記の通り設定
 Size: 320,288  (※NFOV BinnedモードのDepth画像のサイズ)
 SizeMode: Zoom (※PictureBoxのサイズを変更した場合に便利)

f:id:tks_yoshinaga:20191205125542p:plain


5) Form上に配置したPictureBoxをコピー&ペースト
6) pictureBox1とpictureBox2を左右に並べる
7) Formのサイズを整える

f:id:tks_yoshinaga:20191205125742p:plain 

補足:
今回はカラー画像用とDepth画像用にそれぞれPictureBoxを用意します。このあとの章でカラー画像をDepth画像に合わせる処理を行うことでカラー画像の縦・横幅はDepthと同じになるため各PictureBoxのサイズを同じにしています。


8) [プロジェクト]→[(プロジェクト名)のプロパティ]をクリック

f:id:tks_yoshinaga:20191205125832p:plain


9) 左の列から[ビルド]をクリック
10) 構成から[すべての構成]を選択
11) [アンセーフコードの許可]をチェック

f:id:tks_yoshinaga:20191203163531p:plain

 

3.使用する変数やメソッドの準備

1) Form1.csのコードを開く
2) usingでImage, BitmapData, PixelFormatを読み込む
3) カラー/Depth画像を記録する変数、colorBitmapdepthBitmapを宣言
4) 各画像の間の位置合わせをするTransformationを扱う変数を宣言
5) Kinectからのデータ取得を継続するフラグ、loopを宣言&trueで初期化
6) colorBitmapとdepthBitmapを初期化する関数InitBitmapを追加
7) Kinectからデータをリアルタイムに取得するKinectLoopを追加
8) カラー画像(colorBitmap)にKinectのカラー情報を書き込むSetColorBitmapを追加
9) Depth画像(depthBitmap)にKinectのDepth情報を書き込むSetDepthBitmapを追加
10) コンストラクタでInitBitmap, KinectLoopを呼び出す。
    ※コメントの追加②~⑩の箇所を新規追加箇所

コード

gist.github.com

4.画像の取得と表示

4.1. InitKinectメソッド

画像間の位置合わせに関する情報を取得し、transformationに代入

gist.github.com

4.2. InitBitmapメソッド

1) Depth画像の縦・横のサイズを取得
2) Depth画像のサイズをもとにcolorBitmapとdepthBitmapを初期化

補足:
前述のとおり位置合わせによりカラー画像はDepth画像と同じサイズになるのでBitmapの初期化も同じサイズでOK

gist.github.com

4.3. KinectLooopメソッド

1) while文でloopがtrueの間は画像の取得・表示を行い、whileを抜けたらKinectを停止
2) GetCaptureで最新の情報をKinectから取得
3) SetColorBitmapとSetDepthBitmapでカラー/Depth情報をBitmapに書き込む
4) 各BitmapをPictureBoxに貼り付ける
5) Updateメソッドで表示を更新

補足:
3) で呼び出しているメソッドの挙動は未実装なのでまだ何も表示されません。

gist.github.com

4.4. SetColorBitmapメソッド

1) ColorImageToDepthCameraでDepth画像との位置合わせ済みのカラー画像を取得
2) colorImageから各ピクセルの色のみを格納した配列を取得
3) LockBitsでcolorBitmap(書き込み先のBitmap)への書き込み準備をする
4) 書き込み先のBitmapへのポインタ(配列みたいなもの)を取得
5) for文で1ピクセルごとにBGRAの順番で色を書き込む
6) UnlockBitsで書き込み終了
7) colorImageで確保したメモリを解放 (必ずすること!)

補足:
Kinectのカラー情報のBitmap化については過去の記事でよりシンプルな方法を紹介しましたが、本記事ではOpenCVを併用した画像処理を組み合わせる場合も想定して各ピクセル情報にアクセスする方法を紹介しています。

gist.github.com8) 実行すると補正済みのカラー画像が表示されます

f:id:tks_yoshinaga:20191205125912j:plain

 

4.5. SetDepthBitmapメソッド

1) capture.DepthでDepth画像を取得
2) depthImageから各ピクセルに対応する奥行のみを格納した配列を取得
3) LockBitsでdepthBitmap(書き込み先のBitmap)への書き込み準備をする
4) 書き込み先のBitmapへのポインタ(配列みたいなもの)を取得
5) for文で1ピクセルずつ距離情報を画像に書き込む

補足:
depthArrayには各ピクセルに対応する距離情報がmm単位で格納されている。しかし画像はRGBそれぞれ0~256の整数の組み合わせで表現するので、距離情報の画像化には距離(mm)と色との対応付けが必要となる。本記事では最もシンプルなグレースケール(モノクロ表現)を用い500~5000mmを0~255で表現します。

6) UnlockBitsで書き込み終了
7) colorImageで確保したメモリを解放 (必ずすること!)

gist.github.com

8) 実行すると補正済みのカラー画像とDepth画像が表示されます

f:id:tks_yoshinaga:20191205125934j:plain

 

5.まとめ

今回はColor画像をDepth画像との位置合わせについて紹介しました。ポイントはColorImageToDepthCameraという関数を使ってカラー画像に変換をかけるというこの一行を実行することです。ちなみに今回は紹介しませんでしたが、DepthImageToColorCameraを使えばDepthをカラー画像に合わせることができ、DepthImageToPointCloudを使えばDepthをxyzの3次元座標に変換することができます。ご興味があればぜひお試しください。
また、公式のサンプルでは画像の書き込みの際に非同期処理を用いて記述されています。非同期処理が苦手な方もひとまず本サンプルで処理の手順を理解しておくと公式サンプルを読み解きやすくなるのではないかと思います。

 

AzureKinectの他の記事はこちら!

tks-yoshinaga.hatenablog.com