记录一下c++零基础入门3D结构光投影,这是初步的12步相移+7副格雷码(4副4位格雷码+一副互补+两张黑白)解码全过程,解码的图片也都是网上找的。
之前没学过c++,也没有任何语言基础,所以写的时候就是按照公式推导的思路来完成。
总的来说,格雷码就是解出来级次:K=1、2、3、...N,相移解出对应级次的包裹相位,结合二者得出绝对相位。
目录
一、生成格雷码和互补格雷码
首先根据需求选择需要投影的格雷码张数,这里我用的4副格雷码(既n=4),周期为2^n为16,生成格雷码原理这里不赘述,网上生成格雷码的代码很多。
生成的格雷码为:{0000、0001、0011、0010......1000}
将格雷码转成4*16的矩阵,矩阵的每一行代表所生成的格雷码图片(0代表黑色,1代表白色)
如果只使用格雷码来解包裹相位,会出现边缘跳变的问题,因为格雷码边缘部分对应了相位的边缘部分,为了解决这个问题,我们引入互补格雷码,使互补格雷码稳定的那一部分对应相位出现跳变的那一部分:
我生成互补格雷码的方式就是在格雷码后面加上0、1、1、0这样循环后缀,代码如下:(没学过,写的都是流水账)
vector<string>hbgraycode;
for (int i = 0; i < 8; i++) {
string hbgraycodes1 = grayCodes[2 * i] + to_string(0); //由于互补格雷码的特点是 0110循环
hbgraycode.push_back(hbgraycodes1);
string hbgraycodes2 = grayCodes[2 * i] + to_string(1); //2i和2i+1其实就是第一个和第二个格雷码
hbgraycode.push_back(hbgraycodes2);
string hbgraycodes3 = grayCodes[2 * i + 1] + to_string(1); //给第一个和第二个格雷码后面分别加0或者1,
hbgraycode.push_back(hbgraycodes3);
string hbgraycodes4 = grayCodes[2 * i + 1] + to_string(0); //等同生成四个五位格雷码
hbgraycode.push_back(hbgraycodes4);
}
二、生成格雷码投影图像
我用的投影光机为DLP3010,需要投影的图像为8bit且大小为1*1280,所以在生成投影图案时,将格雷码与互补格雷码生成1*1280的矩阵,除80是因为图像宽度为1280,周期为16,所以每一个条纹间隔宽度为80,互补格雷码生成原理一样。
Mat patternMat(4, 16, CV_8UC1);
projImg[i].at<uchar>(y, x) = patternMat.at<uchar>(i, x / 80);
三、生成相移投影图像
这个原理网上一大堆更详细,不赘述,自己理解原理写,我这里用的12步相移图
四、建立格雷码映射关系
如果给你投影相移条纹图片,你怎么能找到它的位置它是哪根条纹呢,这时候就需要投影的格雷码来辅助了,投影的格雷码条纹图其实就是让你遍历每一个像素点,让其还原成对应的格雷码,比如说我投影了四张格雷码,在(0,0)这个位置点,第一张图像素点为黑色(0),第二张为黑色(0),第三张第四张都为黑色(0),那么在(0,0)这个位置点对应的格雷码就为{0000},转为十进制为0,以此类推每一个像素点,公式为:
其实就是转成8421,我们一共会得到16个十进制码(V):
K就是为了方便映射出来的序号而已,c++用map<>这个函数,或者不用映射让两个数组一一对应也行,但是互补格雷码就只能用映射了,根据以下公式,先将互补格雷码转为十进制(实质就是168421码):
K2虽然只到16,但其对应了32个元素,实质K2为{0、1、1、2、2、3、3...15、15、16},找规律发现K2是从1-33除2取证得到的(在c++记得手动取整!!!!!就是因为这一步错了导致解码一直有错!!!!!),建立其与V2的映射即可。
五、解格雷码
解格雷码我们需要解四位格雷码和加上互补的五位格雷码两种,
简单来说:读图遍历像素点——格雷码转成十进制(V)——V查找映射表换成K
![](https://img-blog.csdnimg.cn/995831cbfc8b42059904845178199bb8.png)
![](https://img-blog.csdnimg.cn/59db58f65c864863bca1fd925dbb8101.png)
可以发现互补格雷码比格雷码提前了半个周期,每一种条纹代表一个K,是从小大到排列的阶梯状
六、求包裹相位
求包裹相位的公式为:
I为图像的灰度,遍历每一个像素点的灰度值就行,N代表相移步数,根据此求出相位主值。 求出的相位包裹在-pai到pai之间,周而复始。
![](https://img-blog.csdnimg.cn/ab508c4022aa40bd954fc71889699cd9.png)
七、求绝对相位(解包裹)
K求出的是阶梯状的序号,而相位主值被包裹在[-pai,pai]直接,K对应的就是第K个相位,为了展开相位,将第K个相位挨个往上抬K*2pai个相位值,使其连续展开,K1的边缘和相位主值的边缘是对齐的,所以K1的边缘不稳定也会使求包裹相位时出现边缘跳变现象,为了解决所以引入互补格雷码,使其互补格雷码中间稳定的部分对其相位主值边缘部分(看下图很好理解)
所以绝对相位就为:
![](https://img-blog.csdnimg.cn/6e1db5b4aa434a649d8db1e6b1462bcf.png)
此时解包裹相位就完成,后续根据标定相机和投影仪数据建立相高模型。