python双目三维重建_OpenCV+OpenGL 双目立体视觉三维重建

0.绪论

这篇文章主要为了研究双目立体视觉的最终目标——三维重建,系统的介绍了三维重建的整体步骤。双目立体视觉的整体流程包括:图像获取,摄像机标定,特征提取(稠密匹配中这一步可以省略),立体匹配,三维重建。我在做双目立体视觉问题时,主要关注的点是立体匹配,本文主要关注最后一个步骤三维重建中的:三角剖分和纹理贴图以及对应的OpenCV+OpenGL代码实现。

1.视差计算

1.1基于视差信息的三维重建

特征提取

由双目立体视觉进行三位重建的第一步是立体匹配,通过寻找两幅图像中的对应点获取视差。OpenCV 中的features2d库中包含了很多常用的算法,其中特征点定位的算法有FAST, SIFT, SURF ,MSER, HARRIS等,特征点描述算法有SURF, SIFT等,还有若干种特征点匹配算法。这三个步骤的算法可以任选其一,自由组合,非常方便。经过实验,选择了一种速度、特征点数量和精度都比较好的组合方案:FAST角点检测算法+SURF特征描述子+FLANN(Fast Library for Approximate Nearest Neighbors) 匹配算法。

在匹配过程中需要有一些措施来过滤误匹配。一种比较常用的方法是比较第一匹配结果和第二匹配结果的得分差距是否足够大,这种方法可以过滤掉一些由于相似造成的误匹配。还有一种方法是利用已经找到的匹配点,使用RANSAC算法求得两幅视图之间的单应矩阵,然后将左视图中的坐标P用单应矩阵映射到右视图的Q点,观察与匹配结果Q’的欧氏距离是否足够小。当然由于图像是具有深度的,Q与Q’必定会有差距,因此距离阈值可以设置的稍微宽松一些。我使用了这两种过滤方法。

另外,由于图像有些部分的纹理较多,有些地方则没有什么纹理,造成特征点疏密分布不均匀,影响最终重建的效果,因此我还采取了一个措施:限制特征点不能取的太密。如果新加入的特征点与已有的某一特征点距离太小,就舍弃之。最终匹配结果如下图所示,精度和均匀程度都较好。

代码:

// choose the corresponding points in the stereo images for 3d reconstruction

void GetPair( Mat &imgL, Mat &imgR, vector &ptsL, vector &ptsR )

{

Mat descriptorsL, descriptorsR;

double tt = (double)getTickCount();

Ptr detector = FeatureDetector::create( DETECTOR_TYPE ); // factory mode

vector keypointsL, keypointsR;

detector->detect( imgL, keypointsL );

detector->detect( imgR, keypointsR );

Ptr de = DescriptorExtractor::create( DESCRIPTOR_TYPE );

//SurfDescriptorExtractor de(4,2,true);

de->compute( imgL, keypointsL, descriptorsL );

de->compute( imgR, keypointsR, descriptorsR );

tt = ((double)getTickCount() - tt)/getTickFrequency(); // 620*555 pic, about 2s for SURF, 120s for SIFT

Ptr matcher = DescriptorMatcher::create( MATCHER_TYPE );

vector> matches;

matcher->knnMatch( descriptorsL, descriptorsR, matches, 2 ); // L:query, R:train

vector passedMatches; // save for drawing

DMatch m1, m2;

vector ptsRtemp, ptsLtemp;

for( size_t i = 0; i < matches.size(); i++ )

{

m1 = matches[i][0];

m2 = matches[i][1];

if (m1.distance < MAXM_FILTER_TH * m2.distance)

{

ptsRtemp.push_back(keypointsR[m1.trainIdx].pt);

ptsLtemp.push_back(keypointsL[i].pt);

passedMatches.push_back(m1);

}

}

Mat HLR;

HLR = findHomography( Mat(ptsLtemp), Mat(ptsRtemp), CV_RANSAC, 3 );

cout<

Mat ptsLt;

perspectiveTransform(Mat(ptsLtemp), ptsLt, HLR);

vector matchesMask( passedMatches.size(), 0 );

int cnt = 0;

for( size_t i1 = 0; i1 < ptsLtemp.size(); i1++ )

{

Point2f prjPtR = ptsLt.at((int)i1,0); // prjx = ptsLt.at((int)i1,0), prjy = ptsLt.at((int)i1,1);

// inlier

if( abs(ptsRtemp[i1].x - prjPtR.x) < HOMO_FILTER_TH &&

abs(ptsRtemp[i1].y - prjPtR.y) < 2) // restriction on y is more strict

{

vector::iterator iter = ptsL.begin();

for (;iter!=ptsL.end();iter++)

{

Point2f diff = *iter - ptsLtemp[i1];

float dist = abs(diff.x)+abs(diff.y);

if (dist < NEAR_FILTER_TH) break;

}

if (iter != ptsL.end()) continue;

ptsL.push_back(ptsLtemp[i1]);

ptsR.push_back(ptsRtemp[i1]);

cnt++;

if (cnt%1 == 0) matchesMask[i1] = 1; // don't want to draw to many matches

}

}

Mat outImg;

drawMatches(imgL, keypointsL, imgR, keypointsR, passedMatches, outImg,

Scalar::all(-1), Scalar::all(-1), matchesMask, Dr

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
<项目介绍> 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到94.5分,放心下载使用! 该资源适合计算机相关专业(如人工智能、通信工程、自动化、软件工程等)的在校学生、老师或者企业员工下载,适合小白学习或者实际项目借鉴参考! 当然也可作为毕业设计、课程设计、课程作业、项目初期立项演示等。如果基础还行,可以在此代码基础之上做改动以实现更多功能。 双目测距理论及其python运用 一、双目测距基本流程 Stereo Vision, 也叫双目立体视觉,它的研究可以帮助我们更好的理解人类的双眼是如何进行深度感知的。双目视觉在许多领域得到了应用,例如城市三维重建、3D模型构建(如kinect fusion)、视角合成、3D跟踪、机器人导航(自动驾驶)、人类运动捕捉(Microsoft Kinect)等等。双目测距也属于双目立体视觉的一个应用领域,双目测距的基本原理主要是三角测量原理,即通过视差来判定物体的远近。 那么总结起来,双目测距的大致流程就是: **双目标定 --> 立体校正(含消除畸变) --> 立体匹配 --> 视差计算 --> 深度计算(3D坐标)计算** linux下安装opencv-python: ```python pip install opencv-python ``` 二、相机畸变 光线经过相机的光学系统往往不能按照理想的情况投射到传感器上,也就是会产生所谓的畸变。畸变有种情况:一种是由透镜形状引起的畸变称之为径向畸变。在针孔模型中,一条直线投影到像素平面上还是一条直线。可是,在实际拍摄的照片中,摄像机的透镜往往使得真实环境中的一条直线在图片中变成了曲线。越靠近图像的边缘,这种现象越明显。由于实际加工制作的透镜往往是中心对称的,这使得不规则的畸变通常径向对称。它们主要分为大类,桶形畸变 和 枕形畸变(摘自《SLAM十四讲》)如图所示: <div align=center><img src="https://img-blog.csdnimg.cn/20190907184815326.PNG" width="324" height="100" /></div> 桶形畸变是由于图像放大率随着离光轴的距离增加而减小,而枕形畸变却恰好相反。 在这种畸变中,穿过图像中心和光轴有交点的直线还能保持形状不变。
系统根据B/S,即所谓的电脑浏览器/网络服务器方式,运用Java技术性,挑选MySQL作为后台系统。系统主要包含对客服聊天管理、字典表管理、公告信息管理、金融工具管理、金融工具收藏管理、金融工具银行卡管理、借款管理、理财产品管理、理财产品收藏管理、理财产品银行卡管理、理财银行卡信息管理、银行卡管理、存款管理、银行卡记录管理、取款管理、转账管理、用户管理、员工管理等功能模块。 文中重点介绍了银行管理的专业技术发展背景和发展状况,随后遵照软件传统式研发流程,最先挑选适用思维和语言软件开发平台,依据需求分析报告模块和设计数据库结构,再根据系统功能模块的设计制作系统功能模块图、流程表和E-R图。随后设计架构以及编写代码,并实现系统能模块。最终基本完成系统检测和功能测试。结果显示,该系统能够实现所需要的作用,工作状态没有明显缺陷。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。进入银行卡列表,管理员可以进行查看列表、模糊搜索以及相关维护等操作。用户进入系统可以查看公告和模糊搜索公告信息、也可以进行公告维护操作。理财产品管理页面,管理员可以进行查看列表、模糊搜索以及相关维护等操作。产品类型管理页面,此页面提供给管理员的功能有:新增产品类型,修改产品类型,删除产品类型。
双目视觉是一种通过个摄像头获取的图像来计算深度信息的技术。OpenCVOpenGL个常用的库,可以用于实现双目视觉三维重建。以下是一个简单的流程: 1.使用OpenCV获取左右个摄像头的图像,并进行立体匹配,得到视差图。 ```python import cv2 # 读取左右个摄像头的图像 imgL = cv2.imread('left.png', 0) imgR = cv2.imread('right.png', 0) # 创建SGBM对象,进行立体匹配 window_size = 3 left_matcher = cv2.StereoSGBM_create( minDisparity=0, numDisparities=160, blockSize=5, P1=8 * 3 * window_size ** 2, P2=32 * 3 * window_size ** 2, disp12MaxDiff=1, uniquenessRatio=10, speckleWindowSize=100, speckleRange=32, preFilterCap=63, mode=cv2.STEREO_SGBM_MODE_SGBM_3WAY ) right_matcher = cv2.ximgproc.createRightMatcher(left_matcher) # 计算视差图 displ = left_matcher.compute(imgL, imgR) dispr = right_matcher.compute(imgR, imgL) ``` 2.使用三角剖分算法,根据视差图计算出点云。 ```python import numpy as np from matplotlib import pyplot as plt # 根据视差图计算点云 focal_length = 0.8 T = 0.5 Q = np.float32([[1, 0, 0, -imgL.shape[1] / 2], [0, -1, 0, imgL.shape[0] / 2], [0, 0, 0, -focal_length], [0, 0, 1 / T, 0]]) points = cv2.reprojectImageTo3D(displ, Q) # 去除无效点 mask = displ > displ.min() out_points = points[mask] out_colors = imgL[mask] # 显示点云 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.scatter(out_points[:, 0], out_points[:, 1], out_points[:, 2], c=out_colors / 255.0, marker='.') ax.view_init(elev=135, azim=90) plt.show() ``` 3.使用OpenGL进行纹理贴图,显示三维重建结果。 ```python import glfw from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * from PIL import Image # 初始化OpenGL窗口 glfw.init() glfw.window_hint(glfw.VISIBLE, False) window = glfw.create_window(640, 480, "OpenGL Window", None, None) glfw.make_context_current(window) # 加载纹理 texture = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, texture) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imgL.shape[1], imgL.shape[0], 0, GL_RGB, GL_UNSIGNED_BYTE, imgL) # 显示点云 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45, 640 / 480, 0.1, 100.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() gluLookAt(0, 0, 0, 0, 0, -1, 0, 1, 0) glTranslatef(0, 0, -3) glRotatef(180, 0, 1, 0) glEnable(GL_TEXTURE_2D) glBegin(GL_POINTS) for i in range(out_points.shape[0]): glColor3f(out_colors[i, 0] / 255.0, out_colors[i, 1] / 255.0, out_colors[i, 2] / 255.0) glVertex3f(out_points[i, 0], out_points[i, 1], out_points[i, 2]) glEnd() glfw.swap_buffers(window) # 保存结果 data = glReadPixels(0, 0, 640, 480, GL_RGB, GL_UNSIGNED_BYTE) image = Image.frombytes("RGB", (640, 480), data) image.save("result.png") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值