トップ回答者
Kinect v2でdepth画像とcolor画像を正しく対応させたい(C++)

質問
-
Kinect v2を使って、depthとcolor画像を別々に出力し、それぞれを保存したいと思っています。
depthとcolorを別々に出力することは出来たのですが、2つの画像を正確に対応させることができません。主な原因は、Kinect v2のdepthカメラの解像度が512×424でcolorカメラの解像度が1920×1080であってサイズ、アスペクト比が異なること、さらに2つのカメラの視点が異なるということです。
1つ目の問題に対処するために、無理矢理、color画像を1920×1080から512×424にリサイズしてみましたが、アスペクト比が異なるので2つの画像にズレが生じてしまっています。
上記の2つの問題を上手く解決して、colorとdepthの画像サイズ、画素値が正しく対応するようにしたいと思っています。
ちなみに、Windowsのvisual studio 2013を使ってC++で書いています。
ご回答よろしくお願いいたします。
回答
-
例えば、MapColorFrameToDepthSpace()を使用すると、colorとdepthがどのように対応するようになるんでしょうか。
この関数を使う前は、例えばColor画像の(x,y)=(500,400)のdepthを取得したくてもdepth座標系とcolor座標系が異なるのでそのまま取得できないが、
この関数を使えば、depthの(x,y)=(500,400)を指定すれば、color画像のその位置のdepthが得られるということであっているのでしょうか?
ICoordinateMapper::MapColorFrameToDepthSpace()では、「Color座標系の座標( cx, cy )に対応するDepth座標系の座標は( dx, dy )」といった対応関係が得られるため、その対応関係をもとにColor画像の任意の画素に対応するDepthデータを得ることができます。
文章で説明するとイメージし難いので、ソースコードと画像を用意しました。
こちらが理解の手助けになれば幸いです。
- 編集済み Tsukasa SugiuraMVP 2015年12月21日 17:05
- 回答の候補に設定 星 睦美 2015年12月22日 4:36
- 回答としてマーク jojotata 2015年12月22日 16:05
-
自分が言いたかったのは、「1920×1080のうちの内部の512×424領域」という意味ではありません。「1920×1080のうちの1304×1080領域」という意味です。自分は1から10まで懇切丁寧に解説するつもりはないので、もう一度よく考えて普通に計算してみてください。自分は実機を持っていないので逆に聞きたいぐらいですが、カラー画像と深度画像は絶対解像度やアスペクト比が違うだけでなく、もともと分解能(DPI)自体が違うんじゃないですか? 人体認識の要となるはずの深度カメラが、カラーカメラ領域の半分もカバーできていないというのは本来ありえないはずです。
前提を誤解していると後々苦労するので、まずはハードウェアのスペックに対する正しい理解から始めたほうがよいと思われます。とりあえず深度画像のフレームをグレースケール画像として保存してみて、同時に取得したカラー画像のフレームと比較してみれば、一体何がどうなっているのか、カラー/深度のマッピングがどういう仕様になっているのかがはっきりすると思います。画像処理をやるのであれば、一発で最終的な解法を求めようとしたりせず、途中まででいいからまず理解しているところまで対象を可視化して少しずつ問題を分析してみるのがセオリーです。他人から手取り足取り教えてもらうよりも、自分で苦労しながら試行錯誤して得た知識や技術のほうが身に付きやすく応用も効き、結果的に早道となることのほうが多いはずです。
すべての返信
-
Kinect SDK v2のICoordinateMapperクラスに各座標系を対応付けるための関数が用意されています。
Kinect v2から取得できる基本データはそれぞれ、ColorはColor座標系、Depth/Infrared/BodyIndexはDepth座標系、BodyはCamera座標系のデータです。
たとえば、「Color画像をDepth画像を基準に位置合わせする」とは「Color座標系をDepth座標系にフレーム単位で変換する」ということなのでICoordinateMapper::MapDepthFrameToColorSpace()を利用します。
MapDepthFrameToColorSpace()の出力はDepth座標系(512*424)の座標それぞれに対応するColor座標系の座標が得られます。
この対応関係をもとにデータを位置合わせすると、Depth解像度のColor画像が得られます。逆に、「Depth画像をColor画像を基準に位置合わせする」とは「Depth座標系をColor座標系にフレーム単位で変換する」ということなのでICoordinateMapper::MapColorFrameToDepthSpace()を利用します。
MapColorFrameToDepthSpace()の出力はColor座標系(1920*1080)の座標それぞれに対応するDepth座標系の座標が得られます。
この対応関係をもとにデータを位置合わせすると、Color解像度のDepth画像が得られます。また、ICoordinateMapperには上記のような「フレーム単位」での変換の他に「座標単位での変換」のための関数も用意されており、目的に合わせてどの関数を利用するのか適切に選択します。
ICoordinateMapperについては、拙著(共著)「KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版」の3.7にて解説しています。
サンプルプログラムはGitHubにて公開しています。ご参考になれば幸いです。
- 編集済み Tsukasa SugiuraMVP 2015年12月20日 19:45
- 回答の候補に設定 星 睦美 2015年12月22日 4:36
-
返信ありがとうございます。
書籍を購入させていただきました。
depthカメラから得られる情報とcolorカメラから得られる情報がどのように対応しているかがまだよくわかっていないのですが、
例えば、MapColorFrameToDepthSpace()を使用すると、colorとdepthがどのように対応するようになるんでしょうか。
この関数を使う前は、例えばColor画像の(x,y)=(500,400)のdepthを取得したくてもdepth座標系とcolor座標系が異なるのでそのまま取得できないが、
この関数を使えば、depthの(x,y)=(500,400)を指定すれば、color画像のその位置のdepthが得られるということであっているのでしょうか?
また、Color画像の中心から512*480より外側の画素に対しては、depthを取得することができないのでしょうか?
画像処理もKinectもはじめてなので、的外れな質問をしてしまっているかもしれませんが、ご回答のほど宜しく御願い致します。
-
ご回答ありがとうございます。
Color画像の中央部分がdepthに対応しているんですね。全く勘違いして理解していました。
ちなみにsyghさんが書いてくださった式はなぜそうなるのでしょうか?
Color画像の1920*1080の中心512*424の画素のdepthの情報はカバーできていますが、それより外はカバーできていないというわけではないのでしょうか?
ちなみに用途としては、物体をKinectで撮影して、Color画像を使って色々画像処理をしたいと思っています。
その画像処理の際に、Color画像内の物体の位置の奥行きを使用したいと思っています。
そのため、depthは2次元配列などに入れておき、Color画像の物体が写っている部分の画素の位置(例えば(x,y)=(1000,800))をとってきて、depth配列からその位置のdepthを取得するというようなことをしたいと思っています。
画像処理がはじめてなので、わからないことが多くて申し訳ございません。
ご回答ほど宜しくお願いいたします。
- 編集済み jojotata 2015年12月21日 13:14
-
例えば、MapColorFrameToDepthSpace()を使用すると、colorとdepthがどのように対応するようになるんでしょうか。
この関数を使う前は、例えばColor画像の(x,y)=(500,400)のdepthを取得したくてもdepth座標系とcolor座標系が異なるのでそのまま取得できないが、
この関数を使えば、depthの(x,y)=(500,400)を指定すれば、color画像のその位置のdepthが得られるということであっているのでしょうか?
ICoordinateMapper::MapColorFrameToDepthSpace()では、「Color座標系の座標( cx, cy )に対応するDepth座標系の座標は( dx, dy )」といった対応関係が得られるため、その対応関係をもとにColor画像の任意の画素に対応するDepthデータを得ることができます。
文章で説明するとイメージし難いので、ソースコードと画像を用意しました。
こちらが理解の手助けになれば幸いです。
- 編集済み Tsukasa SugiuraMVP 2015年12月21日 17:05
- 回答の候補に設定 星 睦美 2015年12月22日 4:36
- 回答としてマーク jojotata 2015年12月22日 16:05
-
フォーラム オペレーターの星 睦美です。
Tsukasa Sugiura さん、質問への回答ありがとうございます。jojotata さん、こんにちは。
フォーラムの回答が役立ったようですね。役立つ情報をフォーラム ユーザーで共有するために、投稿者からの[回答としてマーク] をお願いしています。
今回は私から[回答の候補に設定] させていただきました。お忘れのような場合にはオペレーターからマークさせていただきますが、回答者への励ましになりますのでjojotata さんからの[回答としてマーク] いただけるとうれしいです。
今後ともMSDN フォーラムをお役立てください。フォーラム オペレーター 星 睦美 - MSDN Community Support
-
自分が言いたかったのは、「1920×1080のうちの内部の512×424領域」という意味ではありません。「1920×1080のうちの1304×1080領域」という意味です。自分は1から10まで懇切丁寧に解説するつもりはないので、もう一度よく考えて普通に計算してみてください。自分は実機を持っていないので逆に聞きたいぐらいですが、カラー画像と深度画像は絶対解像度やアスペクト比が違うだけでなく、もともと分解能(DPI)自体が違うんじゃないですか? 人体認識の要となるはずの深度カメラが、カラーカメラ領域の半分もカバーできていないというのは本来ありえないはずです。
前提を誤解していると後々苦労するので、まずはハードウェアのスペックに対する正しい理解から始めたほうがよいと思われます。とりあえず深度画像のフレームをグレースケール画像として保存してみて、同時に取得したカラー画像のフレームと比較してみれば、一体何がどうなっているのか、カラー/深度のマッピングがどういう仕様になっているのかがはっきりすると思います。画像処理をやるのであれば、一発で最終的な解法を求めようとしたりせず、途中まででいいからまず理解しているところまで対象を可視化して少しずつ問題を分析してみるのがセオリーです。他人から手取り足取り教えてもらうよりも、自分で苦労しながら試行錯誤して得た知識や技術のほうが身に付きやすく応用も効き、結果的に早道となることのほうが多いはずです。