结构光多频外差法原理和代码

2023-10-12 08:20

本文主要是介绍结构光多频外差法原理和代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、相移法原理

结构光法原理其实是跟双目视觉一样的,都是要确定对应“匹配点”,利用“视差”三角关系计算距离,所不同的是:

双目视觉通过“被动”匹配唯一特征点

相移法作为结构光法中的一种,通过主动投影多副相移图案来标记唯一位置。虽然大多数结构光系统是单目的,但我们可以将其“双目”的,因为投影仪可以看做是一个“逆向”的相机,明白了这点,对于结构光系统一些公式推导就容易很多。

对于“双目”系统来说,最重要的工作是通过唯一标记来标记某一点,假设我们只投射一个周期的数据,我们从投影仪投出去的光栅公式如下:

图片

其中:

图片

比如说四步相移公式:

图片

需要说明的是,虽然这个公式对整副相移图像的,但是这公式对每个像素都是独立的,所以即使我们拿从相机拍摄到经过调制变形的图像来求解,依然可以得到单个像素点唯一的相位主值。

我们主要关心的是求解出相位主值,因为它对每个像素点是唯一的,假设我们从相机中获取了这四副图像,那怎么反过来求解相位主值?

联立4个方程,得到:

图片

无论拍摄到什么图像,我们要得到某个像素点的唯一“标记”,也就是这个相位主值,代回这个公式即可,都可以得到唯一值。得到了唯一值,建立匹配关系,就可以利用三角公式进行重建。

图片

图片

其中:横坐标为任意一行的像素,这张图中使用周期为11的像素条纹作为正弦光栅。

2、双频外差原理

解决的方法有很多,分为空域和时域展开两种:

空域展开:依靠空间相邻像素点之间的相位值恢复绝对相位,如果重建表面不连续,则出现解码错误。

时域展开:将每个像素点的相位值进行独立计算,有格雷码和多频外差两种,其中格雷码方法对物理表面问题敏感,并且多投影的图并不能用来提升精度,多频外差精度更高。

当然目前还有更多精度更高、效率更快的相位展开方法,在这里暂时不予讨论,这里主要讨论多频外差原理。

多频外差原理:通过多个不同频率(周期)正弦光栅的相位做差,将小周期的相位主值转化为大周期的相位差,从而使得相位差信号覆盖整个视场,然后再根据相位差来得到整副图像的绝对相位分布。

这里以双频外差为例,原理如图1所示:

图片

图片

通常我们说的相位函数的周期,代表的是一个周期正弦函数所占的像素单位个数。

从上述公式可以看出,我们使用两种不同周期的相位值叠加得到一种周期更长的相位函数,为了能够利用多频外差原理实现全场无歧义的相位展开,我们必须选择合适的T1和T2,使得T12能够超过整个视场,从而获得唯一的相位。

3、多频率外差原理
图片

图片

其可以完成整个视场的无歧义标记。

4、代码实践
图片

依据相移法得到的包裹相位图如下图所示,不同颜色代表不同频率的相位主值:

图片

我们进行叠加后的效果:

图片

在这里,我们可以看到,由两个周期小的相位可以合成一个周期更大的编码图案。

图片

图片

其中:

图片

明白了原理,我们来代码实践一下,需要注意的是,求解出来的相位我们要进行归一化到区间操作:

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, 1for idx in range(WIDTH):if t1 > T1: t1 = 1  # 重置一下pha1[idx] = (t1 / T1) * 2 * np.piif t2 > T2: t2 = 1pha2[idx] = (t2 / T2) * 2 * np.piif t3 > T3: t3 = 1pha3[idx] = (t3 / T3) * 2 * np.pit1 += 1; t2 += 1; t3 += 1return pha1, pha2, pha3def 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.piT12 = T1 * T2 / (T2 - T1)# 方法1pha12 = 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, T12if __name__ == '__main__':# 视场宽度WIDTH = 854# 条纹周期T1 = 11T2 = 12T3 = 13pha1, 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()

测试结果如下:

图片

图片

可以看出,最终解出的绝对相位线单调递增,每个相位值是唯一的,虽然在一些交界处会有些许误差。结构光多频外差的原理很简单,而精度这块,其实很大程度依赖于标定、高反处理这些地方。

这篇关于结构光多频外差法原理和代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/194558

相关文章

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

hdu4407容斥原理

题意: 有一个元素为 1~n 的数列{An},有2种操作(1000次): 1、求某段区间 [a,b] 中与 p 互质的数的和。 2、将数列中某个位置元素的值改变。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.Inpu