2012-01-26 13 views
29

Sono nuovo in questo campo e sto cercando di modellare una semplice scena in 3d con le immagini 2D e non ho informazioni sulle telecamere. So che ci sono 3 options:ricostruzione 3D da 2 immagini senza informazioni sulla fotocamera

  • ho due immagini e so il modello della mia macchina fotografica (intrisics) che ho caricato da un XML per esempio loadXMLFromFile() =>stereoRectify() =>reprojectImageTo3D()

  • I non li hanno ma posso calibrare la mia macchina fotografica =>stereoCalibrate() =>stereoRectify() =>reprojectImageTo3D()

  • non riesco a calibrare la fotocamera (è il mio caso, perché non ho la macchina fotografica che ha preso il 2 i maghi, quindi ho bisogno di trovare i punti chiave della coppia su entrambe le immagini con SURF, SIFT per esempio (posso usare qualsiasi rilevatore di blob in realtà), quindi calcolare i descrittori di questi punti chiave, quindi abbinare i punti chiave dall'immagine a destra e l'immagine a sinistra in base ai descrittori, e quindi trova la matrice fondamentale da loro. Il trattamento è molto più difficile e sarebbe stato così:

    1. di rilevare i punti chiave (SURF, SIFT) =>
    2. descrittori estratto (SURF, SIFT) =>
    3. confronto e descrittori partita (in base BruteForce, Flann approcci) =>
    4. trovano mat fondamentale (findFundamentalMat()) da queste coppie =>
    5. stereoRectifyUncalibrated() =>
    6. reprojectImageTo3D()

Sto usando l'ultimo approccio e le mie domande sono:

1) E 'giusto?

2) se è ok, ho un dubbio sull'ultimo passaggio stereoRectifyUncalibrated() =>reprojectImageTo3D(). La firma di reprojectImageTo3D() funzione è:

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

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

Parametri:

  • disparity - Ingresso singolo canale a 8 bit senza segno, 16 bit con segno, 32 bit firmato o in virgola mobile disparità a 32 bit Immagine.
  • _3dImage - Immagine in virgola mobile a 3 canali con le stesse dimensioni di disparity. Ogni elemento di _3dImage(x,y) contiene le coordinate 3D del punto (x,y) calcolato dalla mappa di disparità.
  • Q - Matrice di trasformazione prospettiva 4x4 che può essere ottenuta con stereoRectify().
  • handleMissingValues - Indica se la funzione deve gestire i valori mancanti (cioè i punti in cui la disparità non è stata calcolata). Se handleMissingValues=true, i pixel con la disparità minima che corrisponde ai valori anomali (vedere StereoBM::operator()) vengono trasformati in punti 3D con un valore Z molto grande (attualmente impostato su 10000).
  • ddepth - La profondità della matrice di output opzionale.Se è -1, l'immagine in uscita avrà profondità CV_32F. ddepth può anche essere impostato su CV_16S, CV_32S o su 'CV_32F'.

Come posso ottenere la matrice Q? È possibile ottenere la matrice Q con F, H1 e H2 o in un altro modo?

3) Esiste un altro modo per ottenere le coordinate xyz senza calibrare le telecamere?

mio codice è:

#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 - lingua? – Tim

+0

@Tim C++ con OpenCV2.3.1 – Fobi

+0

Penso che sia ma ti manca qualcosa. La disparità può essere ottenuta con diverse funzioni, è necessario controllare le documentazioni openCV. http://opencv.willowgarage.com/documentation/camera_calibration_and_3d_reconstruction.html –

risposta

4

StereoRectifyUncalibrated calcola semplicemente prospettiva non trasformazione planare rettifica trasformazione in spazio oggetti. È necessario convertire questa trasformazione planare in trasformazione dello spazio dell'oggetto per estrarre la matrice Q e penso che alcuni dei parametri di calibrazione della telecamera siano necessari per questo (come le intrinseche della fotocamera). Ci possono essere alcuni argomenti di ricerca in corso con questo argomento.

È possibile che siano stati aggiunti alcuni passaggi per la valutazione delle intrinseche della telecamera e l'estrazione dell'orientamento relativo delle telecamere per far funzionare correttamente il flusso. Penso che i parametri di calibrazione della fotocamera siano di vitale importanza per l'estrazione della corretta struttura 3d della scena, se non viene utilizzato alcun metodo di illuminazione attivo.

Sono inoltre necessarie soluzioni basate sulla regolazione di blocco del fascio per rifinire tutti i valori stimati con valori più accurati.

2
  1. la procedura sembra OK per me.

  2. per quanto ne so, per quanto riguarda la modellazione 3D basata su immagini, le telecamere sono calibrate in modo esplicito o calibrate in modo implicito. non si desidera calibrare esplicitamente la fotocamera. farai comunque uso di quelle cose. abbinare corrispondenti coppie di punti sono decisamente un approccio molto usato.

1

Credo che è necessario utilizzare StereoRectify per correggere le immagini e ottenere Q. Questa funzione richiede due parametri (R e T), la rotazione e traslazione tra due macchine fotografiche. Così puoi calcolare i parametri usando solvePnP. Questa funzione ha bisogno di alcune coordinate reali 3D dell'oggetto specifico e dei punti 2D nelle immagini e dei corrispondenti punti

Problemi correlati