结构光相移法 - 多频率离群点原理与实践(上)
点击上方“计算机视觉工坊”,选择“星标”
干货第一时间送达
01 相移法原理
02 双频外差原理
03 多频率外差原理
04 代码实践
01 相移法原理
结构光法原理其实是跟双目视觉一样的,都是要确定对应“匹配点”,利用“视差”三角关系计算距离,所不同的是:
双目视觉通过“被动”匹配唯一特征点
相移法作为结构光法中的一种,通过主动投影多副相移图案来标记唯一位置。
说明:虽然大多数结构光系统是单目的,但我们可以将其“双目”的,因为投影仪可以看做是一个“逆向”的相机,明白了这点,对于结构光系统一些公式推导就容易很多。
对于“双目”系统来说,最重要的工作是通过唯一标记来标记某一点,假设我们只投射一个周期的数据,我们从投影仪投出去的光栅公式如下:
其中:
比如说四步相移公式:
我们主要关心的是求解出相位主值,因为它对每个像素点是唯一的,假设我们从相机中获取了这四副图像,那怎么反过来求解相位主值?
需要说明的是,虽然这个公式对整副相移图像的,但是这公式对每个像素都是独立的,所以即使我们拿从相机拍摄到经过调制变形的图像来求解,依然可以得到单个像素点唯一的相位主值。
联立4个方程,得到:
无论:
哪台相机
拍摄到什么图像
我们要得到某个像素点的唯一“标记”,也就是这个相位主值,代回这个公式即可,都可以得到唯一值。得到了唯一值,建立匹配关系,就可以利用三角公式进行重建。
其中:横坐标为任意一行的像素,这张图中使用周期为11的像素条纹作为正弦光栅。
02 双频外差原理
解决的方法有很多,分为空域和时域展开两种:
空域展开:依靠空间相邻像素点之间的相位值恢复绝对相位,如果重建表面不连续,则出现解码错误。
时域展开:将每个像素点的相位值进行独立计算,有格雷码和多频外差两种,其中格雷码方法对物理表面问题敏感,并且多投影的图并不能用来提升精度,多频外差精度更高。
当然目前还有更多精度更高、效率更快的相位展开方法,在这里暂时不予讨论,这里主要讨论多频外差原理。
多频外差原理:通过多个不同频率(周期)正弦光栅的相位做差,将小周期的相位主值转化为大周期的相位差,从而使得相位差信号覆盖整个视场,然后再根据相位差来得到整副图像的绝对相位分布。
这里以双频外差为例,原理如图1所示:
注:通常我们说的相位函数的周期,代表的是一个周期正弦函数所占的像素单位个数。
03 多频率外差原理
其可以完成整个视场的无歧义标记。
04 代码实践
依据相移法得到的包裹相位图如下图所示,不同颜色代表不同频率的相位主值:
我们进行叠加后的效果:
在这里,我们可以看到,由两个周期小的相位可以合成一个周期更大的编码图案。
其中:
明白了原理,我们来代码实践一下,需要注意的是,求解出来的相位我们要进行归一化到区间操作:
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
def phase_simulation(WIDTH, T1, T2, T3):
pha1, pha2, pha3 = np.zeros(shape=WIDTH), np.zeros(shape=WIDTH), np.zeros(shape=WIDTH)
t1, t2, t3 = 1, 1, 1
for idx in range(WIDTH):
if t1 > T1: t1 = 1 # 重置一下
pha1[idx] = (t1 / T1) * 2 * np.pi
if t2 > T2: t2 = 1
pha2[idx] = (t2 / T2) * 2 * np.pi
if t3 > T3: t3 = 1
pha3[idx] = (t3 / T3) * 2 * np.pi
t1 += 1; t2 += 1; t3 += 1
return pha1, pha2, pha3
def parse_phase(pha1, pha2, T1, T2):
pha12 = np.zeros_like(pha1)
# 计算Delta(如果满足条件,输出左侧,否则右侧)
pha12 = np.where(pha1 >= pha2, pha1 - pha2, pha1 - pha2 + 2 * np.pi)
# # 跟下面这段代码等价
# for idx in range(0, pha12.shape[0]):
# if pha1[idx] >= pha2[idx]:
# pha12[idx] = pha1[idx] - pha2[idx]
# else:
# pha12[idx] = pha1[idx] - pha2[idx] + 2 * np.pi
T12 = T1 * T2 / (T2 - T1)
# 方法1
pha12 = T2 / (T2 - T1) * pha12
# # 方法2
# m = np.round((T2 / (T2 - T1) * pha12 - pha1) / (2 * np.pi))
# pha12 = 2 * np.pi * m + pha12
# 归一化到[0,2π]
min_value, max_value = np.min(pha12), np.max(pha12)
pha12 = (pha12 - min_value) * (2 * np.pi / (max_value - min_value))
return pha12, T12
if __name__ == '__main__':
# 视场宽度
WIDTH = 854
# 条纹周期
T1 = 11
T2 = 12
T3 = 13
pha1, pha2, pha3 = phase_simulation(WIDTH, T1, T2, T3)
X = np.arange(0, WIDTH)
plt.plot(X, pha1, label="pha1")
plt.plot(X, pha2, label="pha2:")
plt.plot(X, pha3, label="pha3")
plt.title("相移主值图(仿真)")
plt.xlabel("像素")
plt.ylabel("w/rad")
plt.legend()
plt.show()
# 解相位
pha12, T12 = parse_phase(pha1, pha2, T1, T2)
pha23, T23 = parse_phase(pha2, pha3, T2, T3)
pha123, T123 = parse_phase(pha12, pha23, T12, T23)
plt.plot(X, pha12, label="pha12")
plt.plot(X, pha23, label="pha23")
plt.plot(X, pha123, label="pha123")
plt.title("解出绝对相位")
plt.xlabel("像素")
plt.ylabel("w/rad")
plt.legend()
plt.show()
可以看出,最终解出的绝对相位线单调递增,每个相位值时唯一的,虽然在一些交界处会有些许误差。
结构光多频外差的原理很简单,而精度这块,其实很大程度依赖于标定、高反处理这些地方。这一期内容将分为上下两期,为了便于理解,不再讲述更多内容,更多我们下一期再讲!怎么拿实际投影拍摄到的光栅图片来还原绝对相位!
备注:作者也是我们「3D视觉从入门到精通」特邀嘉宾:一个超干货的3D视觉学习社区
本文仅做学术分享,如有侵权,请联系删文。
下载1
在「计算机视觉工坊」公众号后台回复:深度学习,即可下载深度学习算法、3D深度学习、深度学习框架、目标检测、GAN等相关内容近30本pdf书籍。
下载2
在「计算机视觉工坊」公众号后台回复:计算机视觉,即可下载计算机视觉相关17本pdf书籍,包含计算机视觉算法、Python视觉实战、Opencv3.0学习等。
下载3
在「计算机视觉工坊」公众号后台回复:SLAM,即可下载独家SLAM相关视频课程,包含视觉SLAM、激光SLAM精品课程。
重磅!计算机视觉工坊-学习交流群已成立
扫码添加小助手微信,可申请加入3D视觉工坊-学术论文写作与投稿 微信交流群,旨在交流顶会、顶刊、SCI、EI等写作与投稿事宜。
同时也可申请加入我们的细分方向交流群,目前主要有ORB-SLAM系列源码学习、3D视觉、CV&深度学习、SLAM、三维重建、点云后处理、自动驾驶、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、深度估计、学术交流、求职交流等微信群,请扫描下面微信号加群,备注:”研究方向+学校/公司+昵称“,例如:”3D视觉 + 上海交大 + 静静“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进去相关微信群。原创投稿也请联系。
▲长按加微信群或投稿
▲长按关注公众号
3D视觉从入门到精通知识星球:针对3D视觉领域的知识点汇总、入门进阶学习路线、最新paper分享、疑问解答四个方面进行深耕,更有各类大厂的算法工程人员进行技术指导。与此同时,星球将联合知名企业发布3D视觉相关算法开发岗位以及项目对接信息,打造成集技术与就业为一体的铁杆粉丝聚集区,近2000星球成员为创造更好的AI世界共同进步,知识星球入口:
学习3D视觉核心技术,扫描查看介绍,3天内无条件退款
圈里有高质量教程资料、可答疑解惑、助你高效解决问题
觉得有用,麻烦给个赞和在看~