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í:
- detectar puntos clave (SURF, SIFT) =>
- descriptores de extracto (SURF, SIFT) =>
- comparar y descriptores de los partidos (basado BruteForce, Flann enfoques) =>
- encuentran estera fundamental (
findFundamentalMat()
) de estos pares => stereoRectifyUncalibrated()
=>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 quedisparity
. 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 constereoRectify()
.handleMissingValues
- Indica si la función debe manejar valores perdidos (es decir, puntos donde no se calculó la disparidad). Si eshandleMissingValues=true
, los píxeles con la disparidad mínima que corresponde a los valores atípicos (consulteStereoBM::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 deCV_32F
.ddepth
también se puede establecer enCV_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;
}
Fabio - language? – Tim
@Tim C++ con OpenCV2.3.1 – Fobi
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 –