目录
结构光与tof区别
结构光与tof都是可以直接生成深度图的深度相机,与tof不同,结构光是利用三角测距法配合投影仪计算深度图,其精度相比tof要更高一些能达到1mm内。结构光光学原理比tof要复杂一些,下面根据个人理解介绍一下结构光深度计算原理。
结构光格雷码计算原理
结构光组成主要分为投影仪和ir相机,投影仪可以投影格雷码或多频正弦相位图。格雷码和多频相位图主要用于唯一确定图像位置,格雷码由多张不同编码等级的二进制表示黑白格子图组成,不同等级的格雷码图可以通过将二进制0 1数字反复作对称与扩展而得到。等级越高,编码越复杂,可以唯一标记的像素宽度就越大,可以根据分辨率确定需要用到的格雷码图片个数。比如用五张格雷码图依次用投影仪投影到物体表面,相机接收物体反射回的图像,从图像表面的黑白灰度等级就可以解析出对应的格雷码位置。把整张图解析后就得到了所有的图像像素对应的格雷码对应投影仪表面的位置,物体表面深度变化不同,经过投影后的格雷码在相机像素坐标系的坐标也不同,因此可以反应深度变化。相机和投影仪的对应点位置关系确定后,如果把相机和投影仪看作双目,可以提前进行双目标定极线矫正。之后利用左右相机的对应像素根据基线尺寸利用三角测距即可计算对应深度值。
结构光多频外差计算原理
如果投影仪加载的是两张不同频率的正弦相位条纹图,相机接收的图像是灰度随正弦相位变化的图像,频率不同其灰度变化也不同,通过计算某一点的像素的灰度值可以计算其对应的正弦相位值,通过相位差法也可以计算两个频率唯一确定的相位点从而唯一确定相机图像与投影仪图像的对应位置关系,同理经过双目相机标定和三角测距方法可以计算整个图像的深度值。
综上就是结构光的计算深度基本原理,实际使用中可能会用到两个相机一个投影仪。并同时使用格雷码法和多频外差法,提高计算深度的精度,另外会用gpu cpu加速的方法提高算法计算速度。
结构光计算matlab代码
clear; clc;
close all;
%% 超参数
width = 1280; % 投影仪分辨率:高
heigth = 720; % 投影仪分辨率:宽
Ts = [70 64 59]; % freq = 1 / T,
A = 128; % 调制强度
B = 127; % 调制幅值
N = 12; % 相移步数
save_dir = "output/";
%% step1. 条纹生成
Is = cell(3, N);
for i = 1: 3
for k = 1: N
Is{i, k} = zeros(heigth, width);
end
end
for i = 1: 3 % 对应三种不同的频率
for k = 1: N % 对应N步相位
for x = 1: width
%Is{i, k}(:, x) = (A + B * cos(2 * pi * x / Ts(i) + (k - 1) * (2 * pi / N))) / 255.;
Is{i, k}(:, x) = (A + B * cos(2 * pi * Ts(i) * x / width + (k - 1) * (2 * pi / N))) / 255.;
end
m_save_phase_map(Is{i, k}, save_dir + "img" + int2str(k) + ".bmp");
end
end
%% step2. 包裹相位
pha = cell(3, 1);
for i = 1: 3
pha{i, 1} = m_calc_wrapped_phase(Is, N, i);
end
%% step3. 相位展开
pha1 = pha{1, 1};
pha2 = pha{2, 1};
pha3 = pha{3, 1};
pha12 = m_calc_absolute_phase(pha1, pha2);
pha23 = m_calc_absolute_phase(pha2, pha3);
pha123 = m_calc_absolute_phase(pha12, pha23);
%% step4. 查看结果
m_save_phase_map(pha1, save_dir + '1相位主值.bmp');
m_save_phase_map(pha2, save_dir + '2相位主值.bmp');
m_save_phase_map(pha3, save_dir + '3相位主值.bmp');
m_save_phase_map(pha12, save_dir + '1,2外差.bmp');
m_save_phase_map(pha23, save_dir + '2,3外差.bmp');
m_save_phase_map(pha123, save_dir + '1,2,3外差.bmp');
figure; plot(pha123(1, :)); title("某行相位.bmp");
相位计算函数
function pha12 = m_calc_absolute_phase(pha1, pha2)
mask1 = pha1 > pha2;
pha12 = (pha1 - pha2) .* mask1 + (2 * pi - (pha2 - pha1)) .* (1 - mask1);
end
相位解包裹
function pha = m_calc_wrapped_phase(Is, N, idx)
sin_sum = 0.;
cos_sum = 0.;
for k = 1: N
Ik = Is{idx, k};
sin_sum = sin_sum + Ik * sin(2 * (k - 1) * pi / N);
cos_sum = cos_sum + Ik * cos(2 * (k - 1) * pi / N);
end
pha = -atan2(sin_sum, cos_sum);
end
保存相位图
function [] = m_save_phase_map(pha, name)
figure(), mesh(mat2gray(pha)); title(name); xlabel('X'); ylabel('Y'); zlabel('Pha'); imwrite(mat2gray(pha), name);
end