Kinectでユーザーの座標を検出するには?

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
ジュンヤ
記事: 8
登録日時: 14年前
住所: 東京都
連絡を取る:

Kinectでユーザーの座標を検出するには?

#1

投稿記事 by ジュンヤ » 14年前

「Kinectセンサープログラミング」のサンプルで、
p128のユーザーのスケルトンを作成するという項目のプログラムとまったく同じ
物を作りました。
↓でサンプルと同じ物です。
http://d.hatena.ne.jp/kaorun55/20110523/1306140845

このプログラム自体は、実行できてちゃんと動くし、デプスマップも正常に作成されてます。
しかしユーザーの座標を取得したいと思ってるんですが、
ポーズの検出が上手くいかずスケルトンを描画できない状況です。
いくらやっても235行目のif (skelton.IsTracking(aUsers))の条件式が通らないので、
トラッキングに失敗してるのだと思うんですが・・
ちょっとした情報でもいいので、教えていただければ幸いです。

コード:

#include <iostream>
#include <stdexcept>
#include <vector>

#include <opencv/cv.h>
#include <opencv/highgui.h>

#include <XnCppWrapper.h>

#include "SkeltonDrawer.h"
#include "PoseDetector.h"

const char* CONFIG_XML_PATH = "SamplesConfig.xml";

typedef std::vector<float> depth_hist;

// ユーザーの色づけ
const XnFloat Colors[][3] =
{
  {1,1,1},    // ユーザーなし
  {0,1,1},  {0,0,1},  {0,1,0},
  {1,1,0},  {1,0,0},  {1,.5,0},
  {.5,1,0}, {0,.5,1}, {.5,0,1},
  {1,1,.5},
};

// ユーザー検出
void XN_CALLBACK_TYPE UserDetected(xn::UserGenerator& generator,
  XnUserID nId, void* pCookie)
{
  std::cout << "ユーザー検出:" << nId << " " <<
    generator.GetNumberOfUsers() << "人目" << std::endl;

  XnChar* pose = (XnChar*)pCookie;
  if (pose[0] != '\0') {
    generator.GetPoseDetectionCap().StartPoseDetection(pose, nId);
  }
  else {
    generator.GetSkeletonCap().RequestCalibration(nId, TRUE);
  }
}

// ユーザー消失
void XN_CALLBACK_TYPE UserLost(xn::UserGenerator& generator,
  XnUserID nId, void* pCookie)
{
  std::cout << "ユーザー消失:" << nId << std::endl;
}

// ポーズ検出
void XN_CALLBACK_TYPE PoseDetected(xn::PoseDetectionCapability& capability,
  const XnChar* strPose, XnUserID nId, void* pCookie)
{
  std::cout << "ポーズ検出:" << strPose << " ユーザー:" << nId << std::endl;

  xn::UserGenerator* user = (xn::UserGenerator*)pCookie;
  user->GetPoseDetectionCap().StopPoseDetection(nId);
  user->GetSkeletonCap().RequestCalibration(nId, TRUE);
}

// ポーズ消失
void XN_CALLBACK_TYPE PoseLost(xn::PoseDetectionCapability& capability,
  const XnChar* strPose, XnUserID nId, void* pCookie)
{
  std::cout << "ポーズ消失:" << strPose << " ユーザー:" << nId << std::endl;
}

// キャリブレーションの開始
void XN_CALLBACK_TYPE CalibrationStart(xn::SkeletonCapability& capability,
  XnUserID nId, void* pCookie)
{
  std::cout << "キャリブレーション開始。ユーザー:" << nId << std::endl;
}

// キャリブレーションの終了
void XN_CALLBACK_TYPE CalibrationEnd(xn::SkeletonCapability& capability,
  XnUserID nId, XnBool bSuccess, void* pCookie)
{
  xn::UserGenerator* user = (xn::UserGenerator*)pCookie;

  // キャリブレーション成功
  if (bSuccess) {
    std::cout << "キャリブレーション成功。ユーザー:" << nId << std::endl;
    user->GetSkeletonCap().StartTracking(nId);
  }
  // キャリブレーション失敗
  else {
    std::cout << "キャリブレーション失敗。ユーザー:" << nId << std::endl;
  }
}

// RGBピクセルの初期化
inline XnRGB24Pixel xnRGB24Pixel( int r, int g, int b )
{
  XnRGB24Pixel pixel = { r, g, b };
  return pixel;
}

int main (int argc, char * argv[])
{
  IplImage* camera = 0;

  try {
    // コンテキストの初期化
    xn::Context context;
    XnStatus rc = context.InitFromXmlFile(CONFIG_XML_PATH);
    if (rc != XN_STATUS_OK) {
      throw std::runtime_error(xnGetStatusString(rc));
    }

    // イメージジェネレータの作成
    xn::ImageGenerator image;
    rc = context.FindExistingNode(XN_NODE_TYPE_IMAGE, image);
    if (rc != XN_STATUS_OK) {
      throw std::runtime_error(xnGetStatusString(rc));
    }

    // デプスジェネレータの作成
    xn::DepthGenerator depth;
    rc = context.FindExistingNode(XN_NODE_TYPE_DEPTH, depth);
    if (rc != XN_STATUS_OK) {
      throw std::runtime_error(xnGetStatusString(rc));
    }

    // デプスの座標をイメージに合わせる
    depth.GetAlternativeViewPointCap().SetViewPoint(image);

    // ユーザーの作成
    xn::UserGenerator user;
    rc = context.FindExistingNode( XN_NODE_TYPE_USER, user );
    if ( rc != XN_STATUS_OK ) {
      rc = user.Create(context);
      if ( rc != XN_STATUS_OK ) {
        throw std::runtime_error( xnGetStatusString( rc ) );
      }
    }

    // ユーザー検出機能をサポートしているか確認
    if (!user.IsCapabilitySupported(XN_CAPABILITY_SKELETON)) {
      throw std::runtime_error("ユーザー検出をサポートしてません");
    }

    XnCallbackHandle userCallbacks, calibrationCallbacks, poseCallbacks;
    XnChar pose[20] = "";

    // キャリブレーションにポーズが必要
    xn::SkeletonCapability skelton = user.GetSkeletonCap();
    if (skelton.NeedPoseForCalibration()) {
      // ポーズ検出のサポートチェック
      if (!user.IsCapabilitySupported(XN_CAPABILITY_POSE_DETECTION)) {
        throw std::runtime_error("ポーズ検出をサポートしてません");
      }

      // キャリブレーションポーズの取得
      skelton.GetCalibrationPose(pose);

      // ポーズ検出のコールバックを登録
      xn::PoseDetectionCapability pose = user.GetPoseDetectionCap();
      pose.RegisterToPoseCallbacks(&::PoseDetected, &::PoseLost,
        &user, poseCallbacks);
    }

    // ユーザー認識のコールバックを登録
    user.RegisterUserCallbacks(&::UserDetected, &::UserLost, pose,
      userCallbacks);

    // キャリブレーションのコールバックを登録
    skelton.RegisterCalibrationCallbacks(&::CalibrationStart, &::CalibrationEnd,
      &user, calibrationCallbacks);

    // ユーザートラッキングで、すべてをトラッキングする
    skelton.SetSkeletonProfile(XN_SKEL_PROFILE_ALL);

    // ジェスチャー検出の開始
    context.StartGeneratingAll();

    // カメラサイズのイメージを作成(8bitのRGB)
    XnMapOutputMode outputMode;
    image.GetMapOutputMode(outputMode);
    camera = ::cvCreateImage(cvSize(outputMode.nXRes, outputMode.nYRes),
      IPL_DEPTH_8U, 3);
    if (!camera) {
      throw std::runtime_error("error : cvCreateImage");
    }

    // 表示状態
    bool isShowImage = true;
    bool isShowUser = true;
    bool isShowSkelton = true;

    // メインループ
    while (1) {
      // すべてのノードの更新を待つ
      context.WaitAndUpdateAll();

      // 画像データの取得
      xn::ImageMetaData imageMD;
      image.GetMetaData(imageMD);

      // ユーザーデータの取得
      xn::SceneMetaData sceneMD;
      user.GetUserPixels(0, sceneMD);

      // カメラ画像の表示
      char* dest = camera->imageData;
      const xn::RGB24Map& rgb = imageMD.RGB24Map();
      for (int y = 0; y < imageMD.YRes(); ++y) {
        for (int x = 0; x < imageMD.XRes(); ++x) {
          // ユーザー表示
          XnLabel label = sceneMD(x, y);
          if (!isShowUser) {
            label = 0;
          }

          // カメラ画像の表示
          XnRGB24Pixel pixel = rgb(x, y);
          if (!isShowImage) {
            pixel = xnRGB24Pixel( 255, 255, 255 );
          }

          // 出力先に描画
          dest[0] = pixel.nRed   * Colors[label][0];
          dest[1] = pixel.nGreen * Colors[label][1];
          dest[2] = pixel.nBlue  * Colors[label][2];
          dest += 3;
        }
      }

      // スケルトンの描画
      if (isShowSkelton) {
        XnUserID aUsers[15];
        XnUInt16 nUsers = 15;
        user.GetUsers(aUsers, nUsers);
        for (int i = 0; i < nUsers; ++i) {
          if (skelton.IsTracking(aUsers[i])) {
            SkeltonDrawer skeltonDrawer(camera, skelton,
              depth, aUsers[i]);
            skeltonDrawer.draw();

            PoseDetector pose(camera, skelton, depth, aUsers[i]);
            bool isCross = pose.detect();
          }
        }
      }

      ::cvCvtColor(camera, camera, CV_BGR2RGB);
      ::cvShowImage("KinectImage", camera);

      // キーイベント
      char key = cvWaitKey(10);
      // 終了する
      if (key == 'q') {
        break;
      }
      // 表示する/しないの切り替え
      else if (key == 'i') {
        isShowImage = !isShowImage;
      }
      else if (key == 'u') {
        isShowUser = !isShowUser;
      }
      else if (key == 's') {
        isShowSkelton = !isShowSkelton;
      }
    }
  }
  catch (std::exception& ex) {
    std::cout << ex.what() << std::endl;
  }

  ::cvReleaseImage(&camera);

  return 0;
}

アバター
Dixq (管理人)
管理人
記事: 1662
登録日時: 15年前
住所: 北海道札幌市
連絡を取る:

Re: Kinectでユーザーの座標を検出するには?

#2

投稿記事 by Dixq (管理人) » 14年前

Kinectポーズをしてもずっとキャリブレーション中のままで、トラッキング中にならないということでよかったでしょうか。

私もよくありました。
ポーズは両手を上げるというより、私の場合、手と腕を90度にするような感じ(ボディービルダーみたいな感じ?)の恥ずかしい恰好の方が検出しやすかったです(w

MMDでキネクトを動かせることはご存じだと思いますので、そちらでまず確認してみてはいかがでしょう。
MMDでKinect有効にし、Kinectポーズを取ってMMDが動き始めればキャリブレーション完了です。

アバター
ジュンヤ
記事: 8
登録日時: 14年前
住所: 東京都
連絡を取る:

Re: Kinectでユーザーの座標を検出するには?

#3

投稿記事 by ジュンヤ » 14年前

即解決しました!プログラムの問題とかじゃなくてポーズの問題でした~
キューさんの言われた通り、ボディービルダーみたいな恥ずかしいポーズをとることで、プログラム上でもMMDでも
うまくトラッキング状態に移行できました。

公式SDKではどんなポーズしててもすぐにトラッキング状態に移行してましたので、ここまでシビアだとは思いませんでした。引き続き制作を続けようと思いますので、わからないところがあったらまたよろしくお願いします。
ありがとうございました!

閉鎖

“C言語何でも質問掲示板” へ戻る