news 2026/10/21 5:27:09

在线字典学习MATLAB实现:从稀疏编码到图像去噪

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在线字典学习MATLAB实现:从稀疏编码到图像去噪

简介:这是一份基于MATLAB的在线字典学习实现代码,面向机器学习初学者和图像/信号处理方向的研究者,用于解决如何从序列数据中在线学习一组基字典的问题。与批处理方式不同,在线学习逐样本更新模型,适合内存有限或数据流场景,该代码正好演示了这一过程。压缩包共5个文件,包含4个MATLAB脚本(.m)和1个.mat数据文件,整体仅1.11MB;其中.m文件分别承担主流程、代价函数计算、字典更新等核心模块,数据文件提供示例输入,结构清晰便于对照学习。读者通过运行demo可以观察cost函数随迭代的变化,理解损失最小化与字典更新之间的协同关系;同时可通过调整参数测试不同数据下的稀疏编码效果。目前已有693人学习下载,特别适合希望动手验证在线学习原理、提升MATLAB编程与无监督学习实践能力的开发者。

1. 在线字典学习:把“学完再更新”改成“边学边更新”

之前在调一个图像去噪项目,整批 K-SVD 在 512×512 的灰度图上单次迭代要扫完所有 patch,内存卡得死死的,跑几轮就恨不得换机器。换成在线字典学习之后,每次只吃一个或一小批 patch 就更新一次字典,训练十几轮下来,速度和效果反而都上去了。这套代码就是一个用 MATLAB 写的在线字典学习实现:输入一堆训练图像,切块后边遍历边更新过完备字典,最终得到一组能对图像块做稀疏表示的原子,供去噪、重构、特征提取这类下游任务复用。适合做稀疏表示、图像复原、压缩感知方向但又不想上 CUDA 和深度学习的开发者。


2. 项目架构与技术选型:一次迭代训练和整批训练的本质差异

2.1 为什么用在线方式而不是整批 K-SVD

字典学习的数学目标很直白:给定训练样本集 Y = [y₁, y₂, …, y_m],每个 y ∈ R^n,要找一个字典 D ∈ R^{n×K}(K 通常比 n 大,形成过完备),使得每个样本都能用少数原子线性组合逼近:

min_{D,A} ‖Y - DA‖_F² + λ‖A‖₁, s.t. ‖d_j‖₂ ≤ 1

整批 K-SVD 的套路是:先用 OMP 对所有样本求稀疏系数,再用 SVD 逐个原子更新,反复交替直到收敛。问题在于每次“稀疏编码”阶段都要把全部样本过一遍,内存占用和计算量随样本数线性上涨。我最早就是在这里翻车的:512×512 图切成 8×8 patch,步长 1,能得到 25 万个训练列,OMP 一次要解 25 万个最小二乘,MATLAB 里直接卡成黑匣子。

在线方式的思路完全不同。它不追求一次迭代处理全部数据,而是每一轮随机抽一个或一小批 patch,做完稀疏编码立刻更新字典,再进入下一个样本。更新公式用的是随机梯度下降的变体:

D ← D + η_t · (y_t - Dα_t) · α_tᵀ

其中 η_t 是随迭代衰减的学习率。这样做有三个实际好处:第一,内存只跟单批大小有关,不跟总样本数挂钩;第二,数据可以流式进来,训练中途来新图也能继续学;第三,天然带随机性,反而更不容易陷入局部最优。这套代码就是把“采样→稀疏编码→字典更新→正则化”四步封装成主循环,每一步做成独立函数,方便替换实现。

2.2 目录结构与文件职责

拿到代码包解压后,目录结构长这样:

online-dictionary-learning/ ├── config.m # 全局参数配置 ├── demo_denoise.m # 一键演示:训练字典+图像去噪 ├── src/ │ ├── onlineDictLearn.m # 在线字典学习主循环 │ ├── ompSparseCode.m # OMP 稀疏编码 │ ├── updateDictionary.m # 随机梯度字典更新 │ ├── patchExtract.m # 图像切块/合并 │ ├── normalizeAtoms.m # 原子归一化 │ └── computePSNR.m # 重建质量评估 ├── data/ │ └── train_images/ # 训练用灰度图 └── results/ # 训练日志和重建结果

每个文件只干一件事,这是这套代码最值得抄的地方。config.m 集中管理所有超参数,改参不用翻主循环;onlineDictLearn.m 只负责迭代逻辑,不掺图像 IO;patchExtract.m 管图像和矩阵之间的转换。我后来做二次开发,基本只改 config 和替换某个 src 函数,不用动整个项目。

2.3 数据流与参数约定

整体数据流可以概括成一条链:

灰度图 → 随机切 patch → 列向量化 → OMP稀疏编码 → 梯度更新字典 → 原子归一化 → 下一批

训练阶段完全不保留整图,而是用 patchExtract 把图切成小块再随机打乱,喂给主循环。参数约定集中在 config.m 里,核心几个是:

参数名含义典型值影响
patchSize图像块边长8太小原子抓不住结构,太大计算量暴涨
dictSize字典原子数 K256过完备度,K 越大表示能力越强但训练越慢
sparsity稀疏度 L10OMP 每次选几个原子
batchSize每次更新的样本数64梯度估计稳定性
learningRate初始学习率 η₀0.01太大震荡,太小收敛慢
numEpochs遍历数据的轮数10训练总时长

这里有个容易被忽略的点:learningRate 不是恒定的。在线学习理论要求学习率满足衰减条件,代码里默认用 η_t = η₀ / (1 + t/numEpochs),这样前期快速调整,后期精细收敛。这个衰减策略比固定学习率稳得多,是这套代码能快速收敛的关键之一。


3. 核心模块拆解:一个样本从进入到字典更新的完整链路

3.1 主循环:onlineDictLearn.m

主循环是整个项目的骨架,负责把采样、稀疏编码、字典更新串起来。代码不长,但每一行都有讲究:

function [D, history] = onlineDictLearn(Y, K, params) % Y: 训练矩阵,每列是一个patch的列向量 % K: 字典原子个数 % params: 结构体,包含sparsity, batchSize, learningRate等 % 返回: 训练好的字典 D (n*K),history记录每轮重构误差 n = size(Y, 1); D = randn(n, K) ./ sqrt(n); % 随机初始化并保证列范数~1 D = normalizeAtoms(D); numSamples = size(Y, 2); t = 0; % 全局迭代计数 history.errors = []; history.learningRates = []; for epoch = 1:params.numEpochs % 每轮重新打乱样本顺序,增加随机性 order = randperm(numSamples); for i = 1:params.batchSize:numSamples idx = order(i:min(i+params.batchSize-1, numSamples)); Y_batch = Y(:, idx); % 取一小批样本 t = t + 1; % 1. 稀疏编码:固定D,求A A_batch = zeros(K, length(idx)); for j = 1:length(idx) A_batch(:, j) = ompSparseCode(Y_batch(:, j), D, params.sparsity); end % 2. 字典更新:固定A,梯度下降更新D eta = params.learningRate / (1 + t / numSamples); D = updateDictionary(D, Y_batch, A_batch, eta); % 3. 每隔若干步记录误差 if mod(t, 50) == 0 err = norm(Y_batch - D * A_batch, 'fro') / norm(Y_batch, 'fro'); history.errors(end+1) = err; history.learningRates(end+1) = eta; fprintf('epoch %d, iter %d, rel err %.4f, lr %.5f\n', ... epoch, t, err, eta); end end end end

逻辑说明:外层循环控制 epoch,每轮训练前用 randperm 打乱样本顺序,避免模型记住数据排列。内层按 batchSize 切块,每批样本依次完成“OMP 求稀疏系数 → 按梯度方向更新字典”。这一步是标准的块坐标下降:固定 D 解 A,固定 A 解 D,交替逼近原目标函数。学习率 η 随迭代数衰减,t 越大步长越小,后期只做微调而不破坏已学好的原子。

参数说明:K 是字典宽度,决定过完备程度;sparsity 控制每个 patch 用几个原子表示,太小欠拟合、太大会把噪声也编进去;batchSize 平衡梯度估计的稳定性和计算开销,我一般取 64,显存紧张时降到 32。history 结构体把误差和学习率都记录下来,训练完可以画曲线判断是否收敛。

3.2 稀疏编码:OMP 的 MATLAB 实现

稀疏编码是字典学习里最耗时的环节。OMP(正交匹配追踪)是贪心算法里最常用的实现:每次选出和当前残差最相关的原子,做一次最小二乘,更新残差,重复 L 次。代码里刻意不调用现成工具箱,纯手写,方便看清楚每一步:

function alpha = ompSparseCode(y, D, sparsity) % y: 单样本列向量 % D: n*K 字典 % sparsity: 最大非零系数个数 % 返回: K*1 稀疏系数向量alpha residual = y; alpha = zeros(size(D, 2), 1); selected = false(size(D, 2), 1); % 记录哪些原子已被选中 for iter = 1:sparsity % 计算所有原子与残差的内积,找最相关的 innerProd = D' * residual; innerProd(selected) = -inf; % 已选原子不再重复选 [~, j] = max(abs(innerProd)); selected(j) = true; % 用选中的原子构成子字典,做最小二乘 Dj = D(:, selected); coef_temp = Dj \ y; % 注意是解满秩最小二乘 residual = y - Dj * coef_temp; % 提前终止:残差足够小就不必达到sparsity if norm(residual) < 1e-6 break; end end alpha(selected) = coef_temp; end

逻辑说明:每一轮先做原子与残差的相关性检测,用 selected 掩码把已选原子屏蔽,再用反斜杠运算符求解最小二乘。这里的关键坑位是:每次选新原子后,所有已选原子的系数都要重新算一遍,不能只保留新增系数,否则解不是最小二乘意义下的最优。代码里 coef_temp 每次都用 Dj \ y 整体重算,代价略高但解更准。残差阈值 1e-6 是提前终止条件,实际使用时如果噪声较大,这个阈值可以放宽到 1e-4,否则 OMP 会把噪声当成信号编进去。

参数说明:sparsity 不宜设得比 n 还大,8×8 patch 的维度是 64,稀疏度一般取 10 到 20。值得注意的是 OMP 每轮都在做 Dj \ y,当 Dj 过大时计算量会涨,实际项目中如果发现 OMP 是瓶颈,可以把反斜杠替换成预计算的 Gram 矩阵版本,这是后话。

3.3 字典更新与原子归一化

拿到一批样本的稀疏系数后,字典更新就走随机梯度下降。这一步的公式是 D ← D + η·(y-Dα)·αᵀ,本质是用重构误差的反向传播来调整原子方向:

function D = updateDictionary(D, Y_batch, A_batch, eta) % Y_batch: n*batchSize 样本矩阵 % A_batch: K*batchSize 稀疏系数矩阵 % eta: 当前学习率 residual = Y_batch - D * A_batch; % 批量重构误差 % 对每个样本单独做梯度累积,避免大矩阵运算 for i = 1:size(Y_batch, 2) grad = residual(:, i) * A_batch(:, i)'; D = D + eta * grad; end D = normalizeAtoms(D); % 每步更新后保持列范数为1 end function D = normalizeAtoms(D) % 每个原子归一化到单位范数,防止梯度更新导致原子无限膨胀 colNorms = sqrt(sum(D.^2, 1)); colNorms(colNorms < eps) = 1; % 防止除零 D = D ./ colNorms; end

逻辑说明:grad 是外积形式,表示重构误差对当前字典的梯度方向。更新完所有批内样本后统一做一次归一化,这一步不是可有可无——如果不归一化,目标函数里 ‖d_j‖₂ ≤ 1 的约束会被破坏,原子范数会越学越大,稀疏系数会越学越小,最终数值不稳定。这里使用逐样本循环而不是矩阵乘法累积梯度,是为了避免同时把整个 batch 的梯度矩阵存在内存里,对超大 batch 更友好。

参数说明:eta 从主循环传入,已经是衰减后的值。实际调试时如果发现 loss 曲线震荡,先看 eta 是否太大;如果收敛太慢,看 eta 是否太小。这两个症状都是用学习率调的典型问题,和深度学习里完全一样。

3.4 图像切块与重建质量评估

训练数据来自图像,但进入字典学习的是列向量。patchExtract 负责把图像切成重叠块并可选地做归一化:

function [patches, positions] = patchExtract(img, patchSize, step) % img: 二维灰度图 % patchSize: 块边长 % step: 滑窗步长,step=1时得到最大重叠块 % 返回: patches为样本矩阵,positions记录每块的左上角坐标 [H, W] = size(img); rows = 1:step:(H - patchSize + 1); cols = 1:step:(W - patchSize + 1); numPatches = length(rows) * length(cols); patches = zeros(patchSize * patchSize, numPatches); positions = zeros(numPatches, 2); k = 0; for r = rows for c = cols block = img(r:r+patchSize-1, c:c+patchSize-1); k = k + 1; patches(:, k) = block(:); % 列向量化 positions(k, :) = [r, c]; end end % 减去每块的DC分量,让字典学纹理而非亮度 means = mean(patches, 1); patches = patches - means; end

逻辑说明:把每个 patch 拉成列向量后,减去该块均值。这是字典学习里一个非常容易被忽略而后果严重的预处理操作——图像块的 DC 分量(即亮度均值)差异巨大,如果不减掉,字典原子会花大量精力去表示不同亮度,而不是纹理和边缘结构。减去后,重建时把 DC 单独存下来,叠回去即可。

重建质量评估 computePSNR 不复杂,但要注意输入取值范围。如果图像是 double 类型、像素范围 0 到 255,PSNR 公式里的峰值就取 255;如果归一化到 0 到 1,峰值取 1。经常有人混用导致 PSNR 虚高或虚低,这是评测里的暗坑。


4. 运行指南:从准备数据到训练收敛的完整流程

4.1 环境准备与数据组织

跑这套代码只需要 MATLAB,不需要额外工具箱。建议使用 R2019b 及以上版本,主要是为了兼容 string 数组和结构化网格语法;如果老版本跑不动,把代码里用字符串拼接的部分改成 sprintf 即可。项目对图像数据没有特殊要求,灰度或彩色均可,彩色图会先被转成灰度再切块,运行时在 demo_denoise.m 里会自动处理。

数据组织方式上,把训练图放进 data/train_images/ 目录,命名随意,代码会遍历目录下所有 .png/.jpg 文件。这一步常见的翻车现场是路径带中文或空格,MATLAB 对含中文路径的兼容性一言难尽,建议项目根目录和目标图片路径都保持纯英文。我之前的习惯是在项目根目录建一个setup.m,里面用addpath(genpath(pwd))把 src 目录一次性加进搜索路径,避免每次启动都手动调路径。

4.2 训练配置与一键运行

demo_denoise.m 承担两个角色:既演示训练流程,又顺带验证字典的去噪能力。核心骨架如下:

% 1. 加载训练图并切块 imgs = loadTrainImages('./data/train_images'); Y = []; for i = 1:length(imgs) patches = patchExtract(imgs{i}, 8, 4); % 步长4,控制样本量 Y = [Y, patches]; end Y = double(Y); % 2. 设置参数并训练 params.patchSize = 8; params.dictSize = 256; params.sparsity = 10; params.batchSize = 64; params.learningRate = 0.01; params.numEpochs = 20; [D, history] = onlineDictLearn(Y, params.dictSize, params); % 3. 训练曲线可视化 figure; plot(history.errors); title('Relative Reconstruction Error'); xlabel('Iteration (x50)'); ylabel('Rel Err');

运行方式就是在 MATLAB 命令行里直接敲demo_denoise,跑完会在 results 目录生成训练误差曲线和去燥前后的对比图。训练时间取决于数据量:我用 5 张 512×512 图、步长 4、epoch 设 20,大概 3 到 5 分钟跑完,中途会打印类似这样的日志:

epoch 1, iter 50, rel err 0.3421, lr 0.0098 epoch 1, iter 100, rel err 0.2817, lr 0.0096 epoch 2, iter 150, rel err 0.1932, lr 0.0094

如果看到 rel err 持续下降然后放缓,说明训练正常;如果曲线往上走,大概率是学习率过大或数据没做去均值处理。

4.3 训练过程的监控与收敛判断

收敛判断不能只看 loss 曲线,还要看字典本身的质量。我会在训练结束后做两件事:第一,用displayDictionary(D)把 256 个原子画成 16×16 的图像网格,肉眼扫一遍。学好的字典应该是一堆方向各异的边缘、条纹和纹理基元,如果全是噪点或重复的亮块,说明训练失败。第二,检查原子激活率——统计所有训练样本用到每个原子的次数,如果大量原子从未被选中,说明 dictSize 设得过大或者学习率衰减太快,原子还没来得及被“用”就冻结了。

这套代码在 demo 里自带了一个实用功能:把含噪声的测试图切块,用训练好的字典做稀疏编码,再用稀疏系数重建,计算 PSNR。这个闭环才是“字典学好了”的真正证明——字典本身误差低不代表下游任务效果好,因为字典可能把噪声也编码进去了。去噪场景下,训练字典用的应该是干净图,噪声图只在评测阶段出现。


5. 避坑与排查:在线字典学习最常见的五个经典翻车现场

5.1 原子“饿死”:字典里一半原子从来不被选中

现象:训练结束画出字典,发现大量原子非常相似,都是整体灰蒙蒙一片,或者干脆和初始值没什么差别;统计激活率时,相当一部分原子计数为 0。

原因:在线学习按随机顺序遍历样本,某些原子在初期就没被选中,梯度永远为 0,于是冻结在初始状态。这属于在线学习特有的“冷启动”问题,整批 K-SVD 因为每轮都扫全部样本,反而不容易出现。

解决:最有效的办法是“原子替换”——每隔一定迭代数统计原子激活率,把激活率最低的原子替换成当前残差最大的样本方向。代码里可以在主循环里加一个判断:

if mod(t, 500) == 0 counts = sum(A_batch ~= 0, 2); [~, deadIdx] = sort(counts, 'ascend'); for jj = 1:min(3, length(deadIdx)) r = Y(:, randi(size(Y, 2))) - D * ompSparseCode(Y(:, randi(size(Y, 2))), D, params.sparsity); D(:, deadIdx(jj)) = r / norm(r); end end

这个技巧叫“dead atom recycling”,我在项目里加了之后,字典利用率从 60% 提到 95% 以上。

5.2 重构误差不降反升:学习率参数在作怪

现象:训练日志里 rel err 前期下降,跑到中途突然跳高,然后一直下不来。

原因:学习率 η_t 衰减速度不够快。在线算法的学习率理论上要求满足 ∑η_t = ∞ 且 ∑η_t² < ∞,前一个条件保证能走到最优解附近,后一个条件保证不会一直在最优解附近震荡。代码默认的衰减是 η₀/(1+t/m),如果 η₀ 设成 0.1 甚至更大,后期步长仍然偏大,误差曲线就会像心电图。

解决:把初始学习率降到 0.005 到 0.01;同时把衰减函数改成 η_t = η₀ / (1 + t)^0.8,这是一个经验上很稳的衰减形式。改完参数后,重新看训练曲线,应该呈现单调下降后趋于平稳的形状。

5.3 字典学出来全是亮度模板,学不到纹理

现象:显示的字典原子全是中间亮、四周暗的斑点,几乎看不到方向和边缘。

原因:切块后没有减去 DC 分量。图像块的亮度均值差异远大于纹理差异,字典为了最小化重构误差,把大部分原子都用来表示不同亮度层级,真正有用的纹理原子只占了少数。

解决:在 patchExtract 中强制去均值,把均值作为单独信息保存。重建时先对稀疏系数重建结果加回均值,再拼回图像。这个预处理改动只影响训练阶段,对下游任务没有额外负担,却直接决定了字典质量。

5.4 OMP 耗时感人:稀疏编码成了整个流程的瓶颈

现象:训练日志里迭代很快,但每个 epoch 耗时越来越长,整个训练跑到一半就不想等了。

原因:OMP 每轮都要对已选原子做一次最小二乘,随着稀疏度 sparsity 增大,Dj \ y 的规模线性膨胀。如果 sparsity 设成 20 以上,且字典 K 很大,计算量会成倍上涨。另一个常见原因是把 sparsity 设得过高,明明残差早就降到阈值以下,还在继续选原子。

解决:第一,在 OMP 里保留提前终止条件,残差 norm 小于 1e-5 就跳出;第二,用 Gram 矩阵预计算 DᵀD,在 OMP 迭代中用查表替代重复计算 Dᵀ 与残差的内积。第二个优化在原子数超过 256 时收益非常明显。

5.5 随机种子导致结果不可复现

现象:第一次跑去噪 PSNR 是 32.5dB,第二次跑变成 31.8dB,什么都没改,觉得是玄学。

原因:randperm 打乱样本顺序、randn 初始化字典,每次运行都不一样。在线学习的结果本身受样本顺序影响,同一份数据两次训练会得到不同字典,下游 PSNR 自然不一样。

解决:在 config.m 里固定随机种子,训练前加一句rng(42)。这样至少保证同一份数据、同一参数下的结果是可复现的。真正严谨的调参流程应该是:固定随机种子后,再比学习率、稀疏度、字典规模这些参数,否则两个参数的差异会和随机种子带来的差异混在一起,根本分不清谁起了作用。


6. 二次开发:把在线字典接到自己的图像复原流水线里

6.1 改造一:用训练好的字典做图像去噪

拿到训练好的字典 D 后,把它移植到自己的项目里只需要三步:加载字典 → 对含噪图切块 → 对每个 patch 做稀疏编码再重建。下面这段代码可以直接嵌到任何图像处理脚本里:

% 含噪图像 im_noisy,训练好的字典 D,参数 patches = patchExtract(im_noisy, 8, 4); n = size(patches, 2); recon = zeros(size(patches)); for i = 1:n alpha = ompSparseCode(patches(:, i), D, 10); recon(:, i) = D * alpha; end im_denoised = colfilt2d(recon, 8, 4, size(im_noisy));

去噪效果很大程度上取决于 sparsity 的选择:噪声越强,sparsity 应该设得越小,因为噪声通常会在高频方向被少量原子捕捉,限制稀疏度等于在系数层面做低通滤波。这个改造几乎是零成本,唯一要改的是把训练阶段和推理阶段的 patchExtract 参数保持一致,包括步长和是否去均值。

6.2 改造二:从去噪扩展到压缩感知重构

完整读完这套代码的另一种价值,是理解“稀疏表示 + 字典”这个范式可以迁移到压缩感知:观测向量 y = Φx,其中 Φ 是测量矩阵,x 在字典 D 下稀疏。重构时求解 min ‖α‖₁ s.t. y = ΦDα。把上面 OMP 里的 D 替换成 ΦD 就可以复用全部代码,只是残差计算变成观测域而不是像素域。这个方向适合做信号压缩、MRI 重建之类的项目,也是我在这套代码上做过收获最大的一次扩展。

从那以后,我每次拿到一个新的字典学习项目,都会强制自己先跑一遍默认配置、画出字典网格、检查原子激活率,再谈调参。这三个动作加起来不到两分钟,却能省掉后面一整天的试错时间。希望这套代码和这份拆解能帮你在稀疏表示的路上少踩几个坑。

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

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

图像分类全流程实战:从数据准备到模型部署的关键技术解析

图像分类大概是深度学习中门槛最低、但想真正做好又最不容易的一个方向。很多人第一次跑通手写数字识别之后&#xff0c;觉得分类任务不过如此&#xff0c;结果到了真实项目里&#xff0c;面对脏数据、类别不均衡、模型不收敛、过拟合、部署效果差这一连串问题&#xff0c;才发…

作者头像 李华
网站建设 2026/10/21 5:26:52

经典蓝牙和低功耗蓝牙的通信建立过程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 5:26:28

自然语言驱动UI自动化:用Midscene替代XPath的实践与思考

在用 Midscene 做自然语言 UI 自动化之前&#xff0c;我大概有一年多的时间是跟 XPath 死磕过来的。当时接到的大部分测试任务其实没什么技术难度&#xff0c;无非是打开页面、点几个按钮、填几个表单、核对一下结果&#xff0c;可真正让人头大的反倒是“定位元素”这件事本身。…

作者头像 李华
网站建设 2026/10/21 5:26:15

JS逆向解析实战:从混淆代码到加密接口复现的完整指南

1. 拆解“JS逆向解析”到底在解决什么问题1.1 从一次真实需求说起去年帮一个做数据聚合的朋友处理过一个需求&#xff1a;他们需要定期从某个公开的行业信息平台上抓取一批商品价格数据&#xff0c;用于内部比价分析。听起来很简单对吧&#xff1f;但实际动手才发现&#xff0c…

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

算法公开,密钥保密:从AES到RSA的密码学基石

简介&#xff1a;围绕网络安全课程设计的加密技术资料包&#xff0c;聚焦加密算法原理与编程实现&#xff0c;主要面向高校信息安全、网络工程及密码学相关专业的学生&#xff0c;也适合需要借助具体案例快速理解经典算法的初级开发者。内容以RSA等经典加密算法的原理分析、课程…

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

设备诊断系统演进:从被动响应到主动预判,用数据避免非计划停机

我从一个具体场景说起&#xff1a;某工厂一台核心机组在深夜两点报了轴承温度异常&#xff0c;值班人员按流程先确认、再上报、再联系厂家&#xff0c;等维修团队带着备件赶到现场时&#xff0c;设备已经卡死&#xff0c;整个产线停了差不多九个小时。事后统计&#xff0c;直接…

作者头像 李华