系列文章:
- 双目视觉(一)双目视觉系统
- 双目视觉(二)双目匹配的困难和评判标准
- 双目视觉(三)立体匹配算法
- 双目视觉(四)匹配代价
- 双目视觉(五)立体匹配算法之动态规划全局匹配
- 双目视觉(六)U-V视差
- 【项目实战】利用U-V视差进行地面检测
- 【项目实践】U-V视差路面检测之动态规划
因为在自己的工作中需要剔除行驶的地面,要用到U-V视差,所以写这篇博客主要是记录自己学习到的相关内容。如果写的有问题可以在评论中指出。
实践部分
目录
1.原理:
-
双目系统
双目相机系统如下图所示:f为焦距,b为基线,P(X,Y,Z)为三维点。 我们可以得到视差的公式如下:(双目视觉系统)
-
模型推导
首先,当我们使用双目相机拍摄真实世界时,如下图所示,(Xw ,Yw , Zw )为世界坐标系,(Xl ,Yl , Zl)为左相机坐标系,(Xr ,Yr , Zr)为右相机坐标系。
- 对于世界坐标系和左相机坐标系,存在着b/2的平移,以及一个旋转角θ
- 对于世界坐标系和右相机坐标系,存在着b/2的平移,以及一个旋转角θ
那么,从世界坐标系到左右相机坐标的变换矩阵为:
其次,我们预先通过标定知道了左右相机的内参矩阵为:
当相机的内参和外参都知道了,根据针孔相机模型,就可以计算处相机的投影矩阵P=K[R|t]
使用矩阵的乘法公式对其进行展开得到:
由d=ul-ur得到视差:
2.U-V视差的构造
- U视差的构造
U-disparityMap的列对应于原始视差图的列;
U-disparityMap中(d,u) = 原始视差图中第u列,视差为d的个数。
- V视差的构造
V-disparityMap的行对应于原始视差图的行;
V-disparityMap中(v,d) = 原始视差图中第v行,视差为d的个数。
3.各种3D平面在U-V视差中的投影
4.实例
1.左图像,右图像,视差图像
2.U-视差,V-视差
3.对U-V视差图使用霍夫变换检测线
①,⑤:近似直线,如图中的球体和圆锥;
② 11:地平面在V视差中的投影为直线;
⑥,⑦:侧面的墙在U视差中的投影为直线;
⑨ :垂直障碍物;
③④⑧⑩:垂直墙面的转角处;
4.3D重建的结构
5.Opencv实现
- 双目匹配(这里我们使用Opencv中自带的SGBM算法)
//SGBM param
int mMaxDisp = 128;
int mP1 = 100;
int mP2 = 2700;
int mWinSize = 4;
int mPreFilterCap = 180;
//create SGBM
cv::Ptr<cv::StereoSGBM> mSGBM=cv::StereoSGBM::create(0,mMaxDisp,mWinSize,mP1,mP2,0,mPreFilterCap,5,0,0,cv::StereoSGBM::MODE_HH);
// read image
cv::Mat left=cv::imread("../image/I1_000000.png");
cv::Mat right=cv::imread("../image/I2_000000.png");
cv::Mat disp16s,disp;
//compute disparity
mSGBM->compute(left,right,disp16s);
disp16s=disp16s/16;
disp16s.convertTo(disp,CV_8UC1);
- 计算U视差图
cv::Mat UdispMap=cv::Mat(mMaxDisp,disp.cols,CV_16UC1);
void computeUDisparity(cv::Mat &UdispMap,cv::Mat disp)
{
UdispMap.setTo(0);
int width=disp.cols;
int height=disp.rows;
for(int row=0;row<height;row++)
{
auto pRowInDisp=disp.ptr<uchar>(row);
for(int col=0;col<width;col++)
{
uint8_t currDisp=pRowInDisp[col];
if(currDisp>0&&currDisp<128)
{
UdispMap.at<ushort>(currDisp,col)++;
}
}
}
}
- 计算V视差图
cv::Mat VdispMap=cv::Mat(disp.rows,mMaxDisp,CV_16UC1);
void computeVDisparity(cv::Mat &VdispMap,cv::Mat disp)
{
VdispMap.setTo(0);
int width=disp.cols;
int height=disp.rows;
for(int row=0;row<height;row++)
{
auto pRowInDisp=disp.ptr<uchar>(row);
for(int col=0;col<width;col++)
{
uint8_t currDisp=pRowInDisp[col];
if(currDisp>0&&currDisp<128)
{
VdispMap.at<ushort>(row,currDisp)++;
}
}
}
}
- 原图像
- U视差
- V视差
- U视差用来剔除障碍物(10为阈值)
cv::Mat removeObstacle(cv::Mat Disparity,cv::Mat Udisparity)
{
cv::Mat mObstacleMap;
mObstacleMap.create(Disparity.rows, Disparity.cols, CV_8UC1);
mObstacleMap.setTo(0);
int height = Disparity.rows;
int width = Disparity.cols;
for (int v = 0; v < height; v++)
{
uint8_t* pRowInDisp = Disparity.ptr<uchar>(v);
uint8_t* pRowInObsMap = mObstacleMap.ptr<uchar>(v);
for (int u = 0; u < width; u++)
{
uint8_t currDisp = pRowInDisp[u];
if (currDisp < 128 && Udisparity.at<ushort>(currDisp, u) > 10)
pRowInObsMap[u] = 255;
}
}
return mObstacleMap;
}
参考:
基于 U-V 视差算法的障碍物识别技术研究
A Complete U-V-Disparity Study for Stereovision Based 3D Driving Environment analysis
视差:disparity与UV-视差:UV-disparity_uv视差图_生活没有if-else的博客-CSDN博客
菜鸟看论文——U-V-Disparity与地面检测、相机姿态估计:菜鸟看论文——U-V-Disparity与地面检测、相机姿态估计_yiteeee的博客-CSDN博客