获取深度图
Getting depth map
我无法从差异中获得正常的深度图。
这是我的代码:
#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/) 中获取 depth_map,我认为没有足够的校准信息。
已编辑:
现在我得到像:
当然更好了,但还是不正常。
已编辑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:另外请你告诉我如何只知道基线和焦距(以像素为单位)来计算深度。
我对 OpenCV 的 reprojectImageTo3D()
和我自己的(见下文)进行了简单比较,并且 运行 对正确视差和 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
也被缩放,请注释掉行 disparity.convertTo(disparity, CV_32F, 1.0 / 16.0);
。)
注2:它是用OpenCV 3.0构建的,您可能需要更改包含。
我无法从差异中获得正常的深度图。 这是我的代码:
#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/) 中获取 depth_map,我认为没有足够的校准信息。
已编辑:
现在我得到像:
当然更好了,但还是不正常。
已编辑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:另外请你告诉我如何只知道基线和焦距(以像素为单位)来计算深度。
我对 OpenCV 的 reprojectImageTo3D()
和我自己的(见下文)进行了简单比较,并且 运行 对正确视差和 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
也被缩放,请注释掉行 disparity.convertTo(disparity, CV_32F, 1.0 / 16.0);
。)
注2:它是用OpenCV 3.0构建的,您可能需要更改包含。