c++ - कैमरे के बारे में जानकारी के बिना 2 छवियों से 3 डी पुनर्निर्माण




opencv 3d-modelling (2)

  1. प्रक्रिया मेरे लिए ठीक लगती है।

  2. जहां तक ​​मुझे पता है, छवि आधारित 3 डी मॉडलिंग के संबंध में, कैमरों को स्पष्ट रूप से कैलिब्रेटेड या स्पष्ट रूप से कैलिब्रेटेड किया जाता है। आप कैमरे को स्पष्ट रूप से कैलिब्रेट करना नहीं चाहते हैं। आप वैसे भी उन चीजों का उपयोग करेंगे। संबंधित बिंदु जोड़े से मिलान निश्चित रूप से एक भारी उपयोग किया जाता है।

मैं इस क्षेत्र में नया हूं और मैं 2 डी छवियों में से 3 डी में एक साधारण दृश्य मॉडल करने की कोशिश कर रहा हूं और मुझे कैमरों के बारे में कोई जानकारी नहीं है। मुझे पता है कि 3 विकल्प हैं :

  • मेरे पास दो छवियां हैं और मुझे अपने कैमरे (इंट्रिसिक्स) का मॉडल पता है जो मैंने एक्सएमएल से लोड किया है उदाहरण के लिए loadXMLFromFile() => stereoRectify() => reprojectImageTo3D()

  • मेरे पास नहीं है लेकिन मैं अपने कैमरे को कैलिब्रेट कर सकता हूं => stereoCalibrate() => stereoRectify() => reprojectImageTo3D()

  • मैं कैमरे को कैलिब्रेट नहीं कर सकता (यह मेरा मामला है, क्योंकि मेरे पास कैमरा नहीं है जिसने 2 छवियां ली हैं, तो मुझे उदाहरण के लिए एसयूआरएफ, एसआईएफटी के साथ दोनों छवियों पर जोड़ी कीपॉइंट्स खोजने की ज़रूरत है (मैं किसी भी ब्लॉब का उपयोग कर सकता हूं डिटेक्टर वास्तव में), फिर इन कीपॉइंट्स के वर्णनकर्ताओं की गणना करें, फिर छवि के दाईं ओर की मुख्य बिंदुओं से मिलान करें और छवि उनके वर्णनकर्ताओं के अनुसार बाएं, और फिर उनसे मौलिक मैट्रिक्स खोजें। प्रसंस्करण बहुत कठिन है और ऐसा होगा:

    1. कीपॉइंट्स का पता लगाएं (एसयूआरएफ, एसआईएफटी) =>
    2. वर्णक निकालें (एसयूआरएफ, एसआईएफटी) =>
    3. तुलना और वर्णन करें वर्णक (ब्रूटफोर्स, फ़्लैन आधारित दृष्टिकोण) =>
    4. इन जोड़ों से मौलिक चटाई ( findFundamentalMat() ) findFundamentalMat() =>
    5. stereoRectifyUncalibrated() =>
    6. reprojectImageTo3D()

मैं अंतिम दृष्टिकोण का उपयोग कर रहा हूं और मेरे प्रश्न हैं:

1) क्या यह सही है?

2) यदि यह ठीक है, तो मुझे अंतिम चरण stereoRectifyUncalibrated() => reprojectImageTo3D() बारे में संदेह है। reprojectImageTo3D() फ़ंक्शन का हस्ताक्षर है:

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

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

पैरामीटर:

  • disparity - इनपुट सिंगल-चैनल 8-बिट हस्ताक्षरित, 16-बिट हस्ताक्षरित, 32-बिट हस्ताक्षरित या 32-बिट फ़्लोटिंग-पॉइंट असमानता छवि।
  • _3dImage - disparity के समान आकार की आउटपुट 3-चैनल फ़्लोटिंग-पॉइंट छवि। _3dImage(x,y) प्रत्येक तत्व में असमानता मानचित्र से गणना बिंदु (x,y) 3 डी निर्देशांक होते हैं।
  • Q - 4x4 परिप्रेक्ष्य परिवर्तन मैट्रिक्स जो stereoRectify() साथ प्राप्त किया जा सकता है।
  • handleMissingValues - इंगित करता है कि फ़ंक्शन को गुम मूल्यों को संभालना चाहिए (यानी अंक जहां असमानता की गणना नहीं की गई थी)। यदि handleMissingValues=true , तो handleMissingValues=true संबंधित न्यूनतम असमानता वाले पिक्सल ( StereoBM::operator() ) को बहुत बड़े Z मान (वर्तमान में 10000 पर सेट) के साथ 3 डी बिंदुओं में परिवर्तित कर दिया गया है।
  • ddepth - वैकल्पिक आउटपुट सरणी गहराई। यदि यह -1 है, तो आउटपुट छवि में CV_32F गहराई होगी। CV_16S को CV_16S , CV_32S या 'सीवी_32 एफ' पर भी सेट किया जा सकता है।

मैं Q मैट्रिक्स कैसे प्राप्त कर सकता हूं? F , H1 और H2 या किसी अन्य तरीके से Q मैट्रिक्स प्राप्त करना संभव है?

3) कैमरे को कैलिब्रेट किए बिना xyz निर्देशांक प्राप्त करने का कोई और तरीका है?

मेरा कोड है:

#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;
}

StereoRectifyUncalibrated बस प्लानर परिप्रेक्ष्य परिवर्तन की गणना ऑब्जेक्ट स्पेस में सुधार सुधार नहीं है। क्यू मैट्रिस निकालने के लिए अंतरिक्ष परिवर्तन को ऑब्जेक्ट करने के लिए इस प्लानर रूपांतरण को परिवर्तित करना आवश्यक है, और मुझे लगता है कि कैमरे अंशांकन पैरामीटर के लिए कुछ कैमरे के इंट्रिनिक्स की आवश्यकता है। इस विषय के साथ चल रहे कुछ शोध विषय हो सकते हैं।

आपने कैमरे के इंट्रिनिक्स का आकलन करने के लिए कुछ कदम उठाए हैं, और अपने प्रवाह को सही बनाने के लिए कैमरे के सापेक्ष अभिविन्यास को निकाल सकते हैं। मुझे लगता है कि यदि दृश्य सक्रिय प्रकाश विधि का उपयोग नहीं किया जाता है, तो दृश्य कैलिब्रेशन पैरामीटर दृश्य की उचित 3 डी संरचना निकालने के लिए महत्वपूर्ण हैं।

सभी अनुमानित मानों को अधिक सटीक मानों को परिष्कृत करने के लिए भी ब्लॉक समायोजन आधारित समाधानों को बंडल करना आवश्यक है।