2012-01-26 33 views
29

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:

    1. phát hiện keypoint (SURF, SIFT) =>
    2. trích mô tả (SURF, SIFT) =>
    3. so sánh và mô tả trận đấu (bruteforce, Flann dựa lối vào) =>
    4. tìm mat cơ bản (findFundamentalMat()) từ những cặp =>
    5. stereoRectifyUncalibrated() =>
    6. 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ới disparity. 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ới stereoRectify().
  • 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ếu handleMissingValues=true, thì các pixel có chênh lệch nhỏ nhất tương ứng với các ngoại lệ (xem StereoBM::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âu CV_32F. ddepth cũng có thể được đặt thành CV_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, H1H2 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; 
} 
+0

Fabio - ngôn ngữ? – Tim

+0

@Tim C++ với OpenCV2.3.1 – Fobi

+0

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 –

Trả lời

4

StereoRectifyUncalibrated tính toán đơn giản phẳng biến đổi phối cảnh không chuyển đổi cải chính trong không gian đối tượng. Nó là cần thiết để chuyển đổi này planar chuyển đổi để đối tượng không gian chuyển đổi để trích xuất Q matrice, và tôi nghĩ rằng một số các thông số hiệu chuẩn máy ảnh được yêu cầu cho nó (như intrinsics máy ảnh). Có thể có một số chủ đề nghiên cứu đang tiếp diễn với chủ đề này.

Bạn có thể thêm một số bước để ước tính nội tại của máy ảnh và trích xuất hướng tương đối của máy ảnh để làm cho luồng của bạn hoạt động đúng. Tôi nghĩ rằng các thông số hiệu chỉnh máy ảnh là rất quan trọng để trích xuất cấu trúc 3D thích hợp của cảnh, nếu không có phương pháp chiếu sáng đang hoạt động nào được sử dụng.

Cũng cần có các giải pháp dựa trên điều chỉnh khối bó để tinh chỉnh tất cả các giá trị ước tính thành các giá trị chính xác hơn.

2
  1. quy trình có vẻ OK với tôi.

  2. theo như tôi biết, liên quan đến mô hình 3D dựa trên hình ảnh, máy ảnh được hiệu chỉnh rõ ràng hoặc được hiệu chỉnh hoàn toàn. bạn không muốn hiệu chỉnh máy ảnh một cách rõ ràng. bạn sẽ sử dụng những thứ đó. phù hợp với cặp điểm tương ứng chắc chắn là một cách tiếp cận được sử dụng rất nhiều.

1

Tôi nghĩ rằng bạn cần phải sử dụng StereoRectify để khắc phục hình ảnh của bạn và nhận Q. Chức năng này cần hai tham số (R và T) luân chuyển và dịch giữa hai camera. Vì vậy, bạn có thể tính toán các tham số bằng cách sử dụng giải pháp. Chức năng này cần một số tọa độ thực 3D của đối tượng nhất định và điểm 2d trong hình ảnh và các điểm tương ứng của chúng

Các vấn đề liên quan