Получение карты глубины

Я не могу получить нормальную карту глубины из-за несоответствия. Вот мой код:

#include "opencv2/core/core.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/contrib/contrib.hpp"
#include <cstdio>
#include <iostream>
#include <fstream>

using namespace cv;
using namespace std;

ofstream out("points.txt");

int main()
{
    Mat img1, img2;
    img1 = imread("images/im7rect.bmp");
    img2 = imread("images/im8rect.bmp");

    //resize(img1, img1, Size(320, 280));
    //resize(img2, img2, Size(320, 280));

    Mat g1,g2, disp, disp8;
    cvtColor(img1, g1, CV_BGR2GRAY);
    cvtColor(img2, g2, CV_BGR2GRAY);

    int sadSize = 3;
    StereoSGBM sbm;
    sbm.SADWindowSize = sadSize;
    sbm.numberOfDisparities = 144;//144; 128
    sbm.preFilterCap = 10; //63
    sbm.minDisparity = 0; //-39; 0
    sbm.uniquenessRatio = 10;
    sbm.speckleWindowSize = 100;
    sbm.speckleRange = 32;
    sbm.disp12MaxDiff = 1;
    sbm.fullDP = true;
    sbm.P1 = sadSize*sadSize*4;
    sbm.P2 = sadSize*sadSize*32;
    sbm(g1, g2, disp);

    normalize(disp, disp8, 0, 255, CV_MINMAX, CV_8U);

    Mat dispSGBMscale; 
    disp.convertTo(dispSGBMscale,CV_32F, 1./16); 

    imshow("image", img1);

    imshow("disparity", disp8);

    Mat Q;
    FileStorage fs("Q.txt", FileStorage::READ);
    fs["Q"] >> Q;
    fs.release();

    Mat points, points1;
    //reprojectImageTo3D(disp, points, Q, true);
    reprojectImageTo3D(disp, points, Q, false, CV_32F);
    imshow("points", points);

    ofstream point_cloud_file;
    point_cloud_file.open ("point_cloud.xyz");
    for(int i = 0; i < points.rows; i++) {
        for(int j = 0; j < points.cols; j++) {
            Vec3f point = points.at<Vec3f>(i,j);
            if(point[2] < 10) {
                point_cloud_file << point[0] << " " << point[1] << " " << point[2]
                    << " " << static_cast<unsigned>(img1.at<uchar>(i,j)) << " " << static_cast<unsigned>(img1.at<uchar>(i,j)) << " " << static_cast<unsigned>(img1.at<uchar>(i,j)) << endl;
            }
        }
    }
    point_cloud_file.close(); 

    waitKey(0);

    return 0;
}

Мои изображения:

введите описание изображения здесь введите описание изображения здесь

Карта диспаратности:

введите описание изображения здесь

Я получаю что-то вроде этого облака точек: введите здесь описание изображения

Q равно: [1., 0., 0., -3.2883545303344727e + 02, 0., 1., 0., -2.3697290992736816e + 02, 0., 0., 0., 5.4497170185417110e + 02, 0 ., 0., -1,4446083962336606e-02, 0.]

Я пробовал многое другое. Я пробовал с разными изображениями, но никто не может получить нормальную карту глубины.

Что я делаю неправильно? Что делать с reprojectImageTo3D или использовать вместо него другой подход? Как лучше всего визуализировать карту глубины? (Я попробовал библиотеку point_cloud) Или вы могли бы предоставить мне рабочий пример с набором данных и информацией о калибровке, чтобы я мог запустить его и получить карту глубины. Или как я могу получить карту глубины из стереобазы Middlebury (http://vision.middlebury.edu/stereo/data/), думаю, информации о калибровке недостаточно.

Отредактировано: теперь я получаю что-то вроде: введите описание изображения здесь

Это конечно лучше, но все же ненормально.

Отредактировано 2: Я пробовал то, что вы говорите:

Mat disp;
disp = imread("disparity-image.pgm", CV_LOAD_IMAGE_GRAYSCALE);

Mat disp64; 
disp.convertTo(disp64,CV_64F, 1.0/16.0); 
imshow("disp", disp);

Я получаю этот результат с помощью строки cv :: minMaxIdx (...): введите описание изображения здесь

И это, когда я комментирую эту строку: введите здесь описание изображения

Ps: Также, пожалуйста, не могли бы вы мне сказать, как я могу рассчитать глубину, зная только базовую линию и фокусное расстояние в пикселях.


person Aram Gevorgyan    schedule 06.05.2015    source источник
comment
все зависит от вашей калибровки. если у вас ошибка перепроецирования более 0,5, вы получите плохую Q-матрицу   -  person berak    schedule 06.05.2015
comment
@berak: Я знаю об этом, и поскольку мне не удалось получить хорошую калибровку, я попробовал ее на наборе данных из Интернета (code.google.com/p/tjpstereovision/source/browse), и я думаю, что это нормальная Q-матрица. Как я могу получить карту глубины из набора данных среднего размера?   -  person Aram Gevorgyan    schedule 06.05.2015


Ответы (1)


Я провел простое сравнение между reprojectImageTo3D() OpenCV и моим собственным ( см. ниже), а также запустите тест на правильность несоответствия и Q матрицы.

// Reproject image to 3D
void customReproject(const cv::Mat& disparity, const cv::Mat& Q, cv::Mat& out3D)
{
    CV_Assert(disparity.type() == CV_32F && !disparity.empty());
    CV_Assert(Q.type() == CV_32F && Q.cols == 4 && Q.rows == 4);

    // 3-channel matrix for containing the reprojected 3D world coordinates
    out3D = cv::Mat::zeros(disparity.size(), CV_32FC3);

    // Getting the interesting parameters from Q, everything else is zero or one
    float Q03 = Q.at<float>(0, 3);
    float Q13 = Q.at<float>(1, 3);
    float Q23 = Q.at<float>(2, 3);
    float Q32 = Q.at<float>(3, 2);
    float Q33 = Q.at<float>(3, 3);

    // Transforming a single-channel disparity map to a 3-channel image representing a 3D surface
    for (int i = 0; i < disparity.rows; i++)
    {
        const float* disp_ptr = disparity.ptr<float>(i);
        cv::Vec3f* out3D_ptr = out3D.ptr<cv::Vec3f>(i);

        for (int j = 0; j < disparity.cols; j++)
        {
            const float pw = 1.0f / (disp_ptr[j] * Q32 + Q33);

            cv::Vec3f& point = out3D_ptr[j];
            point[0] = (static_cast<float>(j)+Q03) * pw;
            point[1] = (static_cast<float>(i)+Q13) * pw;
            point[2] = Q23 * pw;
        }
    }
}

Оба метода дали почти одинаковые результаты, и все они кажутся мне правильными. Не могли бы вы попробовать это на вашей карте несоответствия и Q матрице? Вы можете разместить мою тестовую среду на моем GitHub.

Примечание 1: также будьте осторожны, чтобы не увеличивать вдвое неравенство (закомментируйте строку disparity.convertTo(disparity, CV_32F, 1.0 / 16.0);, если ваш disparity также был масштабирован).

Примечание 2: он был создан с помощью OpenCV 3.0, возможно, вам придется изменить его включение.

person Kornel    schedule 06.05.2015
comment
Итак, XYZ - это 3-канальное изображение с плавающей запятой того же размера, что и диспаратность. Каждый элемент XYZ содержит трехмерные координаты точки (x, y), вычисленные из карты диспаратности. Между вашими типами и моим было неправильное использование, я изменил код, чтобы использовать double везде. - person Kornel; 06.05.2015
comment
Спасибо, редактирую вопрос. Я использую Opencv 2.4.9. версия - person Aram Gevorgyan; 06.05.2015
comment
что будет, если закомментировать строку cv::minMaxIdx(...)? - person Kornel; 06.05.2015
comment
Трудно сказать здесь, что у вас есть образец кода с правильной диспаратностью и матрицей Q, можете ли вы загрузить и попробовать его в своем коде? - person Kornel; 06.05.2015
comment
Я провел последний тест, и результаты кажутся мне правильными, пожалуйста, посмотрите мой обновленный ответ - person Kornel; 07.05.2015
comment
Да, работает, большое спасибо за помощь :) Не проверяю с Opencv 3.0 У меня еще не было времени, но я тоже проверю. - person Aram Gevorgyan; 07.05.2015