2012-01-26 7 views
29

私はこの分野では新しく、2D画像から3Dで単純なシーンをモデル化しようとしていますが、カメラに関する情報はありません。私は3 optionsがあることを知っている:カメラに関する情報のない2枚の画像からの再構築

  • が、私は2枚の画像を持っていると私は私のカメラ(intrisics)のモデルを知っている私は、インスタンスloadXMLFromFile() =>stereoRectify() =>reprojectImageTo3D()

  • 私のためにXMLからロードされていますそれらを持っていないが、私は調整することができます私のカメラ=>stereoCalibrate() =>stereoRectify() =>reprojectImageTo3D()

  • 私が撮影したカメラを持っていないので、私は、それは私の場合です(カメラを校正することはできません2 i例えば、私はSURF、SIFTを使って両方の画像上に対のキーポイントを見つけ(実際にはブロブ検出器を使うことができます)、これらのキーポイントのディスクリプタを計算し、ディスクリプタに従って画像の右と左の画像からキーポイントをマッチングさせ、それらから基本行列を見つける。処理がはるかに困難であり、このようなものだ:

    1. 検出キーポイント(SURF、SIFT)=>
    2. 抽出ディスクリプタ(SURF、SIFT)=>
    3. コンペアマッチ記述子(ブルートフォース、FLANNはベースアプローチ)=>
    4. これらの対からの基本的なマット(findFundamentalMat())を見つける=>
    5. stereoRectifyUncalibrated() =>
    6. reprojectImageTo3D()

私は最後のアプローチを使用していて、私の質問は次のとおりです。

1)は、右か?

2)大丈夫なら、私は最後のステップについて疑問を持っていますstereoRectifyUncalibrated() =>reprojectImageTo3D()reprojectImageTo3D()関数のシグネチャは次のとおり

void reprojectImageTo3D(InputArray disparity, OutputArray _3dImage, InputArray Q, bool handleMissingValues=false, int depth=-1) 

cv::reprojectImageTo3D(imgDisparity8U, xyz, Q, true) (in my code) 

パラメータ:

  • disparity - 入力単一チャネルの8ビットの符号なし、16ビット、32ビットの符号付きまたは符号付き32ビット浮動小数点視差画像。
  • _3dImage - 同じサイズの出力3チャネル浮動小数点画像。disparity_3dImage(x,y)の各要素には、視差マップから計算された点(x,y)の3D座標が含まれています。
  • Q - stereoRectify()で得られる4x4透視変換行列です。
  • handleMissingValues - 関数が欠損値(すなわち、視差が計算されなかった点)を処理する必要があるかどうかを示します。 handleMissingValues=trueの場合、外れ値に対応する最小視差を持つピクセル(StereoBM::operator()を参照)は、非常に大きなZ値(現在10000に設定されている)を持つ3Dポイントに変換されます。
  • ddepth - オプションの出力配列の深さです。-1の場合、出力イメージの深さはCV_32Fになります。 ddepthは、CV_16S,CV_32Sまたは `CV_32F 'に設定することもできます。

Qマトリックスを取得するにはどうすればよいですか? F,H1およびH2などの方法で、あるいは別の方法でQ行列を得ることは可能ですか?

3)カメラを較正せずにxyz座標を取得する別の方法はありますか?

私のコードは次のとおり

#include <opencv2/core/core.hpp> 
#include <opencv2/calib3d/calib3d.hpp> 
#include <opencv2/imgproc/imgproc.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/contrib/contrib.hpp> 
#include <opencv2/features2d/features2d.hpp> 
#include <stdio.h> 
#include <iostream> 
#include <vector> 
#include <conio.h> 
#include <opencv/cv.h> 
#include <opencv/cxcore.h> 
#include <opencv/cvaux.h> 


using namespace cv; 
using namespace std; 

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

    // Read the images 
    Mat imgLeft = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); 
    Mat imgRight = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE); 

    // check 
    if (!imgLeft.data || !imgRight.data) 
      return 0; 

    // 1] find pair keypoints on both images (SURF, SIFT)::::::::::::::::::::::::::::: 

    // vector of keypoints 
    std::vector<cv::KeyPoint> keypointsLeft; 
    std::vector<cv::KeyPoint> keypointsRight; 

    // Construct the SURF feature detector object 
    cv::SiftFeatureDetector sift(
      0.01, // feature threshold 
      10); // threshold to reduce 
       // sensitivity to lines 
       // Detect the SURF features 

    // Detection of the SIFT features 
    sift.detect(imgLeft,keypointsLeft); 
    sift.detect(imgRight,keypointsRight); 

    std::cout << "Number of SURF points (1): " << keypointsLeft.size() << std::endl; 
    std::cout << "Number of SURF points (2): " << keypointsRight.size() << std::endl; 

    // 2] compute descriptors of these keypoints (SURF,SIFT) :::::::::::::::::::::::::: 

    // Construction of the SURF descriptor extractor 
    cv::SurfDescriptorExtractor surfDesc; 

    // Extraction of the SURF descriptors 
    cv::Mat descriptorsLeft, descriptorsRight; 
    surfDesc.compute(imgLeft,keypointsLeft,descriptorsLeft); 
    surfDesc.compute(imgRight,keypointsRight,descriptorsRight); 

    std::cout << "descriptor matrix size: " << descriptorsLeft.rows << " by " << descriptorsLeft.cols << std::endl; 

    // 3] matching keypoints from image right and image left according to their descriptors (BruteForce, Flann based approaches) 

    // Construction of the matcher 
    cv::BruteForceMatcher<cv::L2<float> > matcher; 

    // Match the two image descriptors 
    std::vector<cv::DMatch> matches; 
    matcher.match(descriptorsLeft,descriptorsRight, matches); 

    std::cout << "Number of matched points: " << matches.size() << std::endl; 


    // 4] find the fundamental mat :::::::::::::::::::::::::::::::::::::::::::::::::::: 

    // Convert 1 vector of keypoints into 
    // 2 vectors of Point2f for compute F matrix 
    // with cv::findFundamentalMat() function 
    std::vector<int> pointIndexesLeft; 
    std::vector<int> pointIndexesRight; 
    for (std::vector<cv::DMatch>::const_iterator it= matches.begin(); it!= matches.end(); ++it) { 

     // Get the indexes of the selected matched keypoints 
     pointIndexesLeft.push_back(it->queryIdx); 
     pointIndexesRight.push_back(it->trainIdx); 
    } 

    // Convert keypoints into Point2f 
    std::vector<cv::Point2f> selPointsLeft, selPointsRight; 
    cv::KeyPoint::convert(keypointsLeft,selPointsLeft,pointIndexesLeft); 
    cv::KeyPoint::convert(keypointsRight,selPointsRight,pointIndexesRight); 

    /* check by drawing the points 
    std::vector<cv::Point2f>::const_iterator it= selPointsLeft.begin(); 
    while (it!=selPointsLeft.end()) { 

      // draw a circle at each corner location 
      cv::circle(imgLeft,*it,3,cv::Scalar(255,255,255),2); 
      ++it; 
    } 

    it= selPointsRight.begin(); 
    while (it!=selPointsRight.end()) { 

      // draw a circle at each corner location 
      cv::circle(imgRight,*it,3,cv::Scalar(255,255,255),2); 
      ++it; 
    } */ 

    // Compute F matrix from n>=8 matches 
    cv::Mat fundemental= cv::findFundamentalMat(
      cv::Mat(selPointsLeft), // points in first image 
      cv::Mat(selPointsRight), // points in second image 
      CV_FM_RANSAC);  // 8-point method 

    std::cout << "F-Matrix size= " << fundemental.rows << "," << fundemental.cols << std::endl; 

    /* draw the left points corresponding epipolar lines in right image 
    std::vector<cv::Vec3f> linesLeft; 
    cv::computeCorrespondEpilines(
      cv::Mat(selPointsLeft), // image points 
      1,      // in image 1 (can also be 2) 
      fundemental,   // F matrix 
      linesLeft);    // vector of epipolar lines 

    // for all epipolar lines 
    for (vector<cv::Vec3f>::const_iterator it= linesLeft.begin(); it!=linesLeft.end(); ++it) { 

     // draw the epipolar line between first and last column 
     cv::line(imgRight,cv::Point(0,-(*it)[2]/(*it)[1]),cv::Point(imgRight.cols,-((*it)[2]+(*it)[0]*imgRight.cols)/(*it)[1]),cv::Scalar(255,255,255)); 
    } 

    // draw the left points corresponding epipolar lines in left image 
    std::vector<cv::Vec3f> linesRight; 
    cv::computeCorrespondEpilines(cv::Mat(selPointsRight),2,fundemental,linesRight); 
    for (vector<cv::Vec3f>::const_iterator it= linesRight.begin(); it!=linesRight.end(); ++it) { 

     // draw the epipolar line between first and last column 
     cv::line(imgLeft,cv::Point(0,-(*it)[2]/(*it)[1]), cv::Point(imgLeft.cols,-((*it)[2]+(*it)[0]*imgLeft.cols)/(*it)[1]), cv::Scalar(255,255,255)); 
    } 

    // Display the images with points and epipolar lines 
    cv::namedWindow("Right Image Epilines"); 
    cv::imshow("Right Image Epilines",imgRight); 
    cv::namedWindow("Left Image Epilines"); 
    cv::imshow("Left Image Epilines",imgLeft); 
    */ 

    // 5] stereoRectifyUncalibrated():::::::::::::::::::::::::::::::::::::::::::::::::: 

    //H1, H2 – The output rectification homography matrices for the first and for the second images. 
    cv::Mat H1(4,4, imgRight.type()); 
    cv::Mat H2(4,4, imgRight.type()); 
    cv::stereoRectifyUncalibrated(selPointsRight, selPointsLeft, fundemental, imgRight.size(), H1, H2); 


    // create the image in which we will save our disparities 
    Mat imgDisparity16S = Mat(imgLeft.rows, imgLeft.cols, CV_16S); 
    Mat imgDisparity8U = Mat(imgLeft.rows, imgLeft.cols, CV_8UC1); 

    // Call the constructor for StereoBM 
    int ndisparities = 16*5;  // < Range of disparity > 
    int SADWindowSize = 5;  // < Size of the block window > Must be odd. Is the 
            // size of averaging window used to match pixel 
            // blocks(larger values mean better robustness to 
            // noise, but yield blurry disparity maps) 

    StereoBM sbm(StereoBM::BASIC_PRESET, 
     ndisparities, 
     SADWindowSize); 

    // Calculate the disparity image 
    sbm(imgLeft, imgRight, imgDisparity16S, CV_16S); 

    // Check its extreme values 
    double minVal; double maxVal; 

    minMaxLoc(imgDisparity16S, &minVal, &maxVal); 

    printf("Min disp: %f Max value: %f \n", minVal, maxVal); 

    // Display it as a CV_8UC1 image 
    imgDisparity16S.convertTo(imgDisparity8U, CV_8UC1, 255/(maxVal - minVal)); 

    namedWindow("windowDisparity", CV_WINDOW_NORMAL); 
    imshow("windowDisparity", imgDisparity8U); 


    // 6] reprojectImageTo3D() ::::::::::::::::::::::::::::::::::::::::::::::::::::: 

    //Mat xyz; 
    //cv::reprojectImageTo3D(imgDisparity8U, xyz, Q, true); 

    //How can I get the Q matrix? Is possibile to obtain the Q matrix with 
    //F, H1 and H2 or in another way? 
    //Is there another way for obtain the xyz coordinates? 

    cv::waitKey(); 
    return 0; 
} 
+0

Fabio - language? – Tim

+0

@Tim C++ with OpenCV2.3.1 – Fobi

+0

私はそれはだと思いますが、あなたは何かが欠けています。不一致はいくつかの関数で得ることができます。あなたはopenCVのドキュメントをチェックする必要があります。 http://opencv.willowgarage.com/documentation/camera_calibration_and_3d_reconstruction.html –

答えて

4

StereoRectifyUncalibratedは、オブジェクト空間に単に平面透視変換しない整流変換を計算します。この平面変換をオブジェクト空間変換に変換してQ matriceを抽出する必要があります。カメラの校正パラメータの一部がカメラの組み込み関数のように必要であると思います。このテーマについては、いくつかの研究課題があるかもしれません。

カメラの組み込み関数を推定し、カメラの相対的な向きを抽出してフローが正しく動作するようにするための手順を追加している場合があります。私はカメラの較正のパラメータは、アクティブな照明方法が使用されていない場合は、シーンの適切な3D構造を抽出するために不可欠であると思います。

また、すべての推定値をより正確な値に絞り込むには、バンドルブロック調整ベースのソリューションが必要です。

2
  1. 手順はわかりました。

  2. 私が知る限り、画像ベースの3Dモデリングに関して、カメラは明示的に較正されているか、暗黙的に較正されています。カメラを明示的に較正する必要はありません。あなたはとにかくそれらのものを利用します。対応する点の対を照合することは、明らかに多用されるアプローチである。

1

私はあなたがあなたのイメージを是正し、この関数は二つのパラメータ(RおよびT)2台のカメラ間の回転と移動を必要とするQ. を取得するためにStereoRectifyを使用する必要があると思います。 したがって、solvePnPを使用してパラメータを計算することができます。この関数は、あるオブジェクトの3D実座標と画像内の2次元点とそれに対応する点を必要とします。

関連する問題