2012-01-26 12 views
29

Soy nuevo en este campo y estoy tratando de modelar una escena simple en 3D de 2d imágenes y no tengo ninguna información sobre las cámaras. Yo sé que hay 3 options:reconstrucción 3D a partir de 2 imágenes sin información sobre la cámara

  • que tienen dos imágenes y sé el modelo de mi cámara (intrisics) que he cargado desde un XML por ejemplo loadXMLFromFile() =>stereoRectify() =>reprojectImageTo3D()

  • I no los tienen pero puedo calibrar mi cámara =>stereoCalibrate() =>stereoRectify() =>reprojectImageTo3D()

  • no se puede calibrar la cámara (es mi caso, porque yo no tengo la cámara que ha tomado la 2 i mages, entonces necesito encontrar pares de puntos en ambas imágenes con SURF, SIFT por ejemplo (puedo usar cualquier detector de blob en realidad), luego calcular los descriptores de estos puntos clave, luego unir los puntos clave de la imagen a la derecha y la imagen de acuerdo a sus descriptores, y luego encuentra la matriz fundamental de ellos. El procesamiento es mucho más difícil y sería así:

    1. detectar puntos clave (SURF, SIFT) =>
    2. descriptores de extracto (SURF, SIFT) =>
    3. comparar y descriptores de los partidos (basado BruteForce, Flann enfoques) =>
    4. encuentran estera fundamental (findFundamentalMat()) de estos pares =>
    5. stereoRectifyUncalibrated() =>
    6. reprojectImageTo3D()

estoy usando el último enfoque y mis preguntas son:

1) ¿Es correcto?

2) si está bien, tengo una duda sobre el último paso stereoRectifyUncalibrated() =>reprojectImageTo3D(). La firma de reprojectImageTo3D() función es:

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

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

Parámetros:

  • disparity - Entrada de un solo canal de 8 bits sin signo de 16 bits con signo, de 32 bits con signo o 32 bits de coma flotante disparidad imagen.
  • _3dImage - Salida de 3 canales de imagen flotante del mismo tamaño que disparity. Cada elemento de _3dImage(x,y) contiene coordenadas 3D del punto (x,y) calculado a partir del mapa de disparidad.
  • Q - Matriz de transformación de perspectiva 4x4 que se puede obtener con stereoRectify().
  • handleMissingValues - Indica si la función debe manejar valores perdidos (es decir, puntos donde no se calculó la disparidad). Si es handleMissingValues=true, los píxeles con la disparidad mínima que corresponde a los valores atípicos (consulte StereoBM::operator()) se transforman en puntos 3D con un valor Z muy grande (actualmente establecido en 10000).
  • ddepth - La profundidad de la matriz de salida opcional.Si es -1, la imagen de salida tendrá una profundidad de CV_32F. ddepth también se puede establecer en CV_16S, CV_32S o `CV_32F '.

¿Cómo puedo obtener la matriz Q? Es posible obtener la matriz Q con F, H1 y H2 o de otra manera?

3) ¿Hay otra forma de obtener las coordenadas xyz sin calibrar las cámaras?

Mi código es:

#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++ con OpenCV2.3.1 – Fobi

+0

Creo que es pero te estás perdiendo algo. La disparidad se puede obtener con varias funciones, debe verificar las documentaciones de openCV. http://opencv.willowgarage.com/documentation/camera_calibration_and_3d_reconstruction.html –

Respuesta

4

StereoRectifyUncalibrated calcula plana no sólo la transformación perspectiva de transformación de rectificación en el espacio objeto. Es necesario convertir esta transformación planar en transformación de espacio de objetos para extraer matrices Q, y creo que se requieren algunos de los parámetros de calibración de la cámara (como los intrínsecos de la cámara). Es posible que haya algunos temas de investigación en curso con este tema.

Puede agregar algunos pasos para estimar las características intrínsecas de la cámara y extraer la orientación relativa de las cámaras para que el flujo funcione correctamente. Creo que los parámetros de calibración de la cámara son vitales para extraer la estructura 3D adecuada de la escena, si no hay un método de iluminación activo.

También se requieren soluciones basadas en el ajuste del bloque de paquetes para refinar todos los valores estimados a valores más precisos.

2
  1. el procedimiento se ve bien para mí.

  2. hasta donde yo sé, con respecto al modelado 3D basado en imágenes, las cámaras están explícitamente calibradas o implícitamente calibradas. no quiere calibrar explícitamente la cámara. harás uso de esas cosas de todos modos. igualar los pares de puntos correspondientes es definitivamente un enfoque muy utilizado.

1

Creo que es necesario utilizar StereoRectify para rectificar sus imágenes y obtener P. Esta función necesita dos parámetros (R y T) la rotación y traslación entre dos cámaras. Para que pueda calcular los parámetros usando solvePnP. Esta función necesita algunas coordenadas reales 3d del cierto objeto y 2d puntos en las imágenes y sus puntos correspondientes

Cuestiones relacionadas