Tôi mới trong lĩnh vực này và tôi đang cố gắng tạo mô hình một cảnh đơn giản trong 3d ngoài hình ảnh 2ngày và tôi không có bất kỳ thông tin nào về máy ảnh. Tôi biết rằng có 3 options:dựng lại 3D từ 2 hình ảnh mà không có thông tin về máy ảnh
tôi có hai hình ảnh và tôi biết mô hình của máy ảnh của tôi (intrisics) mà tôi nạp từ một XML ví dụ
loadXMLFromFile()
=>stereoRectify()
=>reprojectImageTo3D()
tôi không có chúng, nhưng tôi có thể hiệu chỉnh của tôi camera =>
stereoCalibrate()
=>stereoRectify()
=>reprojectImageTo3D()
tôi không thể hiệu chỉnh camera (đó là trường hợp của tôi, bởi vì tôi không có máy ảnh mà đã đưa ra những 2 tôi pháp sư, sau đó tôi cần phải tìm cặp khóa trên cả hai hình ảnh với SURF, SIFT ví dụ (tôi có thể sử dụng bất kỳ trình phát hiện blob nào), sau đó tính toán mô tả của các điểm then chốt này, sau đó khớp các điểm chính từ hình ảnh bên phải và hình ảnh bên trái theo mô tả của họ, và sau đó tìm ma trận cơ bản từ chúng. Việc xử lý là khó khăn hơn nhiều và sẽ là như thế này:
- phát hiện keypoint (SURF, SIFT) =>
- trích mô tả (SURF, SIFT) =>
- so sánh và mô tả trận đấu (bruteforce, Flann dựa lối vào) =>
- tìm mat cơ bản (
findFundamentalMat()
) từ những cặp => stereoRectifyUncalibrated()
=>reprojectImageTo3D()
Tôi đang sử dụng phương pháp mới nhất và các câu hỏi của tôi là:
1) Có phải không?
2) nếu được, tôi có nghi ngờ về bước cuối cùng stereoRectifyUncalibrated()
=>reprojectImageTo3D()
. Chữ ký của reprojectImageTo3D()
chức năng là:
void reprojectImageTo3D(InputArray disparity, OutputArray _3dImage, InputArray Q, bool handleMissingValues=false, int depth=-1)
cv::reprojectImageTo3D(imgDisparity8U, xyz, Q, true) (in my code)
Tham số:
disparity
- Input đơn kênh 8-bit unsigned, 16-bit đã ký, 32-bit ký kết hoặc 32-bit floating-point chênh lệch hình ảnh._3dImage
- Đầu ra hình ảnh nổi 3-kênh có cùng kích thước vớidisparity
. Mỗi phần tử của_3dImage(x,y)
chứa tọa độ 3D của điểm(x,y)
được tính từ bản đồ chênh lệch.Q
- ma trận chuyển đổi quan điểm 4x4 có thể lấy được vớistereoRectify()
.handleMissingValues
- Cho biết, chức năng có nên xử lý các giá trị bị thiếu hay không (ví dụ: các điểm không tính chênh lệch). NếuhandleMissingValues=true
, thì các pixel có chênh lệch nhỏ nhất tương ứng với các ngoại lệ (xemStereoBM::operator()
) được chuyển thành các điểm 3D với giá trị Z rất lớn (hiện được đặt là 10000).ddepth
- Độ sâu mảng đầu ra tùy chọn.Nếu đó là -1, hình ảnh đầu ra sẽ có độ sâuCV_32F
.ddepth
cũng có thể được đặt thànhCV_16S
,CV_32S
hoặc `CV_32F '.
Làm cách nào để lấy ma trận Q
? Có thể lấy ma trận Q
với F
, H1
và H2
hoặc theo cách khác không?
3) Có cách nào khác để có được tọa độ xyz mà không cần hiệu chỉnh máy ảnh không?
Mã của tôi là:
#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 - ngôn ngữ? – Tim
@Tim C++ với OpenCV2.3.1 – Fobi
Tôi nghĩ rằng đó là nhưng bạn đang thiếu một cái gì đó. Có thể thu được sự khác biệt với nhiều chức năng, bạn nên kiểm tra tài liệu openCV. http://opencv.willowgarage.com/documentation/camera_calibration_and_3d_reconstruction.html –