(结构光)单目+结构光三维重构总体结构

博主是那种动手能力较差的人(超级容易踩坑,一个坑踩超级久),独自搭建一个单目+结构光系统是真的挺挑战的。
在自己做的过程中,最让人心累的就是,我结果不好的话,会认为是投影仪不够好才标定出问题的bulabulabula…,基本上卡着我的点都是诸如“怎么从投影仪投射一张正常的图片”这种让大佬们感觉很低级的问题。其实我的确很容易被所谓“低级问题”卡住,这也是需要进步的一个点。
本次实验主要参考了这位博主的3D重构系列博客。

相机+投影仪

相机是从包工头那里拿的MindVision,投影仪是博主还是白的时候从京东买的一个200多的“家庭影院”投影仪,物理分辨率800*480。听说别人用的都是几千块的投影仪,我的200块,我……是有点怕的。

系统标定

包括两个部分,相机标定和投影仪标定。OpenCV和MATLAB都有对应的标定工具,由于我使用的C++,所以用的OpenCV标定。标定过相机的伙伴可能对相机标定已经不陌生了,那么系统标定主要是投影仪怎么标定了。
OpenCV标定将投影仪看做一个相机模型,使用棋盘格进行标定。且只要知道了投影仪图片的角点坐标+角点坐标对应的世界坐标就能够对投影仪进行标定了。
具体操作坚持一个原则:保证打印棋盘格(用于相机的标定)和投影棋盘格在同一个平面上(对我来说比较难的是采集图片,我苦于没有准备好白板,标定的事情拖了好久好久)。采集图片时,保持相机与投影仪的相对位姿不变,改变白板与相机+投影仪系统的相对位姿,使用相机采集图片。
新手疑问1:打印棋盘格和投影棋盘格怎么摆?如图,相互不交叉,且角点个数不一样就可以了,保证角点个数不一样是为了在运行程序的时候区分是打印的其棋盘格还是投影的棋盘格(也就是标定的是相机还是投影仪)
在这里插入图片描述
新手疑问2:投影仪世界坐标和图片坐标怎么得到?系统首先标定相机,标定相机之后,提取上图中投影棋盘格的角点并计算这些角点的世界坐标(投影仪的世界坐标get);投影用的那张图片相当于投影仪相机模型中“相机采集到的图片”,提取角点就得到了标定中需要的图片角点坐标。然后就可以标定了。
新手疑问3:如何确定相机和投影仪的位姿?我看的以篇论文中提到,标定时得到相机RT,投影仪RT每一组都能够用作重构,对应的只是选择了不同的世界坐标系而已。对于重构结果没有本质上的影响。
新手疑问4:如果不小心动了投影仪和相机怎么办?动了就摆回去喽。。。摆不回去的话,内参无需重新标定,只需要重新标定外参就可以了。新手可以参考OpenCV中的函数solvePnPRansac(),这个函数就是知道了角点的世界坐标和图片坐标和相机内参和畸变系数能够得到相机相对于世界坐标系的RT的函数。这个函数真是太妙了。
我在标定这里踩了比较多的坑,最最最大的坑就是,我不知道使用多大的图片合适。可能第一次标定用的投影图片得到的结果也能用吧,但是我的测试结果不太好。最好就是采用与自己的投影仪物理分辨率一致的图片

三维重构原理

单目+结构光系统的原理与双目原理一样,只要找到了两张图片之间的像素对应关系+标定结果就能三角测量了。唯一的不同点就是寻找对应像素的方式不同。双目系统直接运行对应的算法就可以了,例如OpenCV中的SGBM算法。单目+结构光妙在结构光,通过对结构光进行编码、解码,得到像素之间的对应关系。我的投影仪正弦性不是很好,所以,我用的格雷码,这也是我参考开头那位博主的方法的原因。
在系统已经标定好的前提下,通过相机采集一批图片,然后对图片进行二值化,得到每个图片每个像素的格雷码,对格雷码解码之后得到的就是像素在“投影仪采集的(投影图片)图片中的位置”,如此一来,我们就得到了两张图片之间的像素对应关系,加上前边的标定结果,直接对“对应像素”进行三角测量就可以了。

我是不是写的太大白话了。。。

测试重构一个白色的方块
在这里插入图片描述
通过MATLAB中表示的结果,能够发现,点云分层,方块的上表面与白板分开。说明总体原理实现是正确的。
在这里插入图片描述
下一步应该是对点云中的离群点进行剔除。

  • 15
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 25
    评论
结构是一种利用投射条、格或者其他纹理来获取场景深度信息的技术。OpenCV提供了相应的函数来实现结构三维重建,主要包括以下几个步骤: 1. 投射纹理:使用投射仪投射纹理到物体表面,获取纹理图像。 2. 相机标定:通过相机标定,获取相机的内参矩阵和畸变参数,这是进行三维重构的前提条件。 3. 特征点提取:在纹理图像中提取特征点。 4. 匹配:将特征点在不同投射纹理下的坐标进行匹配。 5. 三维重建:通过相机的内参矩阵和匹配点对,计算出对应的三维点坐标。 6. 点云处理:将三维点云进行处理,去除离群点、进行滤波等操作。 7. 可视化:将处理后的点云进行可视化,生成三维模型。 以下是一个基于OpenCV的结构三维重建的示例代码: ```python import cv2 import numpy as np # 投射纹理 projector = cv2.projector.Projector() projector.setResolution(proj_width, proj_height) projector.setPattern(proj_pattern) projector.setExposure(proj_exposure) projector.setContrast(proj_contrast) projector.setBrightness(proj_brightness) projector.setSaturation(proj_saturation) proj_imgs = projector.generate() # 相机标定 K = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]]) # 内参矩阵 dist = np.array([k1, k2, p1, p2, k3]) # 畸变参数 img_size = (img_width, img_height) # 图像大小 retval, K, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, img_size, K, dist) # 特征点提取 orb = cv2.ORB_create() kp = [] des = [] for i in range(proj_num): gray = cv2.cvtColor(proj_imgs[i], cv2.COLOR_BGR2GRAY) kp_i, des_i = orb.detectAndCompute(gray, None) kp.append(kp_i) des.append(des_i) # 匹配 bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) matches = [] for i in range(proj_num-1): matches_i = bf.match(des[i], des[i+1]) matches.append(matches_i) # 三维重建 pts3d = [] for i in range(img_num): pts_i = [] for j in range(len(matches[i])): pt1 = kp[i][matches[i][j].queryIdx].pt pt2 = kp[i+1][matches[i][j].trainIdx].pt x1, y1 = pt1 x2, y2 = pt2 Z = (baseline * focal) / (x1 - x2) X = Z * (x1 - cx) / fx Y = Z * (y1 - cy) / fy pts_i.append([X, Y, Z]) pts3d.append(np.array(pts_i)) # 点云处理 pts3d_merged = np.vstack(pts3d) mask = (pts3d_merged[:, 2] > 0) pts3d_filtered = cv2.fastBilateralFilter(pts3d_merged[mask], 10, 50, 50) # 可视化 from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.scatter(pts3d_filtered[:, 0], pts3d_filtered[:, 1], pts3d_filtered[:, 2]) plt.show() ``` 需要注意的是,这只是一个示例代码,实际应用中需要根据具体需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值