ラベル KINECT の投稿を表示しています。 すべての投稿を表示
ラベル KINECT の投稿を表示しています。 すべての投稿を表示

2014年10月1日水曜日

【kinect使ってみる。】座標のずれ

kinect記事前回では、depth画像とcolor画像の座標のズレを合わすところまで入てやりました。

↓これで座標を変換しているらしい
NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution()

しかし、それでも若干ずれている気がする~で終わりました。 

今回はそれをとりあえず直すことをやってみます。



※プログラミングスキルは初心者なので間違いや無駄等あると思います。


事前にに保存した画像でなんやかんややるので下記のプログラムではKinectは使っていません。


#include <iostream>
#include <opencv2\opencv.hpp>

using namespace std;
using namespace cv;

int main(int argc, char* argv[]){

 Mat depth, depth2; //depth2:ズラす用
 int counter = 0;
 char readBuf[256];
 char writeBuf[256];

 //動画で書き出す用
 //double fps = 15;
 //VideoWriter wDepth("wDepth.avi", CV_FOURCC('D', 'I', 'B', ' '), fps, cv::Size(640, 480), true);

 while (1){

  //事前に保存した画像の読み込み
  /*
  保存時にファイル名に連番を振っていたので
  counterで番号を回しながら読み込んで行きます。
  自分の場合、別のディレクトリに保存していました。
  */
  sprintf_s(readBuf, "..\\元画像保存ディレクトリ\\ファイル名%04d.jpg", counter);

  depth = imread(readBuf);
  depth2 = Mat::zeros(480, 640, CV_8UC3); //とりあえず真っ黒を用意
 if (depth.data == NULL) break;

  for (int y = 0; y < depth.rows; y++){

   Vec3b* ptrDepth = depth.ptr<Vec3b>(y);
   Vec3b* ptrDepth2 = depth2.ptr<Vec3b>(y); //ズラす用

   for (int x = 0; x < depth.cols; x++){

    if (x + 13 < depth2.cols)
     ptrDepth2[x + 13] = ptrDepth[x]; //ここで右に13ズラす

   }
  }


  //表示
  cv::imshow("depth", depth);
  cv::imshow("depth2", depth2);


  //静止画で書き出す
  sprintf_s(writeBuf, "保存先ディレクトリ\\保存ファイル名%04d.jpg", counter); 
  imwrite(writeBuf, depth2);

  //動画で書き出す
  //wDepth << depth2;

  //キー入力
  int key = cv::waitKey(10);
  if (key == 'q') break;


  counter++;
 }//while

 //終了
 //wDepth.release();
 cv::destroyAllWindows();
}








実行結果
元画像:



ずらした画像:





別途編集ソフト使って重ね合わせてみる
color画像:



color画像と元depth画像:




color画像とズラしたdepth画像:







画素にアクセスして x について右にズラしただけです。

ずらしたものを静止画で保存しています。

元の深度画像とカラー画像を合わせてみると横方向にずれているように見えます。

それを単純に右にずらしました。なんとなく合ってるよね?

(もし、元画像の方でdepthとcolorで取得のタイミングが異なる場合は時間とかでラベル付けしたり肉眼で比較してみて合わせてだいたい同じタイミングの画像を探してみるとか。)


きっともっとスマートな方法があるのだと思いますが、勉強不足ゆえこんな感じです。

肉眼を頼りにずれを調節しているので、正確さは保障できないと思います。とりあえずです。



今回は以上。


---[追記]-----

ある論文(出典見失った;・・・たしか阪大かどこかだったような)によると
Kinectはカラーカメラとデプスカメラは非同期らしいので、そもそもズレがあるようです。
ただ、フレームを取得する間隔はどちらも一定で、その幅がカラーとデプスでは異なるようなのでズレが生じているらしいです。

まぁだから↑のように単純に座標をズラしただけじゃダメってことだと思います。

ただXBOX版の時の話なので、今はどうなのか・・・。また調べてみようと思います。

--------


参考:
http://d.akiroom.com/2012-06/opencv-pixel-read-write-get-set/
http://kassymemo.blogspot.jp/2011/09/opencv2cvmat.html











2014年9月25日木曜日

【kinect使ってみる。】

kinect v2だっけ?新しいバージョンが発売するそうだけど、それはwindows8専用らしいです。

でとりあえずwindows版とxbox版が手元に転がっていたのでこれらを使ってこれから遊んでいこうと思います。





試しにこのサンプルを使ってみます。

プレイヤーの認識とかは今回は使わないのでカットして、colorカメラの表示、depth座標をcolor座標に変換するのを加えてみました。

だいたいコピペです。
でも正しいかどうかは素人勉強中のためよくわかっていません。
プログラミングスキルもカスなのでご了承を。
逆にアドバイスもらえると嬉しいです。


環境:
windows7 64bit home premium
visual stadio 2013
openCV2.4.8
kinect for windows SDK v1.8


#include <Windows.h>
#include <NuiApi.h>

#include <iostream>
#include <conio.h>

#include <opencv2\opencv.hpp>

using namespace std;
using namespace cv;

void main()
{
 try {
  int count = 0;
  ::NuiGetSensorCount(&count);
  if (count == 0) {
   throw std::runtime_error("利用可能なKinectがありません");
  }

  INuiSensor* kinect;
  ::NuiCreateSensorByIndex(0, &kinect);

  //変更
  kinect->NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH | NUI_INITIALIZE_FLAG_USES_COLOR);

  //追加:colorHandle
  HANDLE depthHandle;
  HANDLE colorHandle;

  //追加
  //depth
  kinect->NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH, NUI_IMAGE_RESOLUTION_640x480, 0, 2, 0, &depthHandle);
  //color
  kinect->NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, 0, 2, 0, &colorHandle);

  DWORD width = 0;
  DWORD height = 0;
  ::NuiImageResolutionToSize(NUI_IMAGE_RESOLUTION_640x480, width, height);

  while (true) {
   // 距離カメラのフレームデータを取り出す
   NUI_IMAGE_FRAME depthFrame = { 0 };
   kinect->NuiImageStreamGetNextFrame(depthHandle, INFINITE, &depthFrame);
   
   //追加:colorカメラのフレームデータを取り出す
   NUI_IMAGE_FRAME colorFrame = { 0 };
   kinect->NuiImageStreamGetNextFrame(colorHandle, INFINITE, &colorFrame);

   // フレームデータを元に、拡張距離データを取得する
   BOOL nearMode = FALSE;
   INuiFrameTexture *frameTexture = 0;
   kinect->NuiImageFrameGetDepthImagePixelFrameTexture(
    depthHandle, &depthFrame, &nearMode, &frameTexture);
   //追加:color
   INuiFrameTexture *colorframeTexture = colorFrame.pFrameTexture;

   // NUI_DEPTH_IMAGE_PIXELを取り出す
   NUI_LOCKED_RECT rectDepth = { 0 }; //名前変えたrect→rectDepth
   frameTexture->LockRect(0, &rectDepth, 0, 0);

   //追加:カラー
   NUI_LOCKED_RECT rectColor = { 0 };
   colorframeTexture->LockRect(0, &rectColor, 0, 0);

   NUI_DEPTH_IMAGE_PIXEL* depthPixel = (NUI_DEPTH_IMAGE_PIXEL*)rectDepth.pBits;

   // 表示する
   cv::Mat cameraDepth(height, width, CV_8UC3);
   //追加
   cv::Mat cameraColor(height, width, CV_8UC4, reinterpret_cast<ushort*>(rectColor.pBits));

   for (int y = 0; y < height; ++y) {
    for (int x = 0; x < width; ++x) {
     int depthIndex = (y * width) + x;

     //追加
     unsigned char iro = depthPixel[depthIndex].depth * 255 / 1000;

     //追加:depthとcolorの位置合わせ    
     LONG colorX = 0;
     LONG colorY = 0;
     kinect->NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution(
      NUI_IMAGE_RESOLUTION_640x480, NUI_IMAGE_RESOLUTION_640x480,
      nullptr, x, y, 0, &colorX, &colorY );
     int cameraIndex = ((colorY * width) + colorX) * 3; 
     

     //追加
     //1mより遠い場合
     if (depthPixel[depthIndex].depth > 1000) {
      cameraDepth.data[cameraIndex] = 0;
      cameraDepth.data[cameraIndex + 1] = 0;
      cameraDepth.data[cameraIndex + 2] = 0;
     }
     else{ // 1mより近い場合
      cameraDepth.data[cameraIndex] = iro;
      cameraDepth.data[cameraIndex + 1] = iro;
      cameraDepth.data[cameraIndex + 2] = iro;
     }
    }
   } 

   imshow("depth", cameraDepth);
   //追加:カラー表示
   imshow("color", cameraColor);

   kinect->NuiImageStreamReleaseFrame(depthHandle, &depthFrame);
   //追加  
   kinect->NuiImageStreamReleaseFrame(colorHandle, &colorFrame);

   int key = cv::waitKey(10);
   if (key == 'q') {
    break;
   }
  }
 }
 catch (exception& ex) {
  cout << ex.what() << endl;
 }
}




実行結果(あるフレームでの)
Color:


Depth:


1mより先は黒で塗りつぶしています。
あと若干まだ座標のズレを感じます。距離画像の方が左に10画素くらい。


参考文献

2014年4月14日月曜日

OpenCV2.4.8インストール

忘備録。



Kinectを使うにあたりOpenCV2.4.8のインストールを行った。


基本的にはyoutubeにあがっていた動画↓通りに進めていく。





■環境
Windows7 Home Premium 64bit
Visual Studio 2013 for Windows Desktop


■1. OpenCV2.4.8をダウンロード。


■2. 任意のフォルダに展開。

今回はCドライブ下にフォルダを予め作成

C:\opencv

ここに解凍した。



展開後、C:\opencv\opnecvとなるので、今後の事も考え名前を変更

C:\opencv\248

とした。


■3. 環境変数の設定

「スタート」→「コンピュータ」を右クリック→「プロパティ」→「システムの詳細設定」→「環境変数」

「Path」を編集

末尾に

;C:\opencv\248\build\x86\vc12\bin

を追加。

※「;」を忘れず。


■4. Visual Studio 2013

□新しいプロジェクト


「新しいプロジェクト」→「Win32 コンソールアプリケーション Visual C++」

名前は適当につけて「OK」を。

何か小窓が出てくるので「次へ」→「空のプロジェクト」にチェックを入れる→「完了」



□プロパティシートの追加


上のメニューバーで「表示」→「その他のウィンドウ」→「プロパティ マネージャ」

「Debug | Win32」に「新しいプロジェクト プロパティシートの追加」→名前は適当に→「プロパティ」


「共通プロパティ」→「VC++ディレクトリ」

「実行可能ファイルディレクトリ」に

C:\opencv\248\build\x86\vc12\bin

を追加。

「ライブラリディレクトリ」に

C:\opencv\248\build\x86\vc12\lib

を追加。



次に「C/C++」→「全般」

「追加のインクルードディレクトリ」に

C:\opencv\248\build\include

を追加。


次に「リンカー」→「全般」

「追加のライブラリディレクトリ」に

C:\opencv\248\build\x86\vc12\lib

を追加。

「入力」

「追加の依存ファイル」に

opencv_calib3d248d.lib
opencv_contrib248d.lib
opencv_core248d.lib
opencv_features2d248d.lib
opencv_flann248d.lib
opencv_gpu248d.lib
opencv_highgui248d.lib
opencv_imgproc248d.lib
opencv_legacy248d.lib
opencv_ml248d.lib
opencv_nonfree248d.lib
opencv_objdetect248d.lib
opencv_ocl248d.lib
opencv_photo248d.lib
opencv_stitching248d.lib
opencv_superres248d.lib
opencv_ts248d.lib
opencv_video248d.lib
opencv_videostab248d.lib

※C:\opencv\248\build\x86\vc12\libに入っているもの。「*d.lib」となっているファイル。

Release版は d がついてない方?

を追加。

「適用」→「OK」で終了。

■Sampleの実行

ソースファイルに任意のSampleファイル追加し、ビルドして実行。

C:\opencv\248\sources\samples\cpp

にある。

動画ではdrawing.cpp


※失敗するときはWindows SDK 7.1かなにかでなんやかんやすれば怒られないらしい。


以上。