news 2026/10/21 10:13:32

基于混沌序列与双随机相位系统的菲涅尔变换图像加密及Matlab实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于混沌序列与双随机相位系统的菲涅尔变换图像加密及Matlab实现

图像加密这个方向,第一次听到“二维混沌序列 + 双随机相位系统 + 菲涅尔变换”这个组合时,多数人第一反应是:这套东西到底比直接拿 AES 加密一张图强在哪?我最初也这么想,直到自己动手在 Matlab 里把整条加解密链路跑通,才发现这个方案是光学信息安全和密码学交叉领域里非常典型的一类做法:密钥不再是固定的字符串,而是混沌初值、衍射距离、波长这些连续物理参数;加密过程也不再是逐像素替换,而是让整幅图像经历两次随机相位调制和两次菲涅尔衍射,最终在数学上变成一幅复振幅噪声图。

这套方案解决的核心痛点很明确:图像数据量大、相邻像素相关性极强,传统文本加密算法直接套在图像上,要么效率感人,要么密文依然残留可被统计攻击利用的结构特征。而基于混沌和菲涅尔变换的光学加密思路,天然适合并行处理二维数据,同时把密钥维度从“相位板本身”压缩到“几个初始值”,安全性和实用性都能兼顾。这篇文章我会从原理、Matlab 数值实现、完整加解密流程、安全性指标到踩坑记录,把整套系统拆开讲透,适合正在做光学图像加密课题的学生、需要做多媒体加密仿真验证的工程师,以及对混沌密码学感兴趣的初学者参考。

1. 这套系统到底在做什么

1.1 图像加密为什么不能只靠 AES

很多人拿到图像加密需求,第一反应就是把图像像素转成一维字节流,然后用 AES 加密。这个思路在原理上没错,但落到图像数据上会有两个很现实的问题。

第一是效率。一张 512×512 的灰度图就有约 26 万个像素,转成字节流后还需要补位、分组、多轮迭代,加密耗时远高于对同体积文本的处理。第二是统计特征残留。AES 这类对称分组密码本质上是把数据“打乱”成看似随机的字节序列,但如果直接把密文字节流还原成图像矩阵来观察,虽然内容不可读,可如果加密模式设计不当,密文图像的直方图、相邻像素相关性等统计特征可能依然和明文存在关联。对于安全要求高的场景,攻击者可以借助这类统计信息做针对性分析。

所以做图像加密的人通常会走两条路:一条是纯数字域的置乱-扩散框架,比如 Arnold 置乱配合像素值扩散,把像素位置和像素值同时打散;另一条就是这里要讲的光学变换域加密思路,把图像调制到复振幅空间,用随机相位板和衍射变换把信息“淹没”在噪声里。两种思路本质目标一致:破坏像素间的相关性,抹掉明文的统计特征,同时让密钥空间足够大。

1.2 双随机相位编码的基本逻辑

双随机相位编码(DRPE)是光学图像加密里最经典的结构。它的基本想法非常直接:在输入平面对明文乘一块随机相位板,把它变成复振幅分布;经过一次光学变换(通常是傅里叶变换)后,在频谱平面再乘另一块随机相位板;最后再做一次逆变换,输出端得到的就是一幅复振幅噪声图像。

用个粗糙但好懂的类比:明文图像就像一张写满字的纸,第一块随机相位板相当于在每个字上面盖了一层随机厚度的透明薄膜,让字变得扭曲;透镜变换相当于把这堆扭曲后的信息重新排布到另一个空间;第二块相位板则是对排布后的信息再做一次全局扰动。解密时,只有持有完全相同的两块“相位钥匙”,并按相反顺序做共轭操作,才能把原始信息恢复出来。如果其中任何一把钥匙不对,输出的就是纯噪声。

DRPE 的关键在于:随机相位板不再是一把传统意义上的“钥匙”,而是一整块每个像素都有独立相位的二维掩模。这意味着密钥信息量极大,穷举攻击几乎不可能。而它真正巧妙的地方在于,整个加密过程在光学上是并行的、瞬时完成的,非常适合图像这类二维数据。

1.3 把傅里叶换成菲涅尔,多出了什么

经典的 DRPE 用的是傅里叶变换,系统和数学实现都简单。但傅里叶变换有一个特点:它没有任何可调的物理参数,密钥完全由两块相位板构成。于是很多研究者把目光转向了菲涅尔变换——也就是光场在近场衍射过程中的传播规律。

菲涅尔变换相比傅里叶变换,多出了衍射距离和波长这两个连续物理量。哪怕攻击者拿到了两块相位板,如果不知道加密时使用的衍射距离到底是多少毫米、波长是多少纳米,依然无法正确解密。对密钥设计来说,这是“白赚”的额外安全维度。你不需要增加任何硬件复杂度,只需要在仿真里多传几个参数,整个系统的密钥空间立刻膨胀了若干个数量级。

而且从光学工程角度看,菲涅尔变换对应的是真实光场的传播过程,这让方案具备了实际光路实现的可能性。仿真结果可以直接映射到真实光学系统,这是纯数字域加密算法不具备的优势。

2. 二维混沌序列的角色:随机相位板不是随便生成的

2.1 为什么相位板要用混沌来生成

看到这里你可能会问:相位板直接用 rand() 生成随机相位不就行了吗?可以,但在“密钥管理”这件事上会非常尴尬。如果相位板是纯随机生成的,那么传输密钥的时候就必须把这整块相位板发给接收方。一块 512×512 的相位板,每个像素还有量化精度,数据量轻松超过一幅图像本身。这相当于为了加密一幅图,先得传输一把比图还大的钥匙,完全失去了实用性。

混沌系统的价值恰好体现在这里。混沌序列有三个特点:对初值极度敏感,初值差 1e-15 都会让序列轨迹完全不同;确定性,同样的初值和参数必然复现同样的序列;遍历性,序列值会在一定范围内密集穿行,统计上接近均匀分布。这三个特性组合起来,就实现了“用几十个字节的种子,生成一整块统计上像噪声的随机相位板”。

你可以把混沌初值和参数理解成一个压缩包的密码。只要密码正确,接收方就能通过同样的迭代规则,把整块巨大的相位板“解压”出来;密码错误,产生出来的相位板完全不一样。密钥从一幅巨型图像变成了几个浮点数,这是混沌方法最核心的工程价值。

2.2 用 Logistic 映射生成二维相位板的完整做法

实践中最常见、也最容易上手的混沌系统是 Logistic 映射:

x_{n+1} = μ * x_n * (1 - x_n)

当 μ 取值在 (3.57, 4] 区间时,系统进入混沌状态。我习惯取 μ = 3.99 或 3.999,尽量避免接近周期窗口的参数值。初值 x0 不能取 0、0.25、0.5、0.75、1 这类特殊点,否则序列会收敛到不动点或陷入短周期。

生成相位板时,要注意两个工程细节:一是先迭代丢弃前几百个点,消除暂态影响;二是把生成的一维序列 reshape 成和图像尺寸相同的矩阵。下面是可以直接用的函数:

function phase = chaos_phase(M, N, mu, x0) % 生成 M x N 大小的混沌相位分布,值域 [0, 2*pi) total = M * N; burn = 200; % 丢弃暂态点数 x = zeros(total + burn, 1); x(1) = x0; for n = 1 : total + burn - 1 x(n+1) = mu * x(n) * (1 - x(n)); end s = x(burn+1 : end); % 去掉前200点 s = reshape(s, M, N); % 极少数情况下序列会接近0或1,裁剪一下避免后续相位计算异常 s = max(min(s, 1 - 1e-12), 1e-12); phase = 2 * pi * s; end

调用的时候也很简单:

P1 = exp(1j * chaos_phase(M, N, mu1, x01)); P2 = exp(1j * chaos_phase(M, N, mu2, x02));

这里 P1、P2 就是两块随机相位板。注意两块板子必须用不同的初值和参数生成,比如一组用 (μ=3.99, x0=0.31415926),另一组用 (μ=3.98, x0=0.65358979)。如果两块相位板相同或高度相关,整个系统的密钥量会大幅缩水。

标题里提到“二维混沌序列”,严格来说,直接把一维 Logistic 序列 reshape 成二维矩阵,相邻行列之间多少还会保留一些序列自身的相关性,不算最理想的二维混沌。追求更高质量时,可以用二维耦合映射,比如 2D-Logistic:

x_{n+1} = a * x_n * (1 - x_n) + b * y_n y_{n+1} = c * y_n * (1 - y_n) + d * x_n

取 a=c=3.9、b=d=0.1、初值落在 (0,1) 区间,可以生成两组互相耦合的二维序列,分布更均匀。不过对多数复现和教学场景,一维 Logistic 配合足够长的前向预迭代,已经能满足加密需求。

2.3 密钥管理与抗穷举的基本盘

最终整套系统的密钥包括:两个混沌映射的初值 x01、x02,两个控制参数 μ1、μ2,两段菲涅尔衍射距离 d1、d2,以及波长 λ。如果每个双精度浮点数按约 1e16 的独立组合数估算,仅初值和参数已经能提供 10^96 量级的理论组合空间,再叠加距离和波长的连续取值,暴力破解基本不现实。

这不是说系统就无懈可击,任何密码系统都有侧信道、已知明文攻击等更复杂的威胁模型,但在常规密钥安全评估框架下,这个方案的密钥空间是达标的。对你来说,理解混沌生成相位板的核心,就是要明白:密钥的本质是“种子”,相位板只是种子长出来的树。

3. 菲涅尔变换的数值实现:Matlab 里最容易翻车的地方

3.1 三条数值实现路径怎么选

菲涅尔变换在 Matlab 里其实没有现成函数,需要自己写。常见的离散实现路径有三条:单次 FFT 法、卷积法、角谱法。我把它们的适用场景和复杂度整理成一张表:

方法适用距离实现复杂度关键注意点
单次 FFT 法中等及较远距离一次 FFT,代码最简洁观察平面采样间隔必须换算,公式易错
卷积法任意距离,尤其近距离三次 FFT,需要补零输出平面采样间隔与源平面相同
角谱法任意距离,含极短距离两次 FFT需要保证频域采样充分,代码略绕

做加密仿真时,我建议优先用单次 FFT 法。原因很实际:它代码量最小,每一步都有明确的物理意义,调试更多时候是解决坐标换算问题而非原理问题。如果遇到距离太近、二次相位因子严重欠采样的情况,再切换到角谱法兜底。

3.2 单次 FFT 法的公式推导和采样间隔换算

菲涅尔衍射的卷积积分形式是:

U2(x2, y2) = exp(jkz) / (jλz) * ∬ u1(x1, y1) * exp{ jk / (2z) * [(x2 - x1)^2 + (y2 - y1)^2] } dx1 dy1

把平方项展开,可以改写成一个非常漂亮的“二次相位 + 傅里叶变换 + 二次相位”结构:

U2 = C * exp{ jk/(2z) * (x2^2 + y2^2) } * FFT{ u1 * exp{ jk/(2z) * (x1^2 + y1^2) } }

其中 C = exp(jkz) / (jλz),k = 2π/λ。

这个形式告诉我们:先把源平面的复振幅乘上一个二次相位因子,做一次傅里叶变换,再乘上另一个二次相位因子,就完成了菲涅尔衍射的数值计算。但这里藏着一个几乎所有初学者都会踩的坑:FFT 输出的频率坐标 fx 和观察平面的空间坐标 x2 之间,必须满足换算关系:

x2 = λ * z * fx

也就是说,观察平面的采样间隔不是源平面的 dx1,而是:

dx2 = λ * z / (M * dx1)

如果不做这个换算,直接沿用源平面坐标去构造第二个二次相位因子,加密链路看起来正常,解密出来却总是一团乱麻或者出现奇怪的缩放。我当初就卡在这个问题上整整一个晚上,后来把所有中间平面的采样间隔变化列出来才彻底想通。

下面是一个正确的单次 FFT 法菲涅尔变换函数:

function U2 = fresnel_fft(U1, z, lambda, dx) % U1: 源平面复振幅 % z: 衍射距离,可以为负(对应逆传播) % lambda: 波长 % dx: U1 所在平面的采样间隔 [M, ~] = size(U1); k = 2 * pi / lambda; % 源平面坐标 x = (-M/2 : M/2-1) * dx; [X, Y] = meshgrid(x, x); % 第一次乘二次相位 A = U1 .* exp(1j * k / (2*z) * (X.^2 + Y.^2)); % 中心化傅里叶变换:先ifftshift再fft2,最后fftshift Uf = fftshift(fft2(ifftshift(A))); % 频域坐标 fx = (-M/2 : M/2-1) / (M * dx); [Fx, Fy] = meshgrid(fx, fx); % 观察平面坐标(关键换算) x2 = lambda * z * fx; [X2, Y2] = meshgrid(x2, x2); % 常数因子和第二个二次相位 C = exp(1j * k * z) / (1j * lambda * z); U2 = C .* exp(1j * k / (2*z) * (X2.^2 + Y2.^2)) .* Uf; end

这段代码里有两个细节值得强调。一个是 fftshift 和 ifftshift 的组合:我们约定坐标原点在阵列中心,所以先 ifftshift 把中心点搬到 FFT 的起始位置,做完 fft2 再用 fftshift 把低频移回中心,这样频域坐标才能和 (-M/2 : M/2-1) 一一对应。另一个是 z 为负数时的处理:代码直接把负 z 代入公式,二次相位因子自动反号,常数项 C 也相应变化,这正好对应光场的反向传播,解密时直接复用这个函数即可。

3.3 参数搭配的实践经验

仿真时最关键的一组参数是波长、距离、采样间隔和图像尺寸。它们的关系被采样间隔换算公式绑定在一起。我常用的起点配置是:图像 256×256,源平面采样间隔 dx = 10 μm,波长 λ = 532 nm,加密距离 d1 = 50 mm、d2 = 80 mm。

用上面的公式估算一下中间平面采样间隔:dx1_out = λ * d1 / (M * dx) = 532e-9 * 0.05 / (256 * 10e-6) ≈ 1.04e-5 m,也就是约 10.4 μm,和源平面间隔相当。这种量级下相位因子变化平缓,FFT 数值计算非常稳定。如果距离拉得太大,观察平面采样间隔会被放大,导致图像在空间域被过度拉伸;距离太近,二次相位因子变化太快,又可能出现欠采样。

判断欠采样有个很实用的经验法则:观察二次相位因子在相邻采样点之间的相位差,如果超过 π,基本就欠采样了,密文图像会出现明显的网格状条纹。遇到这种情况,优先增大图像采样点数,或者改用卷积法、角谱法实现。

4. 加密与解密全流程:从明文到密文再回来

4.1 加密过程的五个核心步骤

整个加密过程可以拆成五步:

第一步,把明文图像归一化到 [0,1] 区间。这一步非常关键,否则后续乘相位板后数值尺度会被带偏,解密后还要做复杂的幅度校正。

第二步,用混沌序列生成两块随机相位板 P1、P2。

第三步,明文乘 P1,得到初始复振幅 A1 = img .* P1,这是第一次随机相位调制。

第四步,对 A1 做距离 d1 的菲涅尔变换,得到菲涅尔域的复振幅 B1。注意这一步之后,平面的采样间隔已经从原来的 dx 变成了 dx1_out,后续所有操作都要在这个新间隔下进行。

第五步,B1 乘 P2,再做距离 d2 的菲涅尔变换,得到密文 Cipher。Cipher 是复数矩阵,幅度是噪声图,相位也是噪声分布。

对应的 Matlab 主加密代码:

% 读取并归一化图像 img0 = im2double(imread('cameraman.tif')); img0 = imresize(img0, [256, 256]); [M, N] = size(img0); % 参数设置 lambda = 532e-9; dx0 = 10e-6; d1 = 50e-3; d2 = 80e-3; mu1 = 3.99; x01 = 0.31415926; mu2 = 3.98; x02 = 0.65358979; % 生成双随机相位板 P1 = exp(1j * chaos_phase(M, N, mu1, x01)); P2 = exp(1j * chaos_phase(M, N, mu2, x02)); % 加密链路 A1 = img0 .* P1; % 第一步调制 B1 = fresnel_fft(A1, d1, lambda, dx0); % 第一次菲涅尔变换 dx1 = abs(lambda * d1 / (M * dx0)); % 中间平面采样间隔 Cipher = fresnel_fft(B1 .* P2, d2, lambda, dx1); % 第二次调制+变换 % 显示结果 figure; subplot(1,3,1); imshow(img0); title('明文'); subplot(1,3,2); imshow(mat2gray(abs(Cipher))); title('密文幅度'); subplot(1,3,3); imshow(mat2gray(angle(Cipher))); title('密文相位');

这里有一个无数人踩过的坑:第二次调用 fresnel_fft 时,传入的采样间隔必须是 dx1,而不是初始的 dx0。因为 B1 这个复振幅所在的平面,像素间隔已经不是原来的 10 μm 了。忽略这一步,解密时坐标链就对不上,输出图像会变形甚至完全无法识别。

4.2 解密过程的相位共轭逻辑

解密过程是加密的逆过程,但并不是简单“倒回去”,而是要用到相位共轭的性质。加密时我们乘的是 exp(jphase),解密时对应的操作是乘 exp(-jphase),也就是共轭。因为复数的相位可以通过取共轭来“抵消”:

P .* conj(P) = 1

这正是双随机相位系统能正确还原的数学基础。解密链路如下:

第一步,对密文做距离 -d2 的菲涅尔变换,也就是反向传播。这里的负号让光场在数学上“倒着走”回 B1 所在的平面。

第二步,乘上 P2 的共轭,抵消第二次相位调制的效果。

第三步,再做距离 -d1 的菲涅尔变换,回到 A1 所在平面。

第四步,乘上 P1 的共轭,抵消第一次相位调制的效果。此时得到的是复数,理想情况下虚部为零、实部等于原始明文。取 real 后归一化显示即可。

代码实现如下:

function dec = decrypt_image(Cipher, P1, P2, lambda, d1, d2, dx0) [M, ~] = size(Cipher); dx1 = abs(lambda * d1 / (M * dx0)); dx2 = abs(lambda * d2 / (M * dx1)); B2h = fresnel_fft(Cipher, -d2, lambda, dx2); % 反向d2 B1h = B2h .* conj(P2); % 抵消P2 A1h = fresnel_fft(B1h, -d1, lambda, dx1); % 反向d1 dec = abs(A1h .* conj(P1)); % 抵消P1并取幅度 end

注意这里用 abs 而不是 real,是实用考虑:数值误差会导致结果里有微量虚部残留,abs 对轻微噪声更鲁棒,解密图像质量和 real 相比几乎没有区别。如果你需要非常严谨的评估,可以改成 real 再做一个最小值裁剪。

4.3 完整闭环:主程序 + 函数封装

把上面两节组合起来,就是一套可以完整运行的最小系统。为了复用方便,我把加密逻辑也封装成函数:

function Cipher = encrypt_image(img, P1, P2, lambda, d1, d2, dx0) [M, ~] = size(img); A1 = img .* P1; B1 = fresnel_fft(A1, d1, lambda, dx0); dx1 = abs(lambda * d1 / (M * dx0)); Cipher = fresnel_fft(B1 .* P2, d2, lambda, dx1); end

主程序调用:

Cipher = encrypt_image(img0, P1, P2, lambda, d1, d2, dx0); dec = decrypt_image(Cipher, P1, P2, lambda, d1, d2, dx0); % 解密质量评估 cc = corr2(img0, mat2gray(dec)); mse = mean((img0(:) - mat2gray(dec(:))).^2); psnr = 10 * log10(1 / mse); fprintf('重构相关系数 CC = %.6f\n', cc); fprintf('峰值信噪比 PSNR = %.2f dB\n', psnr);

我第一次跑通这个闭环时,CC 达到 0.9999 以上,PSNR 超过 60 dB,肉眼几乎看不出明文和重构图的差异。能做到这个量级,说明链路中每个坐标换算都是正确的。

4.4 密钥错误的直观表现

为了验证系统的密钥敏感性,可以把解密时的混沌初值加上一个极小的扰动,比如让 x01 = x01 + 1e-15,其余全部保持不变,再跑一次解密:

P1_err = exp(1j * chaos_phase(M, N, mu1, x01 + 1e-15)); dec_err = decrypt_image(Cipher, P1_err, P2, lambda, d1, d2, dx0); cc_err = corr2(img0, mat2gray(dec_err));

实测下来 CC_err 会在 0.01 以下,解密结果就是一幅不规则的噪声图,完全看不到明文轮廓。这个实验强烈地展示了混沌初值敏感性的威力:密钥差 1e-15,解密结果天差地别。

5. 安全性与性能验证:不是加密了就完事

5.1 密钥空间与抗暴力破解

这套系统的密钥由混沌初值、控制参数、衍射距离和波长组成。仅以双精度浮点初值为例,每个初值就约有 10^16 种可能组合,两个初值叠加两个 μ 参数,理论组合量已经达到 10^64。再叠加 d1、d2、λ 这些连续参数,密钥空间只会更大。

暴力破解的不可行性不仅是理论上的。实际操作中,攻击者每尝试一组密钥,就需要完整执行两次菲涅尔变换和两次相位共轭操作,这是一套相当重的计算流程。精确搜索数百字节密钥所对应的 10^60 以上组合,在当前算力下是不可能完成的任务。

5.2 统计特性验证

图像加密的另一个重要指标是密文是否破坏了明文的统计特征。明文图像里相邻像素通常高度相关,相关系数常常超过 0.9,这给预测攻击提供了大量先验信息。加密后,密文幅度的相邻像素相关性应该接近 0,直方图应该接近均匀分布。

可以用 Matlab 自带的 corr2 快速计算水平相邻像素相关系数:

c_plain_h = corr2(img0(:, 1:end-1), img0(:, 2:end)); c_cipher_h = corr2(abs(Cipher(:, 1:end-1, 1)), abs(Cipher(:, 2:end, 1)));

注意我这里用密文幅度而不是密文本身,因为密文是复数矩阵,corr2 需要实数输入。实际测试中,明文水平相邻像素相关系数往往大于 0.95,密文会降到 0.05 以下,说明像素间的冗余结构已经被打散。

直方图方面,明文图像的直方图有明显的峰值和结构,而密文幅度的直方图会接近均匀分布,这意味着基于直方图的一类统计攻击基本失效。

5.3 解密质量量化指标

除了安全性,还需要量化解密质量。两个最常用的指标是相关系数 CC 和峰值信噪比 PSNR。

CC 反映重构图和原始图像的线性相似度,Matlab 里直接用 corr2 即可。完美还原时 CC = 1,实际数值仿真中达到 0.999 以上就算非常理想。

PSNR 对归一化到 [0,1] 的图像,计算公式是:

PSNR = 10 * log10(1 / MSE),MSE = mean((orig - dec).^2)

其中 1 是归一化图像的最大可能像素值。解密图如果和原始图像完全一致,MSE 为 0,PSNR 无穷大;实际会受到 FFT 舍入误差和相位量化误差的影响,通常做到 50 dB 以上就说明数值实现没有问题。

需要提醒的是,PSNR 不是越高越好,它能反映像素级误差,却无法反映人眼感知的细节差异。加密方案评估时一般 CC 和 PSNR 结合着看,CC 更贴近结构相似性。

6. 实操中常见的问题与排查实录

6.1 解密图像是镜像或旋转过的

如果你解密出来的图像能看出轮廓,但左右翻转或者旋转了 90 度、180 度,大概率是 FFT 坐标和 meshgrid 坐标定义不一致导致的。排查思路很简单:先单独验证 fresnel_fft 函数。用一个简单的球面波相位作为输入,或者直接用已知图像的菲涅尔变换结果和一个参考实现对比。

常见原因有两个。一是 ifftshift 和 fftshift 的使用顺序不匹配。二是 meshgrid 生成坐标时,X、Y 的顺序理解错误。Matlab 的 meshgrid(x, y) 生成的结果中,行方向对应 x,列方向对应 y,这和图像矩阵的行列习惯正好相反。如果你在构造二次相位因子时把 X 和 Y 用反了,解密图像就会出现转置类的问题。

这个问题没有捷径,唯一可靠的排查办法是打印各个平面的坐标网格、检查幅度和相位分布是否符合预期,而不是直接跳到加解密结果上。

6.2 解密图像边缘出现亮环或振铃

这个现象通常不是解密逻辑错,而是菲涅尔衍射本身的孔径效应。明文图像被硬截断成一个矩形区域,边缘相当于一个突变孔径,高频分量在衍射传播过程中会在边界附近产生 Gibbs 现象,表现为亮环或振荡条纹。

如果这个问题影响到解密质量,可以从两个方向解决:一是对明文图像做边缘柔化,比如乘一个余弦窗函数,让边缘平缓过渡。但要注意这会改变明文本身,评估重构质量时要把窗口补偿回去。二是在加密前对图像做零填充,扩大有效孔径,减少边缘截断效应。零填充会让计算量增加,但效果立竿见影。

6.3 密文出现网格状条纹

如果密文图像里能看到规则的网格条纹,而不是均匀的噪声,最可能的原因就是二次相位因子欠采样。前面 3.3 节提到过,二次相位因子 exp(jk/(2z) * (x^2 + y^2)) 在距离太近或网格点数不足时,相邻采样点之间的相位差会超过 π,导致傅里叶变换结果出现混叠。

排查方法很简单:计算相位因子在相邻点之间的最大相位差,如果接近或超过 π,就调整距离、增大采样点数,或者换用角谱法。我一般在写代码时会把最大相位差打印出来作为诊断信息,低于 π 才继续跑后续加密。

6.4 复数密文如何保存和显示

加密结果是一个复数矩阵,既不能直接 imsave,也不能当作普通灰度图保存。如果只是为了实验记录,最省事的方式是直接用 save 存成 .mat 文件。如果需要把密文传给另一端处理,可以考虑拆成实部、虚部两幅图像分别保存为 16 位整数,或者拆成幅度、相位两个分量的图像。无论哪种方式,接收方都需要额外知道保存格式和归一化规则,否则无法还原复数矩阵。

显示密文时也有一个细节:复数矩阵的幅度动态范围可能非常大,直接 mat2gray 会把大部分细节压缩成一片黑。经验做法是先对幅度做对数变换,再用 mat2gray 映射到 0~255,视觉效果会清晰很多。

subplot(1,2,1); imshow(mat2gray(abs(Cipher))); title('线性幅度'); subplot(1,2,2); imshow(mat2gray(log1p(abs(Cipher)))); title('对数幅度');

6.5 密钥错误时解密图还能看到明文轮廓

这是一个比较隐蔽的问题。理论上双随机相位系统在密钥不匹配时输出应该是完全的噪声,如果解密图还能隐约看到明文轮廓,往往说明中间某一步的相位调制没有充分发挥作用。

我遇到过的原因主要有两个:一是 P1、P2 两块相位板是用相同初值或线性相关参数生成的,导致两次调制效果部分抵消;二是加密时明文乘 P1 之后没有对数值范围做处理,P1 的相位调制在幅值上体现不出来。相位调制只影响相位,不影响幅度,但代码里如果错误地在加密过程中把幅度也改变了,就会破坏系统结构。检查方法很简单:分别打印 A1、B1、密文的幅度分布,确认每一步幅度都已经变得平坦且接近噪声,而不是残留明文轮廓。

6.6 混沌序列退化或出现短周期

Logistic 映射虽然简单,但参数和初值选择不当会退化。μ 落在某些窗口内会周期收敛,初值取到特殊点会直接掉到不动点。我自己的排查经验是:每次生成相位板后,先画一下 phase 的二维分布图,肉眼确认它是一片均匀的细小颗粒状纹理,而不是有条纹、有规律的大块色块。同时检查序列的取值范围,如果出现大量 0 或 1,说明初值或参数有问题,需要换一组种子。

另外一个容易被忽视的点是预迭代的丢弃数量。混沌系统在初始阶段可能还处于暂态,轨迹尚未进入吸引子,直接使用前几百个点会让相位板的统计特性变差。我习惯至少丢弃 200 点,复杂系统甚至会丢弃 500 点,代价很小但稳定性提升明显。

最后分享一个调试顺序方面的体会。这类光学加密系统代码真正跑通之前,最忌讳的是一上来就追求大尺寸图像和复杂参数。我建议先从 128×128 或 256×256 的图像开始,固定一组简单的距离参数,先把加解密闭环跑通,确认 CC 和 PSNR 达标之后,再逐步换更大的图像、更激进的参数,甚至叠加攻击实验。这样出了问题,定位范围可以控制在坐标换算、相位生成、采样判断这几个环节里,而不是在混沌参数和距离参数的组合空间里迷路。图像加密这个方向后续还可以往彩色图像多通道加密、压缩感知联合加密等方向扩展,但无论扩展到哪里,双随机相位加混沌序列这套底层的思路和数值实现的细节,都是值得先吃透的基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 10:12:44

SpringBoot+Vue构建高校实习管理系统:RBAC权限与全流程管理实战

高校里每年实习季最忙的就是辅导员和教学秘书——学生要联系企业、提交申请,老师要审查材料、跟踪出勤、评定成绩,一套流程走下来,表格文件满天飞,漏掉一两个审批节点太正常了。这个基于SpringBootVue的高校实习管理系统&#xff…

作者头像 李华
网站建设 2026/10/21 10:12:29

开源代码审查方案open-code-review:从流程设计到文化落地

我这两年最常干的一件事,就是劝身边的团队把代码审查(Code Review)从“走过场”变成“真家伙”。很多项目的代码质量问题,追根溯源都能发现,问题不是出在写代码的人手里,而是出在审查环节彻底失效了。今天要…

作者头像 李华
网站建设 2026/10/21 10:12:00

大模型辅助学术写作:人机协同的智能论文工作流解析

最近半年,学术写作这个圈子被大模型搅动得不轻,几乎每个科研交流群里都有人在问:“AI到底能不能帮我写论文?”我的答案是:能,但前提是你得把它当成一套工程方案来用,而不是当成一个会变魔法的黑…

作者头像 李华
网站建设 2026/10/21 10:11:47

原木与树脂手作挂钟:零基础玩转家居艺术创作

“artcraft”这个标题,乍一看像是某个独立游戏。但在我眼里,它更像是一个动作——把艺术感做进手作里。做内容这么多年,我发现一个很有意思的现象:纯艺术的门槛太高,纯手工的又少了点灵气。而“artcraft”恰好卡在中间…

作者头像 李华
网站建设 2026/10/21 10:11:43

图表设计方法论:从信息分层到视觉表达的完整指南

1. 图表设计到底在解决什么问题 先说个可能很多人都有过的经历:你花了一下午用画图工具把系统架构、业务流程或者接口关系画出来,结果发给团队之后,收到的反馈不是"明白了",而是"这个框和那个框之间是什么关系&…

作者头像 李华
网站建设 2026/10/21 10:11:22

PMSM三电平SVPWM的V/F控制仿真:从原理到Simulink实现

1. 为什么偏偏是V/F加三电平?先把这个组合的“为什么”想明白拿到“PMSM电机通过采用基于SVPWM的3电平逆变器以V/F方法进行控制(Simulink仿真实现)”这个题目时,我第一反应是:这个组合选得挺“工程化”。很多初学者一上…

作者头像 李华