cvl-robot's diary

研究ノート メモメモ https://github.com/dotchang/

LeapMotion v2.1に更新したofxLeapMotionでCamera Imagesの表示

 

(メモ)

LeapMotionの生画像取得APIがv2.1~公開されたそうなので、テストしてみます。

Dev向けSDKのV2.1のincludeとlibをofxLeapMotionの既存の物と置き換える。

PIなどの定数定義で引っかかるので、#ifndef~#endifで囲む。

 

ofxLeapMotion.h

//Raw Images
void setPolicyFlags();
void getRawImages();
void getDistorionImages();
ofImage surface[2];
ofImage distortion[2];

ofxLeapMotion.cpp

//Raw Images
void ofxLeapMotion::setPolicyFlags(){
Controller::PolicyFlag addImagePolicy = (Controller::PolicyFlag)(Controller::PolicyFlag::POLICY_IMAGES | ourController->policyFlags());
ourController->setPolicyFlags(addImagePolicy);
}

 

void ofxLeapMotion::getRawImages()
{
//Uses Cinder OpenGL wrapper
Leap::Frame frame = ourController->frame();

ImageList images = frame.images();
for(int i = 0; i < 2; i++){
Image image = images[i];

const unsigned char* image_buffer = image.data();

//Draw the raw image data as a greyscale bitmap
int cursor = 0;
for(int h=0; h<image.height(); h++){
for(int w=0; w<image.width(); w++){
surface[i].setColor(w,h,ofColor_<unsigned char>(image_buffer[cursor]));
cursor++;
}
}
surface[i].reloadTexture();
//surface[i].saveImage(string("raw") + to_string(i) + string(".jpg"));

//Surface surface(image.width(), image.height(), image.width() * 4, SurfaceChannelOrder::RGBA);
//int cursor = 0;
//Surface::Iter iter = surface.getIter();
//while( iter.line() ) {
// while( iter.pixel() ) {
// iter.r() = image_buffer[cursor];
// iter.g() = iter.b() = iter.r();
// iter.a() = 255;
// cursor++;
// }
//}
}
}

 

testApp.cpp

update関数の中

leap.getRawImages();

//IMPORTANT! - tell ofxLeapMotion that the frame is no longer new.
leap.markFrameAsOld();

draw()関数の中

ofEnableLighting();
l1.enable();
l2.enable();

leap.surface[0].draw(-400,100, 320, 240);
leap.surface[1].draw(80,100, 320, 240);

m1.begin();
m1.setShininess(0.6);

 

f:id:cvl-robot:20140822215743p:plain

同様に、サンプルをちょっといじってofImageに合わせて、

void ofxLeapMotion::getRectifiedImages()
{
  //Uses Cinder OpenGL wrapper
  Leap::Frame frame = ourController->frame();

  //Draw the undistorted image using the warp() function
  int targetWidth = 400;
  int targetHeight = 400;

  //Iterate over target image pixels, converting xy to ray slope
  unsigned char brightness[4] = {0,0,0,255}; //An array to hold the rgba color components

  for(int i=0; i<2; i++){
    ImageList images = frame.images();
    for(int h=0; h<targetHeight; h++){
      for(int w=0; w<targetWidth; w++){
        //Normalize from pixel xy to range [0..1]
        Vector input = Vector( (float)w/targetWidth, (float)h/targetHeight, 0);

       //Convert from normalized [0..1] to slope [-4..4]
       input.x = (input.x - images[i].rayOffsetX()) / images[i].rayScaleX();
       input.y = (input.y - images[i].rayOffsetY()) / images[i].rayScaleY();

       Vector pixel = images[i].warp(input);

       if(pixel.x >= 0 && pixel.x < images[i].width() && pixel.y >= 0 && pixel.y < images[i].height()) {
         int data_index = floor(pixel.y) * images[i].width() + floor(pixel.x); //xy to buffer index
         brightness[0] = images[i].data()[data_index]; //Look up brightness value
         brightness[2] = brightness[1] = brightness[0]; //Greyscale
       } else {
         brightness[0] = 255; //Display invalid pixels as red
         brightness[2] = brightness[1] = 0;
       }
       distortion[i].setColor(w,h,ofColor(brightness[0], brightness[1], brightness[2]));
      }
    }
    distortion[i].reloadTexture();
    //distortion[i].saveImage(string("distortion") + to_string(i) + string(".jpg"));
  }

}

f:id:cvl-robot:20140825133747p:plain

処理速度はとっても遅いので、cv::remap風に処理するか、GPUのexampleを参考に書き直した方が実用的です。

 

速さは多少マシバージョン。

std::vector<std::vector<int> > rectified_map;

を.hに追加。

void ofxLeapMotion::getRectifiedImages()
{
  //Uses Cinder OpenGL wrapper
  Leap::Frame frame = ourController->frame();

  //Draw the undistorted image using the warp() function
  static const int targetWidth = 400;
  static const int targetHeight = 400;

  static bool init_map = false;

  ImageList images = frame.images();
  if(!init_map){

    if(images[0].width() != 0){
    rectified_map.resize(2);
    for(int i=0; i<2; i++){
      rectified_map[i].resize(targetWidth*targetHeight);
      for(int h=0; h<targetHeight; h++){
        for(int w=0; w<targetWidth; w++){
          //Normalize from pixel xy to range [0..1]
          Vector input = Vector( (float)w/targetWidth, (float)h/targetHeight, 0);

          //Convert from normalized [0..1] to slope [-4..4]
          input.x = (input.x - images[i].rayOffsetX()) / images[i].rayScaleX();
          input.y = (input.y - images[i].rayOffsetY()) / images[i].rayScaleY();

          Vector pixel = images[i].warp(input);

          if(pixel.x >= 0 && pixel.x < images[i].width() && pixel.y >= 0 && pixel.y < images[i].height()) {
            int data_index = floor(pixel.y) * images[i].width() + floor(pixel.x); //xy to buffer index
            rectified_map[i][h*targetWidth+w] = data_index; //Look up brightness value
          } else {
            rectified_map[i][h*targetWidth+w] = -1;
           }
         }
      }
    }
    init_map = true;

    }

    else return;
  }

  //Iterate over target image pixels, converting xy to ray slope
  unsigned char brightness[4] = {0,0,0,255}; //An array to hold the rgba color components

  for(int i=0; i<2; i++){
    ImageList images = frame.images();
    for(int h=0; h<targetHeight; h++){
      for(int w=0; w<targetWidth; w++){
        if(rectified_map[i][h*targetWidth+w]>=0){
          brightness[0] = images[i].data()[rectified_map[i][h*targetWidth+w]]; //Look up brightness value
          brightness[2] = brightness[1] = brightness[0]; //Greyscale
        }
        else{
          brightness[0] = 255; //Display invalid pixels as red
          brightness[2] = brightness[1] = 0;
        }
        distortion[i].setColor(w,h,ofColor(brightness[0], brightness[1], brightness[2]));
      }
    }
    distortion[i].reloadTexture();
  }

}

 

[1] Camera Images — Leap Motion C++ SDK v2.1.0 Beta documentation

[2] Leap Motionのカメラ画像を取得する[C++] - Build Insider