资讯动态

傅立叶变换与相位掩膜:用Matlab实现双随机相位编码图像加密

发布时间:2026/10/2 15:21:48 来源:尧图企业网站定制
图像加密方向如果只挑一个入门方案来吃透我强烈建议看傅立叶变换加相位掩膜这条链路。这套方法在图像加密领域有个专门的名字——双随机相位编码DRPE最早来源于光学4f系统后来被大量用在数字图像加密的课程设计和研究论文里。它的核心思路并不复杂输入面放一块随机相位掩膜频谱面再放一块随机相位掩膜图像经过两次傅立叶变换后就变成与原始内容毫无视觉关联的复噪声分布只有同时掌握两块相位掩膜的人才能用共轭相位把图像解出来。这篇文章我用Matlab从零实现并验证了这套算法涵盖加密链路、解密链路、参数选择、安全性评估和排坑经验。目的不是给你一段能跑的空壳代码而是把“为什么这样做”讲透为什么选傅立叶变换、为什么相位掩膜能保密、解密时为什么要做共轭相乘、取幅度时为什么不会丢信息。适合正在做数字图像处理大作业的本科生、想快速跑通图像加密demo的研究生以及任何对光学信息安全感兴趣的读者。1. 项目需求与技术选型为什么看中傅立叶变换和相位掩膜1.1 传统图像保护手段的短板图像数据的特殊性在于它天生是二维的相邻像素之间有极强的相关性而且数据量很大。如果直接把一串像素交给AES、DES这类经典分组密码去处理虽然安全但耗时高加密后的数据也完全没法做预览、检索、特征比对等操作。很多场景其实只需要让第三方看不到图片内容或者让窃听者拿到的文件看起来是一堆噪声这就给了光学加密和频域加密发挥的空间。传统的图像置乱方法比如Arnold变换、骑士巡游、幻方置乱本质上是在空域做坐标重排。这类方法的优点是简单、可逆缺点是密文的直方图几乎和明文一模一样只是像素位置变了攻击者用统计特征的关联分析很容易猜出原始图像的内容大类。另一个常见思路是混沌序列扩散用混沌系统生成伪随机序列去替换灰度值效果比置乱好很多但它逐像素操作很难直接映射到光学硬件上且如果不和置乱结合抗选择明文攻击的能力有限。这个背景下把傅立叶变换引入加密就顺理成章了。透镜本身就是天然的傅立叶变换器二维傅立叶变换能把图像的能量重新分布到频域再配合随机相位进行调制信息会散开到整个平面。这套思路早在1995年就被Javidi等人系统提出后来成为光学信息安全领域的奠基框架。1.2 方案对比置乱、混沌与DRPE的取舍我整理了一张对比表方便你直观感受不同方案的定位差异。方案核心原理优点短板像素置乱Arnold等空域坐标重排实现简单、完全可逆直方图不变统计泄露严重混沌序列扩散灰度值替换密钥空间大、敏感性高单像素操作并行性和光学实现弱纯频域变换加密频谱分块置乱/滤波天然支持频域处理缺少随机调制频谱统计信息易泄露DRPE双随机相位编码空域频域双重随机相位调制密钥空间大、密文类白噪声、可光学并行数字仿真密文为复数存储传输需特殊处理DRPE最吸引我的一点是它的物理背景极其直观光通过透镜就是一次傅立叶变换相位掩膜可以看作一块随机起伏的光学玻璃光经过它后相位被随机扰乱。两块随机相位板一前一后直接改变了光场的相位分布最终输出面的光强变成散斑噪声信息被完全隐藏。数字Matlab实现只是把这套物理过程用矩阵运算重新走了一遍但理解了光学链路再写代码思路会异常清晰。1.3 适合的场景与实验定位这个项目放在本科数字图像处理课程里属于光学变换类的高阶题目放在信息安全专业的课程里能作为光学加密的入门实验。做这个项目不需要真正搭建光学平台用Matlab的fft2和ifft2就能完整模拟。但如果后续要扩展到光学实验透镜型号、相位板加工精度、CCD记录方式等物理参数会变成新的变量这部分我放到第6章讨论。对于刚入门的朋友先把数字域的加密解密链路跑通建立起“复数信号、相位调制、正逆变换配对”的感觉比急着追求复杂密钥结构重要得多。2. 算法核心原理双重随机相位编码到底做了什么2.1 加密链路空域调制、频域调制与逆变换先给加密过程一个整体的数学描述它只有四步。设原始图像为 I(x,y)两块相位掩膜分别为 P1(x,y) 和 P2(u,v)其中 P1 在输入平面P2 在频谱平面。加密输出 C(x,y) 可以写成C(x,y) IFT{ FT{ I(x,y) · exp(i·P1(x,y)) } · exp(i·P2(u,v)) }拆开来看第一块相位掩膜乘在图像上相当于对原始图像的每一个像素做一个随机相位偏转。图像本来是实函数相乘之后变成复函数它的傅立叶谱不再是共轭对称的信息分布被彻底打破。如果只有这一步攻击者还能从频谱幅度里看出明文的轮廓因为输入面的随机相位只改变相位不改变幅度谱的大致分布。第二块相位掩膜乘在频谱上意义完全不同。它是在频域对每个傅立叶系数再做一次单位模长复数的旋转。因为 exp(i·P2) 的模长恒为1所以不会改变频谱的幅度能量但会把每个频点携带的相位信息随机化。频域相位正是图像信息最密集的载体相位一旦被打乱逆变换回到空域后能量会散布到整个输出平面形成类似白噪声的复数分布。最后再用一次逆傅立叶变换收尾输出密文。从卷积角度理解更接地气频域相乘对应空域卷积频谱平面上的随机相位掩膜等效于一个冲击响应非常复杂的卷积核。图像通过这个卷积核之后原本集中在局部区域的信息被弥散到全局。这就像把一张写满字的纸彻底切碎再均匀撒到整个房间里没有拼图规则根本还原不回来。2.2 解密链路相位共轭还原的数学机理解密过程在设计上几乎是对称的但顺序不能乱。解密端拿到密文 C(x,y) 后需要用到 P1 和 P2 的负值也就是共轭相位。完整链路为I(x,y) | IFT{ FT{ C(x,y) } · exp(-i·P2(u,v)) } · exp(-i·P1(x,y)) |核心逻辑来自一个非常简单的复数事实exp(iθ)·exp(-iθ)1。密文先做一次正向傅立叶变换回到频谱域。此时只要乘上第二块相位掩膜的共轭频域相位调制刚好抵消得到未被P2调制的频谱。然后再做逆傅立叶变换回到空域得到带有第一块相位掩膜调制的复振幅分布。这时再乘上第一块相位掩膜的共轭输入面的相位也被抵消剩下原始图像的实数值。这里有个容易绕晕的细节为什么加密端最后用 ifft2而解密端第一步用 fft2从纯数学角度正变换和逆变换本来就是一对可逆操作fft2(ifft2(X)) X。加密端选择“fft2进、ifft2出”解密端就必须“fft2进、ifft2出”形成完整回路。如果你在加密端最后也用了 fft2那解密端第一步就要换成 ifft2否则结果会带尺度误差。这一点我在第5章的排坑部分会专门展开。2.3 密钥空间与安全性的底层底气这套算法的密钥就是两块随机相位掩膜矩阵本身。以256×256的灰度图为例每块相位板包含65536个独立相位值每个相位理论上可以在[0, 2π)内连续取值。如果每个相位被量化到12位单独一块板的密钥空间就是2^(65536×12)量级两块板叠乘之后是一个天文数字。密钥敏感性也非常强。频域相位掩膜哪怕只有一个频点的相位值差了0.001弧度逆变换回来时这个误差会被扩散到所有像素上解密结果直接退化成噪声。这就是“雪崩效应”密钥微小的改变带来密文或解密结果的剧烈变化是密码系统的基本要求。DRPE天然满足这一点因为傅立叶变换本身是全图耦合的变换任何一个频点的相位变化都会影响整个空域输出。需要提醒的是密钥空间大不等于无条件安全。经典DRPE在已知明文攻击下存在被破解的可能性这部分我在第6章会专门说明因为很多初学者会把“密钥空间巨大”直接等同于“绝对安全”。3. Matlab完整实现从预处理到解密还原3.1 输入图像准备灰度、归一化与数据类型Matlab里实现这套算法最容易被忽略的其实是数据处理。我建议统一按下面的流程准备输入读入图像后先判断是不是彩色图如果是用rgb2gray转成灰度图。彩色图像虽然可以对三个通道分别加密但实验阶段没必要增加负担。把图像转成double类型并归一化到[0,1]区间这一步直接影响后续数值稳定性和PSNR计算。随机相位掩膜用rand(M,N)2pi生成让相位均匀分布在[0,2π)之间。这里不要用高斯分布因为相位本质上是圆上的变量均匀分布才能最大化相位熵。关于归一化有个典型坑Matlab的im2double函数对uint8类型会自动除以255但对已经是double类型的矩阵不做任何缩放。如果你先用double(I)把图像变成0~255范围的double矩阵再调用im2double它依然返回0~255范围的数据。所以我习惯自己写判断而不是盲目依赖im2double。统一的数据预处理代码I imread(cameraman.tif); if size(I, 3) 3 I rgb2gray(I); end if isa(I, uint8) I double(I) / 255; else I double(I); end这样处理之后I的所有像素值都在[0,1]内后面无论做fft2还是计算PSNR量纲都是统一的。3.2 加密函数实现随机相位生成与FFT链路加密函数我封装成独立的m函数输入是归一化后的灰度图像输出是加密结果和两块相位掩膜。相位掩膜直接作为函数输出返回方便后续存储和复现。function [encrypted, Phase1, Phase2] drpe_encrypt(I) [M, N] size(I); Phase1 2 * pi * rand(M, N); % 输入面随机相位掩膜 Phase2 2 * pi * rand(M, N); % 频谱面随机相位掩膜 f I .* exp(1i * Phase1); % 空域相位调制 F fft2(f); % 第一次傅立叶变换 E F .* exp(1i * Phase2); % 频域相位调制 encrypted ifft2(E); % 逆变换回空域得到密文 end这段代码只有六行但每一步背后的意图必须清楚。exp(1iPhase1)本质上是构造一个单位模长的复数矩阵乘到图像上不改变幅度能量只改变相位方向。fft2把空间域信息映射到频率域得到的是复频谱。exp(1iPhase2)再次做相位旋转直接作用于频谱的每个复数值上。注意这里用的是点乘而不是矩阵乘法理由很简单相位掩膜需要和频谱逐点对应不是做线性代数意义上的矩阵乘。为什么要用ifft2而不是fft2作为最后一步因为这样和解密端的fft2构成正逆变换对数学上最直接、数值误差最小。ifft2自带1/(M*N)归一化与fft2配合刚好形成完整的离散傅立叶变换对。3.3 解密函数实现共轭还原与幅度提取解密端看起来是加密端的逆过程但顺序和操作符都需要仔细对齐。function decrypted drpe_decrypt(encrypted, Phase1, Phase2) E fft2(encrypted); % 密文回到频谱域 F2 E .* exp(-1i * Phase2); % 乘共轭相位抵消频域调制 f2 ifft2(F2); % 逆变换回空域 d f2 .* exp(-1i * Phase1); % 乘共轭相位抵消空域调制 decrypted abs(d); % 取幅度得到实数图像 end解密函数中最容易出现争议的是最后一步取abs。在我看来这一步既是为了显示也是数学必然。因为原始图像是实数经过两轮相位调制后再恢复理论上得到的复振幅应当是实数。但浮点运算会引入极微小的虚部残留直接用real(d)也可以得到近似正确结果只是不够干净。取abs则把虚部残留一并纳入幅度结果更稳健。如果解密时忘记乘某个共轭相位或者把exp(-1iPhase2)误写成exp(1iPhase2)相位偏移会保留下来解密结果会表现为严重的噪声图。我一直建议在调试时用复数矩阵的中间步骤逐一检查这比从头到尾只看最终图像要高效得多。3.4 完整调用流程与中间结果检查主脚本把加密、解密、显示串起来代码如下clear; close all; clc; rng(2025); % 固定随机种子保证实验可复现 I imread(cameraman.tif); if size(I, 3) 3 I rgb2gray(I); end if isa(I, uint8) I double(I) / 255; else I double(I); end [encrypted, Phase1, Phase2] drpe_encrypt(I); decrypted drpe_decrypt(encrypted, Phase1, Phase2); figure; subplot(1,3,1); imshow(I); title(原始图像); subplot(1,3,2); imshow(abs(encrypted), []); title(加密结果); subplot(1,3,3); imshow(decrypted); title(解密结果);中间结果检查可以关注三个点。第一加密结果应该是复数矩阵数值范围大致在[-1,1]附近abs后视觉效果像均匀噪声。第二解密结果应当与原始图像几乎逐像素相等我用MSE看一般在1e-28量级这说明链路完全自洽。第三Phase1和Phase2必须保存好它们就是密钥。我建议直接save(drpe_keys.mat, Phase1, Phase2);密钥和密文如果存成常见的jpg、png会同时丢失虚部和相位精度解密必然失败这点在下一章会详细讲。4. 实验验证与安全性评估4.1 正确性验证肉眼、MSE与PSNR解密图像的视觉结果和原始图像几乎无法区分这是正确性验证的第一步。我实际运行的cameraman灰度图解密结果像素值与原始图像的MSE约在10^-28量级这个误差基本就是双精度浮点运算的舍入误差。换算成PSNR会超过250dB远高于肉眼可感知的范围。很多人在这一步看到PSNR几百甚至几千dB会怀疑自己算错其实没任何问题因为这是个无损加密解密流程信息没有丢失误差完全来自数值精度。计算指标时我建议用统一的范围。因为图像归一化到了[0,1]PSNR公式里的峰值信号应该取1而不是255。自动计算函数可以这样写mse_val mean((decrypted(:) - I(:)).^2); psnr_val 10 * log10(1 / max(mse_val, eps));注意加了max(mse_val, eps)防止MSE为0时log10报错。如果你把图像保持在0~255范围PSNR公式就改成10*log10(255^2/mse_val)两个口径混用是初学者的高发错误。4.2 密钥敏感性测试微小偏差带来的雪崩效应密钥敏感性的测试方法很简单对正确的相位掩膜施加一个极小的扰动然后解密观察结果退化程度。我做的实验是给P1加上幅度为1e-6的高斯随机扰动其他密钥保持完全正确。P1_wrong Phase1 1e-6 * randn(size(Phase1)); d_wrong drpe_decrypt(encrypted, P1_wrong, Phase2); psnr_wrong psnr_custom(d_wrong, I);结果解密图像的PSNR通常会跌到10dB以下视觉上完全是散斑噪声看不到任何原始轮廓。这说明相位掩膜哪怕只有极小的密钥偏差也会因傅立叶变换的全图耦合特性被放大到整个输出平面。这个特性对密码系统而言是理想的因为攻击者无法通过近似密钥来获得部分信息要么拿到精确密钥要么什么都拿不到。进一步可以做更严格的敏感性测试比如只修改相位掩膜中的一个元素、把某个相位值增加0.01弧度然后重新解密。这个实验能直观展示“单个密钥元素错误也足以毁掉全图”对整个系统的安全直觉建立非常有帮助。4.3 抗噪性与抗裁剪性能量扩散带来的容错能力DRPE有一个很有意思的性质密文在传输过程中如果被加上少量噪声或者被裁剪掉一部分解密结果虽然会退化但通常还能看出图像轮廓。原因是傅立叶变换把信息散布到了整个平面局部区域的丢失不会导致对应局部信息的彻底消失而是表现为整体模糊或降质。我做了两类鲁棒性实验。第一类是噪声测试给密文加上高斯噪声后解密noisy_cipher encrypted 0.05 * randn(size(encrypted)); d_noisy drpe_decrypt(noisy_cipher, Phase1, Phase2);少量噪声下解密图像会有颗粒感但主体轮廓仍然可辨。第二类是裁剪测试把密文中间100×100区域置零再解密attacked encrypted; attacked(80:180, 80:180) 0; d_crop drpe_decrypt(attacked, Phase1, Phase2);裁剪的影响比噪声更大因为被置零区域携带的能量完全丢失解密结果会出现局部纹理失真但依然能看出原图大概是人物还是风景。这个特性让DRPE非常适合做容错加密或者加密域的预处理任务比如直接在密文域做特征提取。当然鲁棒性和安全性是权衡关系。系统越鲁棒意味着密钥偏差或密文篡改对结果的影响越小这在某些攻击场景下反而不利。实际应用中应该根据需求调节这个平衡而不是盲目追求某一项指标。4.4 密文统计特性为什么看起来像纯随机噪声加密结果之所以看起来像白噪声可以从统计特性解释。原始图像具有强烈的空间相关性像素之间高度相关而经过两块随机相位掩膜的调制以及傅立叶变换的全图混合后输出面的每个像素都携带了原始图像全局信息的叠加。按照中心极限定理大量独立随机相位叠加的结果会趋于高斯分布。我在实验中调取了加密结果的实部、虚部和幅度分布figure; subplot(1,3,1); histogram(real(encrypted(:)), 100); title(实部分布); subplot(1,3,2); histogram(imag(encrypted(:)), 100); title(虚部分布); subplot(1,3,3); histogram(abs(encrypted(:)), 100); title(幅度分布);实部和虚部的直方图都近似零均值的高斯钟形曲线幅度分布则更接近瑞利分布。这个特征和相干光照射随机散射体产生的散斑统计完全一致。因此从统计检测角度看密文没有泄露原始图像的轮廓、纹理和灰度分布信息。这也是DRPE区别于简单置乱方法的核心标准之一置乱加密的直方图不变而DRPE的密文统计特性已经完全不依赖于明文。5. 常见问题与排坑经验5.1 解密结果全黑或者全是噪点解密结果全黑十有八九是显示问题而不是算法问题。Matlab对double类型的复数矩阵做imshow时只会显示实部而且如果实部范围不在[0,1]内默认会截断到[0,1]。密文本身是复数实部有正有负直接imshow自然会显示成一片混乱或黑屏。正确做法是imshow(abs(encrypted), [])用空矩阵作为显示范围参数让Matlab自动拉伸灰度范围。解密后如果忘记取abs直接用imshow(decrypted)也可能出现黑屏。因为恢复出的复振幅虚部虽然接近0但实部可能出现轻微负值。取abs之后数值回归到[0,1]区间显示就正常了。所以我习惯在解密函数最后一行就返回abs结果从源头规避这个坑。5.2 复矩阵的显示陷阱与密文保存方式密文是复数矩阵这一点需要时刻记住。常见误区是密文用imwrite直接存成png再读回来解密结果全乱。png只能保存实数标量复数会被截断成实部虚部直接丢失而DRPE的解密极端依赖完整复振幅缺失虚部等于密钥缺失。正确的密文保存方式有两种。第一种是存成.mat文件保留复数矩阵的完整信息save(cipher.mat, encrypted);第二种是工程上常用的双通道保存把实部和虚部分开写成double二进制文件fid fopen(cipher_real.bin, wb); fwrite(fid, real(encrypted), double); fclose(fid); fid fopen(cipher_imag.bin, wb); fwrite(fid, imag(encrypted), double); fclose(fid);读取时再把两个通道合并成复数。这样做的优势是方便用标准文件传输协议发送密文体积可控也便于后续做加密域的并行处理。密钥文件同样建议用单独通道保存不要和密文放在同一个文件里。5.3 FFT正逆变换配对与归一化问题加密链路中正逆变换的配对关系是新手犯错最多的地方。Matlab的fft2是无归一化的正变换ifft2是带1/(M*N)归一化的逆变换二者互为逆运算。加密端用了ifft2收尾解密端第一步就必须用fft2这样才能把归一化因子抵消。如果加密端用fft2收尾解密端第一步就要用ifft2。经常有人自作主张把加密端的ifft2改成fft2或者把解密端的fft2改成ifft2结果解密出来的图像数值范围变化明显或者出现空间倒置。判断正逆变换是否配对的快速方法对任意矩阵X执行ifft2(fft2(X))后应该得到X本身如果结果差了系数或者翻转方向说明配对错了。另外别忘了exp(1iPhase2)是单位模长复数点乘频谱只会旋转相位不会改变幅度。如果你不小心用了exp(Phase2)而不是exp(1iPhase2)频谱幅度会被指数放大或缩小解密结果必然失败。这个细节我在代码评审时见过不止一次。5.4 随机种子、密钥保存与性能调试跑实验时建议在脚本开头设置rng(2025)固定随机数生成器种子。这样每次运行生成的相位掩膜完全相同实验结果可复现。很多学生写课程报告时发现前后两组实验密文不同误以为算法随机性出了问题其实就是没有固定种子。密钥的保存一定要趁早。Phase1和Phase2由加密函数内部生成如果不显式保存函数调用结束后这两个矩阵就消失了。一旦丢了没有备份手段能找回。测试时可以把密钥保存在drpe_keys.mat里下次解密直接load。性能方面fft2对任意尺寸图像都能计算不需要强制把图像缩放到2的幂大小。256×256和512×512灰度图在这个算法里跑起来很快但密文和密钥都是复数矩阵512×512的密文占用4MB左右如果循环测试大量图片要注意及时clear不再使用的变量。遇到特别大的图像可以考虑把加密函数里的中间变量F、E等复用同一个变量名减少内存峰值。实测下来这套算法对内存的压力主要是复数矩阵的三到四份拷贝而不是FFT本身。6. 系统边界与后续扩展6.1 安全性边界DRPE不是绝对安全的关于DRPE有一个广为流传的误解密钥空间无穷大所以无条件安全。实际不是这样。对于单幅图像的经典DRPE如果攻击者通过某种途径获得了一对已知明文和对应密文可以利用相位恢复算法比如Gerchberg-Saxton迭代从强度或复振幅信息中估计出频域相位掩膜。换句话说在已知明文攻击下DRPE的安全性会出现明显软肋。因此现代研究很少单独使用经典DRPE作为最终方案而是把它当作整个加密框架中的核心组件再叠加抗已知明文攻击的改造。研究方向包括把随机相位掩膜换成与图像内容相关的混沌相位序列让每次加密的密钥流都随明文变化或者采用相位截断傅立叶变换把加密和解密密钥分离成非对称结构。这一点在学术报告中要特别注意不能把DRPE描述成“绝对安全”严谨的说法是“在未知密钥和未知明文条件下具有极高的抗暴力穷举能力”。6.2 扩展方向混沌相位、分数阶变换与光学实现这个项目后续可以向多个方向延伸我整理了三条比较成熟的路线。第一条是混沌系统生成相位掩膜。用Logistic映射、超混沌Chen系统等生成与图像尺寸相同的伪随机矩阵替代rand产生的均匀随机相位。好处是混沌系统只需要传递初始值和控制参数密钥量从传输整块相位板缩减为传输几个初值密钥管理更方便同时混沌序列对初值极敏感安全性进一步提升。第二条是分数阶傅立叶变换域DRPE。经典DRPE的变换核是二阶傅立叶变换分数阶傅立叶变换额外引入一个分数阶参数阶数本身可以作为密钥。这样密钥空间从两个相位板扩展为“两个相位板两个分数阶参数”安全性显著增强。Matlab里可以用Chirp-Z分解实现分数阶变换代码量不大但物理意义更深入。第三条是走回光学实验。用空间光调制器加载相位掩膜用透镜做傅立叶变换用CCD记录密文强度。这里会遇到数字仿真没有的光学问题CCD只能记录强度复振幅信息需要通过同轴全息或相移干涉来恢复透镜孔径有限会带来信息截断相位板的加工精度会影响解密质量。这些问题单独拿出来都能写一篇完整的实验报告但对理解光学信息处理非常有帮助。我在实际做这套实验时最深的体会是数字仿真里跑通一套加密解密链路只需要十几行代码但真正把光学链路、数学公式和Matlab矩阵运算三者对齐需要花不少心思。很多现象只有亲手输错一次、再盯着中间结果检查一遍才能真正理解为什么傅立叶变换和相位掩膜能够组合成一个安全的加密系统。如果你也踩到了解密失败或者显示异常的问题建议先别急着改代码把信号链路里正逆变换的配对顺序、单位模长复数乘法的位置、以及最后取幅度的步骤逐一核对八成能快速定位问题。后面如果想继续深入混沌相位掩膜和分数阶变换都是很有意思的方向我后续也会单独整理。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑