【HIMO】跨模态图像匹配算法:IMO方向场提取与PolarP描述符源码精讲

摘要

HIMO(Cross-Arbitrary-Modality Image Invariant Feature Transform with Hierarchical Intrinsic Major Orientation)是北京理工大学团队发表于 IEEE TPAMI 2026 的手工设计(handcrafted)跨模态图像匹配方法,官方开源了纯 MATLAB 实现。本文不解读论文公式推导,而是直接走读 HIMO_image_matching 子目录的全部 .m 源码,梳理其主流程调用链、核心数据结构,并重点拆解两个与 SIFT 系方法差异最大的设计:IMO 方向场的深浅双路融合与奇偶耦合机制 ,以及基于逐像素方向差异构造的 DoF 稳定性图。所有结论均可对照源码文件与具体行号验证。


论文 :HIMO: Cross-Arbitrary-Modality Image Invariant Feature Transform with Hierarchical Intrinsic Major Orientation

代码 :HIMO_ImgMatching


一、项目定位与仓库结构

仓库 HIMO_ImgMatching 下的 HIMO_image_matching 子目录是一套纯 MATLAB、Apache-2.0 许可的跨模态图像匹配实现,面向可见光/红外/SAR/遥感等任意模态组合,不依赖深度学习。目录结构:

目录/文件 作用
A_HIMO_demo.m 主流程入口:读图→建金字塔→检测关键点→描述与匹配→几何变换与拼接
func_HIMO/ HIMO 算法核心:方向场提取、金字塔构建、关键点检测、描述符、多尺度匹配、外点剔除
func_Math/ 底层数学算子:Log-Gabor 滤波(LogGabor.m)、相位一致性(phasecong3.m)、Harris/ShiTomasi 角点响应、共现滤波(CoOcurFilter.m)、RANSAC 式几何一致性校验(FSC.m)
functions/ 以 .p 形式发布的工程壁(读图、预处理、可视化、图像变换等),源码未开放,本文不涉及其内部实现

效果展示见图 1(原仓库 README 配图,跨模态/多数据集/稠密匹配效果):

HIMO cross-modal matching

图 1:HIMO 在光学-SAR、光学-红外等跨模态图像对上的匹配效果示意。来源:HIMO_ImgMatching README display1.jpg


二、整体匹配流程

A_HIMO_demo.m 的调用链可以归纳为四个阶段(源码 A_HIMO_demo.m:44-129):

HIMO pipeline overview

图 2:HIMO 主流程架构图。四个阶段严格对应 A_HIMO_demo.m 中的四段注释划分,右上角"IMO 方向场提取"是全流程中唯一与 SIFT 系方法在底层算子上不同的环节。来源:重绘自源码结构,原仓库无此图。

四个阶段的关键参数(A_HIMO_demo.m:29-42):

参数 默认值 含义
nOctaves / nLayers 3 / 2 高斯金字塔的组数与每组层数
G_resize 1.2 组间降采样比例(远小于 SIFT 的 2,换取跨模态尺度搜索密度)
key_type 'PC-ShiTomasi' 关键点类型:相位一致性 + ShiTomasi 角点响应联合
patchsize / NBA / NBO 72 / 12 / 12 PolarP 描述符的支撑域半径与角度/方向分 bin 数
Error / K 5 / 1 外点剔除的重投影误差阈值(像素)与重复次数

值得注意的是 G_resize 取 1.2 而非 2------这是穷举式多尺度策略的直接代价:由于跨模态图像不满足统一的退化模型,HIMO 无法像 SIFT 一样用 DoG 极值自适应估计特征尺度,只能把尺度间隔缩小、金字塔层数增多,靠后续在所有 octave × layer 组合间暴力匹配来覆盖尺度差异(这一点作者在 README 的"Open Questions"里也坦承是尚未解决的问题)。


三、IMO 方向场提取:深浅双路融合与奇偶耦合

这是 HIMO 相对于 RIFT、SRIF 等同类跨模态方法最核心的设计,集中在 func_HIMO/Intrinsic_Major_Orientation.m。

IMO orientation extraction internals

图 3:IMO 方向场提取内部数据流。浅层/深层两路方向估计各有互补的失效场景,奇偶耦合环节按局部结构置信度逐像素择优。来源:重绘自源码结构,承载了原始代码注释中未显式画出的"两路估计如何合并"这一关键逻辑,原仓库和论文配图均未给出。

浅层路径 (:12-19)用一对 Odd-Sobel / Even-Sobel 算子提取像素梯度,并把二者编码为复数 Gx = Gx1·i + Gx2·sign(Gx1),本质是把梯度方向和梯度强度打包进复平面,方便后续与深层响应直接相加。

深层路径 (:21-33)调用 LogGabor.m 构建 4 尺度 × 6 方向的 Log-Gabor 滤波器组,取每个方向/尺度的复响应 EO{i,j},按方向余弦/正弦权重叠加进 Gx, Gy。Log-Gabor 响应对光照和模态差异更鲁棒,但空间定位精度不如像素梯度------这正是两路融合要解决的互补问题。

融合后(:34-67)用圆形窗口做多尺度加权的结构张量二阶矩估计,得到 G x x , G y y , G x y G_{xx}, G_{yy}, G_{xy} Gxx,Gyy,Gxy,并进一步定义:

G s x = G x x − G y y , G s y = 2 G x y G_{sx} = G_{xx} - G_{yy}, \qquad G_{sy} = 2G_{xy} Gsx=Gxx−Gyy,Gsy=2Gxy

方向估计为:

θ = atan2 ⁡ ( G s y ,   G s x )   /   2 + π / 2 \theta = \operatorname{atan2}(G_{sy},\, G_{sx})\,/\,2 + \pi/2 θ=atan2(Gsy,Gsx)/2+π/2

其中 G x x , G y y , G x y G_{xx}, G_{yy}, G_{xy} Gxx,Gyy,Gxy 是融合后复数梯度场在圆形窗口内加权求和得到的二阶矩(结构张量的三个独立分量)。这与 Harris 角点检测里的结构张量主方向估计是同一套数学工具,只是输入换成了融合后的复数梯度场。

奇偶耦合 (:69-90)是容易被忽略但很关键的一步:Odd-Sobel 主导和 Even-Sobel 主导分别给出两套方向估计 magnitude(:,:,1) 和 magnitude(:,:,2),代码逐像素比较二者幅值,取更大(更可靠)的一路方向作为输出;当 int_flag=1(跨模态场景)时,还会用两路幅值的局部一致性((Gxx·Gyy - Gxy²)/(Gxx+Gyy))做二值化置信度图,直接把不可靠区域的方向响应清零,而不是像 int_flag=0 时那样用幅值的四次方根做软加权。

⚠️ 这里的"深层/浅层"是笔者根据代码注释与变量命名给出的工程化概括(代码本身没有这两个词),用于帮助理解两路方向估计的物理含义差异,并非论文原文术语,读者如需严谨对照请以源码变量名为准。


四、DoF 稳定性图与关键点检测

Build_Himo_Pyramid.m 在构建金字塔的同时,顺手计算了一张跟关键点检测强相关的副产品------DoF(Degree of Fluctuation)稳定性图 (:30-47):

matlab 复制代码
DoF = DoF .* prod(abs(abs(imresize(map_curr,[M,N]) - ...
                          imresize(map_prev,[M,N])) * norm_f - 1), 3).^(6/n_scale);
DoF = DoF .* log(abs(imresize(I_t,[M,N]) - I) + 1);

直觉是:如果某个像素的 IMO 方向估计在相邻金字塔层之间几乎不变(差值接近 0 或接近 π/2 的边界反转),说明这里的结构在跨尺度下是稳定的,值得当关键点;反之则大概率是噪声或模态差异导致的伪响应。DoF 最终以逐层累乘的形式融合所有 octave/layer 对的差异,再乘以降采样前后灰度差的对数项(CoF feature,衡量共现滤波引入的灰度扰动)。

关键点检测(Detect_Himo_Keypoint.m:19-62)再把这张图当作权重叠加到角点响应上:

matlab 复制代码
value = Harris(I_p,scale);          % 或 ShiTomasi
value = value .* weight;            % weight 即 DoF(经 Image_Pat 补边)

当 key_type 含 'PC' 时,还会先用 phasecong3.m 算出相位一致性响应叠加进原图灰度,再送入角点检测------这是为了让角点响应同时捕捉到强度边缘和相位结构边缘,缓解跨模态图像强度边缘不一致的问题。最终经过非极大值抑制(ordfilt2 灰度膨胀)和按响应值排序取 Top-N(默认 5000 个)。


五、PolarP 描述符与多尺度匹配

5.1 描述符结构

PolarP_Descriptor.m 把支撑域(半径 W = patchsize/2)按半径分成 3 个同心环(圆心区 + 内环 + 外环,面积比由 NBA 决定),每环再按角度分成 NBA(默认 12)个扇区,方向上分 NBO(默认 12)个 bin,构成一个类似 GLOH(Gradient Location and Orientation Histogram,梯度位置方向直方图)但径向分区更简单的极坐标直方图:

分量 维度 说明(对应代码变量)
feat_center NBO 圆心区方向直方图
feat_outer NBO × NBA × 3 内环/外环/融合环的方向-角度联合直方图
feat_skip 2 × NBO 奇偶扇区交叉加权,增强对小角度偏差的容忍
feat_all NBO 融合环按角度求均值,压缩一份全局统计

是否启用旋转不变性由 rot_flag 控制:启用时先调用 Base_Direction.m 估计关键点主方向,再把所有角度 bin 相对主方向归一化;同时为了消除主方向估计 180° 模糊,还做了一次"左右半区方差比较"的翻转判定(:94-98),这是论文没有单独命名、但工程上处理得比较细的一个小技巧。

5.2 多尺度匹配策略

因为前面提到 HIMO 没有自适应尺度估计,Multiscale_Strategy.m 必须在参考图和待匹配图的所有 octave × layer 组合间暴力搜索。版本 2(非并行模式,:92-148)的迭代优化逻辑用 mermaid 表示如下:
#mermaid-svg-2Cw0vXSftqac91vI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2Cw0vXSftqac91vI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2Cw0vXSftqac91vI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2Cw0vXSftqac91vI .error-icon{fill:#552222;}#mermaid-svg-2Cw0vXSftqac91vI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2Cw0vXSftqac91vI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2Cw0vXSftqac91vI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2Cw0vXSftqac91vI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2Cw0vXSftqac91vI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2Cw0vXSftqac91vI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2Cw0vXSftqac91vI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2Cw0vXSftqac91vI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2Cw0vXSftqac91vI .marker.cross{stroke:#333333;}#mermaid-svg-2Cw0vXSftqac91vI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2Cw0vXSftqac91vI p{margin:0;}#mermaid-svg-2Cw0vXSftqac91vI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2Cw0vXSftqac91vI .cluster-label text{fill:#333;}#mermaid-svg-2Cw0vXSftqac91vI .cluster-label span{color:#333;}#mermaid-svg-2Cw0vXSftqac91vI .cluster-label span p{background-color:transparent;}#mermaid-svg-2Cw0vXSftqac91vI .label text,#mermaid-svg-2Cw0vXSftqac91vI span{fill:#333;color:#333;}#mermaid-svg-2Cw0vXSftqac91vI .node rect,#mermaid-svg-2Cw0vXSftqac91vI .node circle,#mermaid-svg-2Cw0vXSftqac91vI .node ellipse,#mermaid-svg-2Cw0vXSftqac91vI .node polygon,#mermaid-svg-2Cw0vXSftqac91vI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2Cw0vXSftqac91vI .rough-node .label text,#mermaid-svg-2Cw0vXSftqac91vI .node .label text,#mermaid-svg-2Cw0vXSftqac91vI .image-shape .label,#mermaid-svg-2Cw0vXSftqac91vI .icon-shape .label{text-anchor:middle;}#mermaid-svg-2Cw0vXSftqac91vI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2Cw0vXSftqac91vI .rough-node .label,#mermaid-svg-2Cw0vXSftqac91vI .node .label,#mermaid-svg-2Cw0vXSftqac91vI .image-shape .label,#mermaid-svg-2Cw0vXSftqac91vI .icon-shape .label{text-align:center;}#mermaid-svg-2Cw0vXSftqac91vI .node.clickable{cursor:pointer;}#mermaid-svg-2Cw0vXSftqac91vI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2Cw0vXSftqac91vI .arrowheadPath{fill:#333333;}#mermaid-svg-2Cw0vXSftqac91vI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2Cw0vXSftqac91vI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2Cw0vXSftqac91vI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2Cw0vXSftqac91vI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2Cw0vXSftqac91vI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2Cw0vXSftqac91vI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2Cw0vXSftqac91vI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2Cw0vXSftqac91vI .cluster text{fill:#333;}#mermaid-svg-2Cw0vXSftqac91vI .cluster span{color:#333;}#mermaid-svg-2Cw0vXSftqac91vI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2Cw0vXSftqac91vI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2Cw0vXSftqac91vI rect.text{fill:none;stroke-width:0;}#mermaid-svg-2Cw0vXSftqac91vI .icon-shape,#mermaid-svg-2Cw0vXSftqac91vI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2Cw0vXSftqac91vI .icon-shape p,#mermaid-svg-2Cw0vXSftqac91vI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2Cw0vXSftqac91vI .icon-shape .label rect,#mermaid-svg-2Cw0vXSftqac91vI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2Cw0vXSftqac91vI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2Cw0vXSftqac91vI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2Cw0vXSftqac91vI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
是
否
外层循环: octave2 遍历待匹配图金字塔
内层循环: octave1 遍历参考图金字塔
该 octave×layer 的描述符已缓存?
按需计算 PolarP_Descriptor

(先用 sample_out 过滤已匹配关键点)
Match_Keypoint: matchFeatures 最近邻 + FSC 剔除外点
本轮内点数 > 50?
记录 idx_1/idx_2(已匹配关键点下次跳过)

并把本轮内点存入 ref 供下一次 FSC 做参考一致性检验
遍历完所有 octave 组合
按 octave1-octave2 聚合,取内点数最多的对角窄带
最后一轮 K 次独立 FSC 剔除外点,取内点数最多的一次为最终结果

这里有两个不是一眼能看出来的工程优化:

  1. 按需计算 + 增量过滤 :描述符不是一次性对所有尺度组合算好,而是遇到才算(descriptors_1{octave1,layer1} 为空才调用 PolarP_Descriptor),且每次新一轮匹配前用 sample_out 把已经匹配成功的关键点从候选集里删掉,避免同一对关键点在不同尺度组合里被重复匹配、污染后续的外点统计。
  2. 跨轮次参考一致性(ref) :一旦某个尺度组合匹配到超过 50 个内点,这些内点会被传给 Match_Keypoint → Outlier_Removal/FSC 作为"已知可信对应点"参与下一轮的几何模型估计(FSC.m:13-18 把 ref 拼进待拟合点集),相当于用已确认的强约束去校正后续尺度组合里噪声更大的候选匹配,而不是每轮都从零开始做纯随机采样一致性。

外点剔除本身(func_Math/FSC.m)是一个针对 similarity/affine/projective 三种模型的最小子集采样一致性算法(抽样点数分别为 2/3/4),按理论组合数和 max_iter=800 取较小值作为实际迭代次数,属于 RANSAC 的变体实现,论文称之为 FSC(Fast Sample Consensus)。

数据集匹配效果见图 4,三个公开/自建跨模态数据集(GCZ、WDS 及改标的 MRSI/SRIF)上的表现:

dataset matching performance

图 4:多数据集匹配效果对比。来源:HIMO_ImgMatching README display2.jpg


小结

HIMO 的工程价值不在于引入了多复杂的新模块,而在于把几个经典算子(Sobel、Log-Gabor、相位一致性、结构张量、RANSAC)按一条经过仔细设计的流水线组合起来,专门解决跨模态图像匹配中"强度边缘不可靠"这一根本问题:

  • 设计亮点:IMO 的深浅双路 + 奇偶耦合本质是在逐像素粒度上做"用哪种方向估计更可信"的局部决策,比单一算子更能适应不同模态组合下边缘特性的巨大差异;DoF 稳定性图把尺度跨层方向一致性直接转化为关键点筛选的先验权重,是一种代价很低但针对性很强的技巧。
  • 局限性(作者自述 + 代码可见) :相位一致性关键点检测器在图像边缘会产生强响应伪影,当前只能粗暴地把边缘一圈响应清零(Detect_Himo_Keypoint.m 中 border 相关逻辑),既浪费了边缘纹理也没有精确估计伪影范围;多尺度匹配是穷举式而非自适应,Multiscale_Strategy.m 的运行时间会随 nOctaves × nLayers 平方增长,大尺度差异场景下代价不小。
  • 个人判断 :作为一个纯手工特征方法,HIMO 在可解释性和无需训练数据这两点上对遥感/跨模态场景仍有现实意义,但穷举尺度搜索的复杂度短板,意味着它更适合离线配准而非实时场景;如果要工程化落地,Multiscale_Strategy.m 里"按需计算 + 跨轮次参考一致性"这套思路本身比 HIMO 的具体描述符更值得复用到其他多尺度匹配流水线上。
相关推荐
小南家的青蛙1 小时前
华为云DCS全产品对比
redis·1024程序员节
芝麻开门2921 小时前
c++11
c++11·1024程序员节
乃嘿仔1 小时前
AI 热点日报 · 2026-10-24
1024程序员节
HY小宝F1 小时前
智能摄像头系统 30 天学习计划 Day 08 · FFmpeg:成为你的“视频瑞士军刀”
1024程序员节
zyseo81 小时前
谷歌SEO 排名因素权重地图:把精力花在刀刃上
1024程序员节
basketball6161 小时前
动态规划第一章:引论
算法·动态规划·1024程序员节
CRMEB系统商城1 小时前
家电零售的供应商协同与物流提效
java·开发语言·人工智能·小程序·1024程序员节
xiaoniu1428571 小时前
命题的映射化
数学·1024程序员节·高中数学·文化课
jason.zeng@15022071 小时前
Nginx 配置详解(静态 HTML、下载目录、API 反向代理三套场景)
java·vue.js·1024程序员节