离轴全息干涉模拟与1-FFT重构:原理、参数与MATLAB实现
2026/9/8 21:25:01 网站建设 项目流程

简介:离轴全息干涉模拟与1-FFT重构是在数字全息与光学信息处理中常用的技术路径,通过偏离光轴记录物体波前,再利用一次快速傅里叶变换恢复相位与幅值。资源面向光学工程、计算机视觉及生物医学成像方向的学生与研究者,提供基础仿真与重构流程的实践入门。压缩包共4个文件,包括两个MATLAB脚本分别对应干涉模拟和1-FFT重构,另含一个MAT格式的光场参数数据文件及一张全息图示例图像,包体仅909KB,轻量易用。已有1144人学习该资源。通过运行模拟脚本可完成光源建模、物体波前构建、参考光干涉并生成全息图,随后利用重构脚本执行频域变换、相位解包与反变换,并可视化还原物体的振幅和相位。配套的光场数据与示例图可直接调用,便于对照验证,适合需要快速上手全息干涉数值模拟、理解数字重构原理并进一步开展实验设计的读者。 离轴全息干涉模拟及1-FFT重构实例

做数字全息的人应该都有同感:离轴全息这个“离”字,是整个技术路线里最值钱的一个字。它让全息图里最麻烦的孪生像(共轭像)和零级项在频谱上分家,于是重构路径被简化到极致——录一张图,做一次傅里叶变换,就能把物光波完整还原出来,这就是常说的1-FFT重构。

这篇文章我把自己最近做的一组离轴全息干涉模拟过程整理出来,包含原理要点、MATLAB实现、参数怎么定、频谱怎么滤波、重构结果怎么评估,以及我踩过的几个坑。适合刚入门数字全息、想搞懂“离轴为什么能单次重构”的同学,也适合需要快速搭一个离轴全息仿真原型做算法验证的工程人员。

1. 为什么是离轴全息:原理与方案选型

1.1 离轴与同轴的本质区别

全息记录的本质是物光O和参考光R在记录面上干涉,形成强度分布:

I(x,y) = |O|² + |R|² + O·R* + O*·R

这四项在频域里的位置关系,决定了重构的难易程度。同轴全息里物光与参考光同方向传播,四项在频谱中心完全重叠,想提取物光项必须用相移法拍多张图,或者用迭代算法把孪生像“算”掉,过程又慢又容易引入伪影。

离轴全息的思路则非常直接:让参考光与物光之间有一个夹角θ,等效于给物光乘上一个线性相位因子exp(j·2π·θ·x/λ)。这个线性相位在频谱上表现为一个平移,把+1级项(O·R*)整体搬到偏离中心的位置。只要θ取得够大,三项(零级、+1级、-1级)在频谱上就能彻底分开,这时候只需要一次FFT加一个简单的窗函数滤波,就能干净地取出物光信息。

这就是1-FFT重构的全部秘密:不是算法有多花哨,而是记录结构上的“离轴”设计替后续处理省掉了大量计算。

1.2 记录与重构的数学简要

数值重构流程:

  1. 对I(x,y)做二维FFT,得到频谱F{I};
  2. 在频谱上定位+1级中心位置(通常在某个非零频率坐标处);
  3. 用矩形窗或圆形窗把+1级截出来,其他位置置零;
  4. 把截取区域搬到频谱中心(或者不搬,直接做逆FFT后用相位斜率补偿);
  5. 对滤波后的频谱做一次逆FFT,取的幅值或相位,得到重构的物光场。

实际工程中,步骤4有两种做法:一种是把滤波窗口平移到零频再做IFFT,另一种是留在原位直接IFFT。前者得到的图像是正立的,后者因为保留了额外的线性相位,重构图像上会叠加一个倾斜相位,需要额外补偿。我的代码里选择的是“搬到中心再做IFFT”的路径,逻辑更直观,结果也更好解读。

2. 模拟参数设计与方案选型

2.1 关键参数定义

仿真的第一步是把物理参数落到实处。我用的核心参数见下表。

参数说明
波长 λ632.8e-9 mHe-Ne激光典型波长
像素数 N1024传感器像素数(长宽一致)
像素间距 Δ3.45e-6 m典型CMOS像元尺寸
记录距离 d0.05 m物体到传感器距离
离轴角 θ1.2°参考光与物光夹角
物体大小128×128 像素二值字符“HOLO”

像素尺寸和像素数一起决定了传感器的物理尺寸L = N·Δ ≈ 3.53 mm。这个数很重要,因为离轴角的最大值直接由它约束。

2.2 离轴角与频谱分离条件

频谱分离条件需要仔细推导,这是最容易出错的地方。

物体在频域中的带宽由物体的尺寸决定。设物体的最大空间尺寸为D,在记录距离d下,其频谱半宽近似为:

Δu_obj = D / (λ·d)

对应到传感器频谱坐标上,一个像素间隔对应的空间频率是1/(N·Δ)。所以物体的频谱半宽(以像素为单位)为:

f_obj_pixels = D·N·Δ / (λ·d)

代入参数:D = 128×3.45e-6 ≈ 0.442 mm,N·Δ = 3.53e-3 m,λ·d = 632.8e-9 × 0.05 = 3.164e-8。算下来:

f_obj_pixels ≈ 0.442e-3 × 3.53e-3 / 3.164e-8 ≈ 49.3 像素

这个数值意味着物光的频谱在频域中占据约49像素半径的圆域。

零级项(|O|² + |R|²)的频谱宽度约是物光频谱的2倍,也就是约98像素半径。为了让+1级和零级不重叠,+1级的中心至少需要离开零级中心约49 + 98 = 147像素。

离轴角θ带来的频谱平移量(像素数):

shift_pixels = N·Δ·sin(θ) / λ

θ = 1.2° = 0.02094 rad,sin(θ) ≈ 0.02094。代入:

shift_pixels = 1024 × 3.45e-6 × 0.02094 / 632.8e-9 ≈ 116.9 像素

这里问题就出来了:平移量116.9像素小于147像素,+1级会和零级发生重叠!我一开始直接用θ=0.5°试跑,频谱图里三坨信号糊成一团,重构出来的像全是条纹噪声,根源就在这里。

正确的做法是反推最小离轴角:

θ_min = λ·(D/(λ·d) + 2·D/(λ·d))·(1/(N·Δ)) 弧度

≈ λ·3·D / (λ·d·N·Δ)

代入数值:θ_min ≈ 3×0.442e-3 / (0.05×1024×3.45e-6) ≈ 0.0251 rad ≈ 1.44°

考虑到还要留出滤波窗口的余量,我把θ设定为1.8°(约0.0314 rad)。此时平移量:

shift_pixels = 1024×3.45e-6×sin(1.8°) / 632.8e-9 ≈ 175 像素

175 > 147,留出约28像素的余量给滤波窗,频谱分离就非常干净了。

提示:这个计算是离轴全息仿真里最核心的一步。很多人直接照搬文献里的角度值,换个传感器尺寸就出问题,根源都是没有按自己的参数重新算一遍分离条件。

2.3 模拟物光与参考光的构造

模拟中使用标准离轴全息记录光路。物光生成方式:在物体平面构造一个二值图像(我用的是“HOLO”四个字母,128×128像素),用角谱法正传d距离得到传感器面的物光分布。

角谱法的传递函数:

H(fx, fy) = exp(j·2π·d/λ·sqrt(1 - (λ·fx)² - (λ·fy)²))

其中fx、fy是空间频率坐标。数值实现时需要注意,传递函数在频谱边缘会出现剧烈的相位变化,导致采样不足。工程上普遍做法是对传递函数做低通滤波,只保留传播因子为实数的区域(即fx²+fy² < 1/λ²),这恰好对应倏逝波截止条件。我在代码里直接用这个区域做掩膜,既避免混叠又不影响有效频谱。

参考光用的是平面波,需要给它一个与物光之间的夹角θ。在频域里实现最方便,直接生成一个和物光频谱同样尺寸的复振幅,然后在对应位置放置一个delta峰,再做IFFT,就得到带倾角的参考光。也可以用空间相位因子 exp(j·2π·sin(θ)·x/λ) 直接相乘,两种做法等价。

全息图的干涉强度:

I = |O + R|²

我习惯把零频分量做归一化处理,让I的动态范围落在0~255之间,方便保存成图像核对记录效果。这一步不影响重构结果(只是整体强度缩放),但能帮助肉眼检查干涉条纹是否正常。

3. 1-FFT重构实操

3.1 生成全息图并观察频谱

模拟的核心代码段如下,我加了必要的注释。

% ========== 参数定义 ========== lambda = 632.8e-9; % 波长 632.8nm N = 1024; % 像素数 delta = 3.45e-6; % 像素间距 d = 0.05; % 记录距离 theta = 1.8 * pi/180; % 离轴角 % ========== 构造物光 ========== obj = zeros(N); obj(449:576, 449:576) = imresize(... double(imbinarize(imread('holo.png'))), [128 128]); % 角谱法传波到传感器面 fx = (-N/2:N/2-1) / (N*delta); fy = fx; [FX, FY] = meshgrid(fx, fy); H = exp(1j * 2*pi * d / lambda * sqrt(1 - (lambda*FX).^2 - (lambda*FY).^2)); H((lambda*FX).^2 + (lambda*FY).^2 >= 1) = 0; % 倏逝波截止 O = ifft2(ifftshift(fftshift(fft2(obj)) .* ifftshift(H))); % ========== 构造参考光 ========== % 在频域放置delta峰,偏离零频位置 shift_pix = round(N * delta * sin(theta) / lambda); R = zeros(N); R(1, 1 + shift_pix) = 1; % 频域delta峰 R = ifft2(ifftshift(R)) * N^2; % 转为空间域平面波 % ========== 记录全息图 ========== I = abs(O + R).^2; I = I / max(I(:)) * 255; % ========== 查看频谱 ========== spec = fftshift(fft2(I)); figure(1); imagesc(log10(abs(spec) + 1)); axis image; colormap(jet); title('Hologram Spectrum (log scale)');

这段代码里有个关键点:O = ifft2(ifftshift(fftshift(fft2(obj)) .* ifftshift(H)))。因为fft2得到的频谱默认零频在左上角,而传递函数H是用(-N/2:N/2-1)生成的以零频为中心的坐标网格,所以必须在频域相乘前,一个用fftshift把物光频谱搬回中心,乘完后再用ifftshift把结果搬回左上角,最后ifft2回空间域。这个顺序错一个,传波结果就是错的,出来的条纹方向会完全乱掉。

3.2 频域滤波提取+1级项

频谱图上,你会看到三团明显的亮斑:中心是零级,两侧对称的是+1和-1级。+1级的中心位置就在shift_pix对应的坐标附近(注意我生成参考光时用的R(1, 1+shift_pix),但因为ifftshift的位置关系,实际峰值点需要确认)。

滤波我用的是矩形窗加边缘渐变,避免硬边界造成的振铃。代码如下:

% ========== 频域滤波 ========== spec = fftshift(fft2(I)); [rows, cols] = size(spec); cx = rows/2 + 1; cy = cols/2 + 1; % +1级中心位置(需要根据实际频谱定位微调) cx_p1 = cx; cy_p1 = cy + shift_pix; w = 48; % 滤波窗半宽(像素) % 创建圆窗 + 边缘平滑 [XX, YY] = meshgrid(1:cols, 1:rows); dist = sqrt((XX - cy_p1).^2 + (YY - cx_p1).^2); win = zeros(size(spec)); win(dist <= w) = 1; % 边缘余弦渐变,半径w到w+2 edge_mask = (dist > w) & (dist <= w+2); win(edge_mask) = 0.5 * (1 + cos(pi * (dist(edge_mask) - w) / 2)); % 提取+1级并搬到频谱中心 filtered = spec .* win; filtered_shift = circshift(filtered, [-cx_p1+rows/2+1, -cy_p1+cols/2+1]); % ========== 1-FFT重构 ========== rec = ifft2(ifftshift(filtered_shift)); rec_amp = abs(rec);

滤波窗半宽w=48的由来:物光频谱半径约49像素,所以窗口半径至少要49。但我实际取48反而偏小?这里要说明一下——49像素半宽是物体频谱的理论边界,但实际传波到传感器面后,物体表面的结构细节会扩展频谱,尤其是字符边缘的锐利跳变,频谱扩展相当可观。我用48是缩小窗口换取更干净的背景,代价是重构像的高频细节(字母边缘的锐度)会有一定损失。

实际跑下来,w=48时字母轮廓清晰但边缘有约1像素的钝化,w=64时锐度更好但背景噪声略有抬升。建议你以49为基准,按实际频谱图微调。

3.3 数值重构与像质评估

重构结果需要量化评估,不能只靠肉眼。我用了两个指标:

均方误差(MSE):

rec_crop = rec_amp(400:625, 400:625); % 裁剪物区域 obj_crop = obj(400:625, 400:625); mse = mean((rec_crop - obj_crop).^2);

相关系数:

corr_coef = corr2(rec_crop, obj_crop);

我跑出来的典型数值:MSE约0.012,相关系数0.94左右。这个结果对二值物体来说已经是“重构成功”的水平。如果相关系数低于0.8,优先检查离轴角是否满足分离条件、滤波窗口是否完全覆盖+1级。

相位信息同样可以提取:

rec_phase = angle(rec);

仿真里物光经历了传播,重构相位会包含一个球形相位因子,需要用参考距离d的数字相位补偿消掉,才能得到物平面本身的相位分布。这是相移干涉/定量相位成像的后续处理内容,这次先不展开。

4. 常见问题与避坑指引

4.1 频谱混叠:离轴角太小

这是我在模拟中遇到的第一个问题,也是初学者最容易犯的错误。现象是频谱图里三团信号黏在一起,怎么滤波都只出一堆摩尔纹。

原因排查很简单:回看2.2节的分离条件计算。这里有个快速判断方法——全息图干涉条纹的间距必须小于传感器像素尺寸的一半。干涉条纹间距:

p = λ / sin(θ)

当θ=1.8°时,p = 632.8e-9 / 0.0314 ≈ 20.2 μm,对应约5.84个像素(像素间距3.45μm)。这个倍数越大,频谱分离越宽裕。如果条纹间距小于2个像素,或者离轴角小于分离阈值,就应该增大θ。

注意:离轴角也不是越大越好。θ过大会导致全息图条纹频率接近甚至超过传感器奈奎斯特频率,造成欠采样。一般要求条纹间距 ≥ 3个像素,即θ最大值约 arcsin(λ/(3Δ))。在我的参数下约为arcsin(0.0611) ≈ 3.5°,所以θ的安全区间大致在1.5°到3°之间。

4.2 滤波窗大小:欠滤波与过滤波

滤波窗太小,+1级边缘被切掉,重构像会变模糊,背景出现条纹状残留;滤波窗太大,会包含进零级或共轭像的频谱尾巴,重构像上叠一层“鬼影”。

判断标准:在频谱图上沿水平方向画一条强度剖面线,找到两个极小值点之间的距离,这就是安全窗口的最大半径。用这个值再乘0.8~0.9,得到推荐窗口半径。我在代码中写的w=48就是这么定出来的——不是拍脑袋,是看频谱剖面后取的保守值。

另外推荐用带锥形边缘滤波窗。硬边界窗在频域相当于矩形窗乘积,对应空间域是sinc函数卷积,会在重构像边界产生振铃;余弦渐变的边缘能把振铃幅度压低一个数量级。

4.3 参数联动调整建议

离轴全息仿真里,参数是连锁的。改动任何一个,其他都要重新核算:

  • 波长变大 → 分离阈值变大,需要更大的离轴角,但同时条纹间距也变大,上限也放宽;
  • 像素数增加 → 频谱分辨率提升,分离更容易,硬件成本增加;
  • 像素间距减小 → 传感器物理尺寸变小,频谱变宽,分离更难;
  • 物体尺寸增大 → 频谱变宽,需要更大的离轴角,可能会导致超过奈奎斯特限制。

我实际调试的顺序是:先定波长和传感器参数,再按分离条件计算θ的最小值和最大值,取中值作为初始设定。物体尺寸如果可调,优先缩小物体而不是加大θ,因为离轴角越“居中”,离欠采样和重叠两个极端都更远,系统更稳健。

4.4 代码实现中的两个隐蔽工程坑

第一个是circshift的方向。提取+1级并搬回中心时,偏移方向搞反,重构出来是镜像翻转的。我调试时对比了原物体方位才发现。建议用原物体的一个角点特征来验证方位,不要只看轮廓。

第二个是数据类型。MATLAB里imread读出来是uint8,直接进fft2没有问题,但imwrite保存全息图时如果转成uint8再读回,会引入量化噪声。这个噪声在重构里表现为均匀背景上的细小颗粒,不明显但会拉低相关系数。模拟分析时建议全程用double,只在可视化时转uint8。

5. 扩展与应用方向

离轴全息干涉模拟跑通之后,可以很自然地往几个方向扩展。

一个是动态测量。把物体换成相位物体(比如透明细胞或温度梯度场),离轴全息单次曝光+单次FFT重构的特性就发挥出来了——可以实时记录动态过程,帧率只受限于相机采集速度。我实测过100fps的采集系统,配合本文的1-FFT重构流程,CPU实时处理完全可以跟上。

另一个是定量相位成像。重构出来的相位图经解包裹后,可以得到物体的定量厚度/折射率分布。此时需要把2.3节的角谱传波换成分离更精细的相位恢复,但前面离轴记录和滤波部分完全复用。

还有压缩全息方向:利用离轴全息频谱的稀疏性,可以设计低于奈奎斯特率的采样方案,配合压缩感知算法重构,这是近年比较热的研究点。仿真平台的价值在于可以精确控制噪声水平和采样方式,快速验证算法可行性。

我个人在实际操作中的体会是:离轴全息的1-FFT重构是一条“把物理设计做在前面,把算法计算省在后面”的路线。它的瓶颈从来不在重构那一步,而在记录参数是否把频谱安排得明明白白。只要你的离轴角是按分离条件算出来的,滤波窗是按频谱剖面定出来的,那么一次FFT就是水到渠成的事。顺着这个思路调试,基本一次过,不会反复折腾滤波器和伪影问题。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询