
简介这份凸优化课程大作业资料围绕MV子视角的帧间预测展开面向正在学习运动估计、光流与单应性变换的高校学生及课程实践者提供可直接运行的十一种方法对比方案。内容将穷尽块匹配、三步搜索、分层块匹配三类运动估计与光流估计、单应性矩阵方案进行交叉组合便于读者复现实验、比较精度与耗时并理解不同策略在帧间预测中的适用条件。压缩包共300个文件约214.99MB含216张png结果图、60个m脚本、10个txt说明、8个mat数据文件及少量py、asv文件覆盖代码、数据与实验输出代码含主流程与辅助函数配合结果图便于检查。已有301人学习适合用作课程大作业参考、算法对照实验和结果分析模板受上传体积限制随包数据集仅保留几个序列但目录组织清晰仍可据此搭建完整的运动估计与光流实验流程。1. 帧间预测的十一种解法值不值得跑一遍第一次做帧间预测多数人会把时间全压在光流法上结果预测帧的 PSNR 还不如一个块匹配的粗糙结果这事在凸优化课的答辩现场挺常见。这套用 MATLAB 代码搭起来的方案把运动估计拆成十一种可对比的实现块匹配三种、光流法四种、全局参数模型三种含单应性矩阵、网格模型一种全部塞进同一条评测流水线。它面向的是要交凸优化大作业、图像处理课设或毕设的人——你需要的不是又一个调包 demo而是一份能解释每种方法能量函数怎么写、参数怎么定、什么时候会崩的完整方案。2. 总体架构十一方法共用一条评测流水线十一种方法最难的地方在于每种方法的输出格式、参数名、耗时量级都不一样。如果每种写一个独立脚本最后想拼一张对比表光是把变量名对齐就要花掉一晚上。通常的做法是先把接口固定下来再往里填方法这样新增一种方法只需要写一个文件、在注册表里加一行。2.1 目录约定与数据流整个工程按职责分四层数据层放两帧或多帧序列方法层放十一个predict_*.m指标层放 PSNR、SSIM 和残差统计结果层统一写入results/。数据流是单向的读入参考帧和目标帧 → 转灰度、归一化到 [0,1] 的 double → 由注册表分派到具体方法 → 输出预测帧、运动矢量场、附加信息 → 指标层计算 → 结果写入文件。project/ data/ # 序列帧命名 frame_000.png 起 methods/ # predict_fs.m / predict_tss.m / predict_hs.m ... metrics/ # psnr_metric.m / ssim_metric.m / residual_stats.m utils/ # 梯度、双线性插值、坐标网格 results/ # 每种方法一个子目录内含预测图与 log.mat run_all.m # 唯一入口遍历注册表数据流里有一个容易被忽略的约定所有方法统一使用「目标帧 I0 由参考帧 I1 预测」这个方向也就是运动矢量描述的是 I0 中像素在 I1 中的位置。方向一旦在某个方法里写反后面所有指标都会失真而且这种错误不会报错只会让 PSNR 掉几个 dB很难定位。我一般会在utils/里放一个check_direction.m用已知的人工平移量做一次自检。run_all.m只做三件事读配置、循环注册表、汇总结果。它不关心任何方法内部细节这样换数据集时不需要改方法代码。2.2 统一函数签名与方法注册表统一的函数签名是整个架构能够成立的基础。所有方法必须接受同样的三个输入返回同样的三个输出function [pred, mv, info] predict_xxx(I0, I1, cfg) % 输入 % I0 - 目标帧double范围 [0,1]尺寸 H×W % I1 - 参考帧同尺寸同类型 % cfg - 结构体含 block/search/alpha/iter/lambda 等公共字段 % 输出 % pred - 预测帧H×W double与 I0 同尺寸 % mv - 运动矢量场H×W×2第三维依次为垂直、水平位移 % info - 结构体至少含 time 与 params 两个字段注册表负责把方法名映射到函数句柄和默认参数一张表就能看清十一种方法的全貌function reg method_registry() % 每行一个方法名称、函数句柄、默认参数、是否属于凸模型 reg { FS, predict_fs, struct(block,16,search,16), false TSS, predict_tss, struct(block,16,search,16), false DS, predict_ds, struct(block,16,search,16), false LK, predict_lk, struct(levels,3,win,15), false HS, predict_hs, struct(alpha,1.0,iter,200), true TVL1, predict_tvl1, struct(lambda,0.35,iter,300), true CLG, predict_clg, struct(win,9,iter,20), true TRANS,predict_trans,struct(thresh,2.0), true AFF, predict_aff, struct(thresh,2.0), true HOMO, predict_homo, struct(thresh,2.0,iter,500), true GRID, predict_grid, struct(grid,[4 4],blend,8), true }; end这张表就是答辩时最有用的一张图。评审老师问「你这个作业到底做了什么」你直接指着表说三种块匹配是组合搜索四种光流里 HS、TV-L1、CLG 是变分凸问题三种全局模型是参数化最小二乘网格模型是把单应性矩阵做成分块加权的凸组合。凸性的标注不是装饰它决定了你能不能说清楚求解器为什么收敛——非凸的那几种只能给局部最优这一点在报告里必须写明白硬说全搜索块匹配是凸问题现场很容易被追问到答不上来。公共参数集中在cfg里方法私有参数用cfg.method子结构传避免字段名冲突。2.3 评价指标与结果日志指标层至少要给四个量PSNR、SSIM、残差的一范数均值、单帧耗时。PSNR 是最直观的但只靠它会把「模糊但平滑」的预测判成好结果所以 SSIM 用来补结构相似性残差一范数用来观察误差分布是不是集中在运动边界。function m eval_prediction(I0, pred, mv, elapsed, border) % border评价时裁掉的边界像素数必须所有方法一致 I0c I0(1border:end-border, 1border:end-border); Pc pred(1border:end-border, 1border:end-border); mse mean((I0c(:) - Pc(:)).^2); m.psnr 10*log10(1/mse); % 峰值按 1.0 计算 m.ssim ssim(Pc, I0c); % 需要 Image Processing Toolbox r abs(I0c - Pc); m.res_l1 mean(r(:)); m.res_entropy entropy(r); % 残差集中度 m.time elapsed; m.mv_energy mean(sqrt(mv(:,:,1).^2 mv(:,:,2).^2)); endborder这个参数看着不起眼实际影响很大。块匹配在图像边缘找不到完整块光流在边界处的梯度是零填充网格模型在块重叠区要融合——这些都会让边缘几个像素的误差明显偏高。统一裁掉search半径大小的边界是对十一种方法最公平的口径。如果某个方法的边界处理特别粗糙裁边会掩盖它的缺点所以在报告里要同时给出裁边前后的两组数说明差异来源。结果日志用save(fullfile(results, name, log.mat), m, cfg)落盘run_all.m最后把所有log.mat读回来拼成一张总表。这张表就是验收和答辩的核心材料。3. 运动估计块匹配、光流法与变分凸松弛这一章是方案的主体。十一种方法里有七种属于运动估计三种块匹配负责「快而糙」的基线四种光流法负责「密而准」它们在同一个数据集上的差距正好能说明凸优化里数据项和正则项各自在起什么作用。3.1 块匹配三件套全搜索、三步与菱形全搜索是精度的上界也是耗时的下界。它的逻辑非常简单把目标帧切成 16×16 的块每块在参考帧的 ±16 邻域里滑一遍取 SAD 最小的位移作为该块的运动矢量。function [pred, mv, info] predict_fs(I0, I1, cfg) t0 tic; B cfg.method.block; R cfg.method.search; [H, W] size(I0); mv zeros(H, W, 2); pred zeros(H, W); for y 1:B:H for x 1:B:W y2 min(yB-1, H); x2 min(xB-1, W); tmpl I0(y:y2, x:x2); best inf; dy0 0; dx0 0; for dy -R:R for dx -R:R yy ydy; xx xdx; if yy 1 || xx 1 || yyB-1 H || xxB-1 W, continue; end cand I1(yy:yyB-1, xx:xxB-1); d sum(abs(cand(:) - tmpl(:))); % SAD 代价 if d best, best d; dy0 dy; dx0 dx; end end end mv(y:y2, x:x2, 1) dy0; mv(y:y2, x:x2, 2) dx0; pred(y:y2, x:x2) I1(ydy0:y2dy0, xdx0:x2dx0); end end info.time toc(t0); info.params cfg.method; end块大小和搜索半径是两个关键参数。块取 8 时运动边界贴合得好但平坦区容易出现多个等价匹配块取 16 时矢量场平滑代价是物体边缘被「糊」成整块。搜索半径取 16 能覆盖大部分平移量超过 32 后耗时按平方增长收益很低除非序列里有快速运动。三步搜索和菱形搜索是同一思路的加速版先用大步长粗搜再逐步缩小步长。三步搜索从 ±R/2 开始每轮步长减半共 log2(R) 轮计算量从 (2R1)² 降到 9·log2(R)。菱形搜索把搜索点排成菱形利用了运动矢量分布集中的先验在慢速运动序列上几乎能追平全搜索。这两种方法的代码结构和全搜索一致只是把内层双重循环换成按步长生成候选点集cfg.method.search的含义从「半径」变成「初始步长」报告里要写清楚否则复现的人会按全搜索的语义去读参数。3.2 光流法两族金字塔 LK 与 Horn-Schunck光流法求的是稠密场每个像素一个位移这就从「块级搜索」跳到了「能量最小化」。金字塔 LK 的思路是在每层金字塔上解一个加权最小二乘把大位移分解到粗层细层只负责修正残差function [uv, info] lk_pyramid(I0, I1, levels, win) % 由粗到细逐层求解初值来自上一层上采样 uv zeros([size(I0) 2]); for lv levels:-1:1 s 2^(lv-1); I0l imresize(I0, 1/s); I1l imresize(I1, 1/s); uv_l imresize(uv, [size(I0l,1) size(I0l,2)]); for k 1:5 % 每层 5 次迭代 Iw warp_by_flow(I1l, uv_l); % 用当前流场反向映射 [Ix, Iy] gradient(Iw); It Iw - I0l; [Ix2,Ixy,Iy2,Ixt,Iyt] local_sums(Ix,Iy,It,win); detA Ix2.*Iy2 - Ixy.^2; detA(detA 1e-6) 1e-6; % 平坦区保护 du -( Iy2.*Ixt - Ixy.*Iyt) ./ detA; dv -(-Ixy.*Ixt Ix2.*Iyt) ./ detA; uv_l(:,:,1) uv_l(:,:,1) dv; uv_l(:,:,2) uv_l(:,:,2) du; end uv imresize(uv_l, [size(I0,1) size(I0,2)]); end end窗口win取 15 或 21太小会在纹理弱的地方解出病态矩阵太大会把运动边界抹平。detA的下限保护是必须的天空、白墙这类区域梯度接近零不设下限会直接出现 Inf。金字塔层数取 3 能覆盖约 8 像素的位移再大就要加层但每加一层细层的初值误差也会放大。Horn-Schunck 是另一条路不假设局部恒定而是给全局一个光滑性约束把光流写成能量泛函。function [u, v] hs_flow(I0, I1, alpha, iters) [Ix, Iy] gradient(I0); It I1 - I0; K [1 2 1; 2 0 2; 1 2 1] / 12; % 拉普拉斯核中心为 0 u zeros(size(I0)); v u; for k 1:iters ubar conv2(u, K, same); % 邻域均值作为光滑项近似 vbar conv2(v, K, same); den alpha^2 Ix.^2 Iy.^2; u ubar - Ix .* (Ix.*ubar Iy.*vbar It) ./ den; v vbar - Iy .* (Ix.*ubar Iy.*vbar It) ./ den; end endalpha是数据项和光滑项的权重比。取 0.5 时流场细节多但噪声大取 2 以上整个场会过度平滑物体边界被抹成斜坡。这个参数没有通用最优值取决于序列的纹理密度报告里要给一张alpha从 0.1 扫到 5 的 PSNR 曲线说明你选的依据。HS 的能量泛函是严格凸的Gauss-Seidel 迭代收敛性可以证明这正是它和块匹配的本质区别——前者有唯一解后者只有「搜到的最小值」。3.3 TV-L1 与一阶原始-对偶求解TV-L1 把 HS 的平方惩罚换成 L1好处是运动边界不会被过度平滑坏处是能量不可微普通梯度下降直接失效。标准做法是写成鞍点问题用 Chambolle-Pock 的原始-对偶迭代$$ \min_{u,v}\ \lambda \int |\nabla I \cdot (u,v) I_t| \int |\nabla u| |\nabla v| $$function [u, v] tvl1_core(I0, I1, lambda, tau, sigma, nIter) [Ix, Iy] gradient(I0); It I1 - I0; [H, W] size(I0); u zeros(H,W); v u; ubar u; vbar v; p zeros(H,W,2); q zeros(H,W,4); % p: 数据项对偶, q: 正则项对偶 for k 1:nIter % 对偶上升数据项次梯度 r Ix.*ubar Iy.*vbar It; p(:,:,1) bsxfun(rdivide, p(:,:,1) sigma*Ix.*r, 1 sigma*abs(r)); p(:,:,2) bsxfun(rdivide, p(:,:,2) sigma*Iy.*r, 1 sigma*abs(r)); % 对偶上升正则项梯度逐点投影到单位球 [qx, qy] grad2(ubar, vbar); q proj_unit_ball(q sigma*[qx qy]); % 原始下降对偶散度回代 [dx, dy] div2(p(:,:,1), p(:,:,2)); u_new u tau*dx; v_new v tau*dy; [rx, ry] div2(q(:,:,1), q(:,:,2)); u_new u_new tau*lambda*rx; v_new v_new tau*lambda*ry; ubar 2*u_new - u; vbar 2*v_new - v; % 外推加速收敛 u u_new; v v_new; end end步长必须满足tau * sigma * ||K||² 1K是梯度算子离散情况下的范数上界是 8所以tau sigma 0.3是安全区。这一条是硬约束违反了不会报错只会让对偶变量在两三轮内涨到 1e6 然后全图 NaN。lambda控制数据项权重取 0.3 到 0.5 之间比较稳太小会让流场过度贴合噪声太大会退化成接近全零的场。CLG 是 HS 和 LK 的折中用局部窗口做加权最小二乘同时保留一阶正则实现上是 HS 迭代里把ubar换成窗口加权均值。四种光流法放在一起正好构成一条「局部恒定假设强度递减、正则强度递增」的谱系这是报告里最值得写的一段分析。4. 全局运动单应性矩阵、仿射与网格模型块匹配和光流都在求「每个点怎么动」全局模型反过来假设整幅图遵循一个参数变换用少量参数解释大部分运动。摄像机平移、绕光轴旋转这类场景全局模型的预测质量能明显超过稠密光流而且参数量从百万级降到 8 个这是它存在的意义。4.1 特征点检测与 RANSAC 剔除误匹配全局模型的第一步是找对应点。Harris 角点不依赖工具箱实现也短function pts harris_points(I, n, minDist) [Ix, Iy] gradient(I); Ix2 Ix.^2; Iy2 Iy.^2; Ixy Ix.*Iy; K fspecial(gaussian, 5, 1.5); Sxx conv2(Ix2,K,same); Syy conv2(Iy2,K,same); Sxy conv2(Ixy,K,same); k 0.04; R Sxx.*Syy - Sxy.^2 - k*(Sxx Syy).^2; % Harris 响应 R R / max(R(:)); cand R 0.01; [y, x] find(cand); [~, idx] sort(R(sub2ind(size(R), y, x)), descend); pts [x(idx) y(idx)]; pts greedy_nms(pts, minDist, n); % 贪心非极大值抑制 endk取 0.04 是经验值minDist取 8 能避免角点扎堆。取完点用简单的 SSD 匹配得到一组含大量误匹配的对应点对——平面纹理重复、光照变化都会让匹配错位。RANSAC 就是用来把这些外点踢出去的function [H, inlier] ransac_homography(p1, p2, thresh, nIter) N size(p1, 2); bestCnt 0; H eye(3); inlier false(1, N); for k 1:nIter idx randperm(N, 4); % 最少 4 点定一个单应 Hk dlt_homography(p1(:,idx), p2(:,idx)); if isempty(Hk) || any(~isfinite(Hk(:))), continue; end q Hk * [p1; ones(1,N)]; q q(1:2,:) ./ q(3,:); d sqrt(sum((q - p2).^2, 1)); in d thresh; if nnz(in) bestCnt, bestCnt nnz(in); H Hk; inlier in; end end end阈值thresh的单位是像素取 2 到 3 比较合适。取 1 会导致内点数太少、估计不稳取 10 会把明显错位的点也放进来最后解出的单应性矩阵在图像一角出现荒谬的缩放。迭代次数nIter取 500 在几百个点对的规模下足够内点率低于 20% 时建议加到 2000。4.2 DLT 求解与归一化精化直接线性变换把x2 H x1展开成两组线性方程八个未知量去掉尺度自由度用 SVD 解最小二乘。裸写 DLT 数值上很脆弱因为像素坐标在几百量级构造出的矩阵条件数极差标准做法是先做 Hartley 归一化function H dlt_homography(p1, p2) % p1, p2: 2×N对应点坐标 [T1, n1] normalise2d(p1); [T2, n2] normalise2d(p2); n size(n1, 2); A zeros(2*n, 9); for i 1:n x n1(1,i); y n1(2,i); u n2(1,i); v n2(2,i); A(2*i-1,:) [-x -y -1 0 0 0 u*x u*y u]; A(2*i, :) [ 0 0 0 -x -y -1 v*x v*y v]; end [~, ~, V] svd(A); Hn reshape(V(:,end), 3, 3); H T2 \ Hn * T1; % 反归一化 H H / H(3,3); end function [T, pn] normalise2d(p) c mean(p, 2); d mean(sqrt(sum((p - c).^2, 1))); s sqrt(2) / max(d, eps); T [s 0 -s*c(1); 0 s -s*c(2); 0 0 1]; pn T * [p; ones(1, size(p,2))]; pn pn(1:2,:) ./ pn(3,:); end归一化的作用是让两幅图的点云质心落在原点、平均距离为 √2矩阵条件数从 1e8 量级降到 1e2 量级。不做这一步SVD 的解在数值上完全不可信表现出来就是「大部分时候能跑偶尔某帧解出一个翻转的矩阵」。反归一化时注意是T2 \ Hn * T1顺序写反是另一个高频错误。得到单应性矩阵后用反向映射生成预测帧也就是对目标帧每个像素用H的逆找到它在参考帧里的位置function pred warp_homography(I, H, sz) [Hh, Ww] deal(sz(1), sz(2)); [xx, yy] meshgrid(1:Ww, 1:Hh); p H \ [xx(:); yy(:); ones(1, numel(xx))]; xs p(1,:) ./ p(3,:); ys p(2,:) ./ p(3,:); pred interp2(I, xs, ys, linear, 0); % 越界填 0 pred reshape(pred, Hh, Ww); endinterp2的参数顺序是 (图像, 列坐标, 行坐标)xs对应列、ys对应行写反的后果是整幅图沿对角线错位PSNR 会比不预测还低。4.3 网格运动模型与凸组合融合单应性矩阵假设整幅图共面一旦场景有前后景分层视差会让全局解在某一层上严重失配。网格模型的做法是把图切成 4×4 块每块单独估一个单应性矩阵再在重叠区做加权融合。融合权重取双线性核权重和恒为 1本质上是若干局部预测的凸组合——这一步是整套方案里「凸优化」三个字最直接的落点。function pred blend_grid(preds, weights) % preds: H×W×Kweights: H×W×K每个像素上 sum(weights,3) 1 pred sum(preds .* weights, 3); end权重图用fspecial(gaussian, blend*21, blend/2)生成blend取 8 到 16。太窄会出现块边界接缝太宽会让相邻块的运动互相污染。网格模型在复杂场景上通常比全局单应好 1 到 3 个 dB代价是参数从 8 个涨到 8×16128 个且每块的特征点数量可能不够需要在报告里说明外点率。5. 避坑与排查同一条流水线上最常翻车的五处十一种方法跑同一套数据出错的地方高度集中。下面五条是实际调试里最耗时间的每条都按「看到什么 → 为什么 → 怎么改」写。5.1 预测图整体偏移几个像素现象是预测帧看起来「差不多」但 PSNR 明显低于预期把两张图叠起来看会发现固定的对角偏移。原因是坐标系语义不统一MATLAB 是 1-based图像坐标是 (行, 列) 即 (y, x)而很多论文公式写的是 (x, y)interp2的参数顺序又是先列后行。三套约定混在一起位移的正负号和维度顺序迟早会错一次。解决方式是在utils/里固定一个make_grid(H,W)全工程只用它生成坐标网格并且在每个predict_*.m的头部注释里写清mv(:,:,1)是垂直位移、mv(:,:,2)是水平位移。再写一个自检函数把 I1 整体平移 (dy, dx) 得到 I0喂给方法看输出的 mv 是否等于 (−dy, −dx)。符号对不对一跑就知道。5.2 光流的 PSNR 崩到不如不平移现象是块匹配还能看四种光流法全部输出接近全零的场或者场的方向明显反了。原因有两个一是光流定义了 I0 到 I1 的位移但 warp 时用的是正向映射应该用反向二是块匹配返回整数像素光流返回浮点像素代码里如果对光流做了round或者int32转换亚像素信息直接丢失精度掉一个档次。解决方式是统一规定所有方法的mv都表示「目标帧像素在参考帧中的相对位置」warp 一律走反向映射插值一律用interp2(..., linear)。在run_all.m里加一条断言检查每种方法输出的mv是否至少有一个非零分量全零直接报警——这能拦住大部分方向写反的情况。5.3 单应性矩阵解出镜像或极端缩放现象是 RANSAC 报告内点数很高但解出的 H 让图像翻转或者缩到只剩一角。原因是特征点匹配用的是原始像素坐标没有归一化DLT 的矩阵条件数爆炸SVD 返回的极小奇异向量在数值上不可信另一种情况是 RANSAC 阈值放得太宽把一些方向错误但距离恰好落在阈值内的点当成了内点。解决方式是 DLT 内部强制做 Hartley 归一化并且在 RANSAC 之后加一道合理性检查det(H(1:2,1:2))必须为正且落在 [0.2, 5] 区间否则这一帧的单应判定为失败退回平移模型。失败帧的比例要写进报告这个数字比 PSNR 更能说明全局模型在什么场景下不可用。5.4 变分求解器两三轮后全图 NaN现象是 HS 或 TV-L1 跑到第 3 到 5 次迭代u、v突然变成 NaN 或 1e6 量级。原因是步长违反了收敛条件。HS 的迭代式里alpha如果取到 0.01 这种量级分母接近零更新量会爆TV-L1 的原始-对偶迭代必须满足tau*sigma*||K||² 1||K||²的离散上界是 8取tau sigma 0.25才安全。解决方式是给所有迭代加三重保护分母加eps、每轮检查any(~isfinite(u(:)))并提前退出、把最终步长和迭代次数写进info。我一般还会在run_all.m里记录「发散帧数」这个指标在答辩时很有说服力——它说明你知道方法的适用边界而不是只会调包。5.5 对比表里各方法的评价口径不一致现象是总表拼出来以后某个方法的 PSNR 高得离谱检查发现它没有裁边、或者用了 [0,255] 的灰度范围而别人用 [0,1]。PSNR 的定义里峰值项对结果影响极大范围差 255 倍dB 值直接差 48。解决方式是把评价参数写进配置文件由run_all.m统一注入方法代码不允许自己调eval_prediction。同时固定三件事灰度范围 [0,1]、裁边宽度等于该方法的最大搜索半径、SSIM 用默认的 11×11 高斯窗。这三条写进 README复现的人照做就能得到同一张表。6. 验收与答辩一张对比表加三条必答追问验收的核心材料只有一张表。把十一种方法按「模型类型、凸性、关键参数、精度排序、耗时量级、失败场景」六列排开精度用相对排序而不是绝对数值避免不同数据集之间不可比。编号方法模型类型凸性关键参数精度耗时典型失败场景1FS块匹配否block16, search16中高大位移、重复纹理2TSS块匹配否初始步长8中低低落入局部极小3DS块匹配否菱形半径2中低快速旋转4LK局部光流否levels3, win15中高中弱纹理、大位移5HS变分光流是alpha1.0, iter200中中运动边界模糊6TV-L1变分光流是lambda0.35, iter300高高步长越界发散7CLG混合光流是win9, iter20中高中窗口跨边界8TRANS全局参数是thresh2.0低极低存在旋转或缩放9AFF全局参数是thresh2.0中低极低强透视10HOMO全局参数是thresh2.0, iter500高平面场景低前后景视差11GRID网格模型是grid4×4, blend8高中高块内特征点不足答辩现场最容易被追问的三个问题提前准备好答案第一「哪些方法是凸的为什么」。答案要落到能量泛函上——HS、TV-L1、CLG 的数据项加正则项是凸的有唯一全局最优块匹配是组合搜索只能保证搜到的局部最小单应性矩阵的 DLT 是线性最小二乘凸但 RANSAC 的外层循环是非凸的。第二「为什么不直接上深度学习光流」。答案不是「深度学习不好」而是这个作业的交付目标是可解释的能量泛函与收敛性分析网络权重给不了这个。第三「单应性矩阵什么时候会崩」。答案是场景存在明显前后景视差、或者特征点集中在图像一角时前者让共面假设失效后者让归一化后的条件数依然很差。从那以后我每次带这类作业都要求学生先跑一遍「人工平移自检」再开始写方法——坐标系和方向这两个坑提前花十分钟验证能省掉后面两天对着 PSNR 曲线猜原因的时间。希望帮到你。本文还有配套的精品资源点击获取