1

OpenCV 2.4.0に組み込まれているOpenNIアクセスで遊んでいて、深度マップの2点間の距離を測定しようとしています。私はこれまでこれを試しました:

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

Point startPt(0,0);
Point endPt(0,0);

void onMouse( int event, int x, int y, int flags, void* )
{
    if( event == CV_EVENT_LBUTTONUP) startPt = Point(x,y);
    if( event == CV_EVENT_RBUTTONUP) endPt   = Point(x,y);
}

int main( int argc, char* argv[] ){
    VideoCapture capture;
    capture.open(CV_CAP_OPENNI);
    //capture.set( CV_CAP_PROP_OPENNI_REGISTRATION , 0);
    unsigned t0=clock();
    if( !capture.isOpened() ){
        cout << "Can not open a capture object." << endl;
        return -1;
    }
    unsigned elapsed=clock()-t0;
    cout << "initialized in "<< elapsed <<" s. ready!" << endl;
    namedWindow( "depth", 1 );
    setMouseCallback( "depth", onMouse, 0 );
    for(;;){
        Mat depthMap;
        if( !capture.grab() ){
            cout << "Can not grab images." << endl;
            return -1;
        }else{
            Mat show,real,valid;
            if( capture.retrieve( depthMap, CV_CAP_OPENNI_DEPTH_MAP ) ){
                depthMap.convertTo( show, CV_8UC1, 0.05f);
            }
            capture.retrieve(valid,CV_CAP_OPENNI_VALID_DEPTH_MASK);
            if( capture.retrieve(real, CV_CAP_OPENNI_POINT_CLOUD_MAP)){
                unsigned int sp = valid.at<unsigned char>(startPt.x, startPt.y);
                unsigned int ep = valid.at<unsigned char>(endPt.x, endPt.y);
                if(sp == 255 && ep == 255){
                    Vec3f s = real.at<Vec3f>(startPt.x, startPt.y);
                    Vec3f e = real.at<Vec3f>(endPt.x, endPt.y);
                    float dx = e[0]-s[0];
                    float dy = e[1]-s[1];
                    float dz = e[2]-s[2];
                    float dist = sqrt(dx*dx + dy*dy + dz*dz);
                    putText(show,format("distance: %f m\n",dist),Point(10,10),FONT_HERSHEY_PLAIN,1,Scalar(255));
                }
            }
            circle(show,startPt,3,Scalar(255),3);
            circle(show,endPt,3,Scalar(192),3);
            line(show,startPt,endPt,Scalar(128));
            imshow("depth",show);
        }
        if( waitKey( 30 ) >= 0 )    break;
    }

}

しかし、私にはいくつかの問題があります:

  1. 最初に有効な深度マスクの値をチェックしない限り、プログラムがクラッシュすることがあります(データが悪いためだと思います)
  2. 点群マップがメートル単位のXYZデータ(CV_32FC3)を返すことを理解している限り、画面に表示される数値は間違って見えます。

xyz値を取得して距離を計算する正しい方法を使用していますか?

私が見逃しているかもしれない詳細はありますか?

4

1 に答える 1

4
  1. コードを実行しましたが、コメントアウトしてもクラッシュさせることができませんでしたif(sp == 255 && ep == 255)。それは頻繁に起こりますか?私はOpenNIドライバーを使用していませんが、たとえばMicrosoftドライバーには、無効な値もあります(たとえば、表面が鏡面反射である場合)。「近すぎる」または「遠すぎる」にも異なる値があります。そのような場合、OpenNIがゴミを返すということでしょうか?

  2. xとyを切り替えてみてください。

    Vec3f s = real.at<Vec3f>(startPt.y, startPt.x);        
    Vec3f e = real.at<Vec3f>(endPt.y, endPt.x);        
    

(そして結果として:)

unsigned int sp = valid.at<unsigned char>(startPt.y, startPt.x);
unsigned int ep = valid.at<unsigned char>(endPt.y, endPt.x);

構文は cv::Mat::at<_Tp>(int y, int x)、またはそれがあなたをより良く助けるなら、 cv::Mat::at<_Tp>(int row, int column) 私はいくつかの距離を測定しました、そしてそれは私にとってうまくいきました。

また、実際に取得するすべてのフレームの3Dポイントと距離を計算しますが、それは意図的なものですか?画像内で2つの2Dポイントを一度選択しても、距離の計算に使用する対応する3Dポイントは、ノイズのためにフレームごとに変化する可能性があるためです。

于 2012-08-16T00:02:00.140 に答える