形状上下文(Shape Context)算法完全解读
- 前言
- 一. 轮廓提取(Canny Edge Detection)和轮廓点采样(Jitendra's Sampling)
- 二. 形状上下文(Shape Context)直方图矩阵的构建及其相似度度量方法
- 三. 局部外观(Local Appearance)描述矩阵的构建及其相似度度量方法
- 四. 匈牙利匹配(Hungarian)策略
- 五. 薄板样条插值(Thin Plate Spline)进行轮廓点拟合及伪点匹配策略
- 六. 损失函数计算和k-NN分类器进行分类
前言
一般来说,在计算机视觉任务中,形状匹配可以分为
- 基于特征(Feature-based): 基于傅里叶变化、特征点的、骨架的等等。
- 基于亮度 (brightness-based): 更偏向于使用像素的灰度值来进行形状匹配。
形状上下文作为一种基于特征的描述子,通过根据目标轮廓采样点之间的相互关系(如距离、梯度),提供了一种较为鲁棒的形状匹配策略。
下面我们一步一步来实现形状上下文算法。
一. 轮廓提取(Canny Edge Detection)和轮廓点采样(Jitendra’s Sampling)
轮廓提取
对于轮廓点提取我们采用canny算子来提取轮廓点,主要步骤就是
- 高斯平滑
- sobel提取梯度幅值和方向
- 非极大抑制
- 双阈值检测以及连接(滞后门限处理)
这里就不细说了,下面说一下轮廓采样如何做。
轮廓采样
对于一般图像,如果采样一定数量像素点的图片可以使用均匀采样、随机采样等等。但是对于二维轮廓点集,这些采样直观上想应该是行不通的,因为二维轮廓点的分布并不是均匀的。
下图1,2是使用canny算子提取的轮廓,3,4是随机采样100个点的采样图,可以看到采样过后轮廓信息丢失严重。那么我们如果想得到5,6这样的采样结果呢?
一种朴素的想法:我们是否可以将轮廓点对之间的欧式距离考虑到采样步骤中,得到一个 相对均匀(或者说是,点对间足够分散) 的的轮廓采样数据呢?比如说,每次剔除最短距离点对中的任意一个点,并解除它与其他点之间的距离关系,依次重复,直至点对只剩下所需数目的点集。
这个就是Jitendra’s sampling的思路,下面附上Jitendra采样的流程:
一些Tips:
- 实现的过程中第一步别忘了对轮廓点进行随机打乱,这样子可以保证删除点对的随机性以及避免删除时产生连锁反应(lab>lbc>lcd>lde,如果每次删除右边的点时候,你会发现删除步骤可能变成了e→d→c→b→a)。
- 其中阈值(k = 3)主要是为了防止轮廓点过多而预设的一个倍数关系。如果轮廓点(I)>3×采样点(N),直接对轮廓点集随机采样,取前3N个就行,如果用c++的进行random shuffle别忘了随机化种子。
- 可以先对点对距离进行排序,然后逐一删除符合条件(点对每个点都没有被删除)的右侧点(左侧点也行,只要规则统一就可以)。
附上论文中这部分Matlab源码,其他语言可以尝试实现以下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | function [xi,yi,ti]=get_samples_1(x,y,t,nsamp); % [xi,yi,ti]=get_samples_1(x,y,t,nsamp); % % uses Jitendra's sampling method N=length(x); k=3; Nstart=min(k*nsamp,N); ind0=randperm(N); ind0=ind0(1:Nstart); xi=x(ind0); yi=y(ind0); ti=t(ind0); xi=xi(:); yi=yi(:); ti=ti(:); d2=dist2([xi yi],[xi yi]); d2=d2+diag(Inf*ones(Nstart,1)); s=1; while s % find closest pair [a,b]=min(d2); [c,d]=min(a); I=b(d); J=d; % remove one of the points xi(J)=[]; yi(J)=[]; ti(J)=[]; d2(:,J)=[]; d2(J,:)=[]; if size(d2,1)==nsamp s=0; end end |
二. 形状上下文(Shape Context)直方图矩阵的构建及其相似度度量方法
对于轮廓中的点对,哪些信息对于形状匹配起到贡献呢?
- 距离,
- 角度,
- 等…
那么对于每个轮廓点,我们可以构建以其为中心的极对数坐标系 log-polar coordinates(包括12个角度区域和5个距离区域,如下图c),再将它周围的轮廓点映射到每个区域内,然后统计落在每个区域的轮廓点个数,最后进行归一化处理(即除以落在所有区域中的轮廓点数)。这样子我们就生成了形状上下文直方图矩阵。如下图所示,我们可以直观的看到,相似度d-e < 相似度d-f。
一些Tips:
- 采用极对数坐标的好处:主要使得描述子对邻近采样点更敏感,强化局部特性。
- 首先求出点对之间的距离矩阵,再除以距离均值,使形状上下文描述符对缩放不敏感。然后再将距离矩阵映射到对数域中,与阈值作比较。那么我们可以想,因为对数函数是单调变换,所以log域中的五个距离阈值可以映射到欧氏距离中(0.125,0.25,0.5,1.0,2.0,这里大于2.0的点认为太远,因此不考虑)后,将距离矩阵与阈值比较,可以大幅简化log运算。如下图:
1 2 | % use a log. scale for binning the distances r_bin_edges=logspace(log10(r_inner),log10(r_outer),5); |
-
角度矩阵的求法也是如上图,相对简单。
-
求解完距离矩阵和角度矩阵就可以做区域映射了,统计各个区域内点的个数。如果这里我们采样100个轮廓点,将会生成100×60大小的矩阵。
-
别忘了做归一化处理。
到这我们的形状上下文直方图矩阵就构建完成了。下面我们使用卡方统计χ2 来计算点与点的相似度。
经过之前的计算,我们获得了输入图像 和模板图像 的N(100)×K(60)的形状上下文直方图矩阵,对于输入图像和模板图像中的每一个点,都有K-bin的直方图,分别记作 g(k) 和 h(k), 代入卡方公式计算相似度度量矩阵:
这样子我们就得到了关于形状上下文的相似度度量矩阵(N×N)。这里解释一下为什么是N×N的矩阵:首先输入图像和模板图像均采样N个轮廓点(也可以采样不同的轮廓点,再通过后续我们所说的伪点策略做匹配),然后对于两张图片每个点对,通过将 g(k) 和 h(k) 带入卡方公式,可以计算出一个Cs。所以一共生成了N×N的矩阵。
三. 局部外观(Local Appearance)描述矩阵的构建及其相似度度量方法
根据形状上下文直方图矩阵,我们获得到了全局信息,即全局点对目标点的一个方位矩阵,类似于在不同方向和角度轮廓点集的密度信息。那么我们下面考虑再添加一个局部外观信息约束。
局部外观信息有很多,例如
- 局部方向(local orientation)
- 局部颜色直方图(local color histogram)
- 局部纹理(local texture)
- 局部拓扑(local topology)
- 等等…
我们在这里考虑使用局部方向(local orientation) 作为形状上下文的局部外观信息。
- 对于输入图像 和模板图像,我们计算它们灰度图的梯度图Gx和Gy,然后找到轮廓点对应的梯度值并求出切向角 θ1,θ2。
- 这里我们引入切向角非相似性(tangent angle dissimilarity)函数作为衡量局部方向的依据:
为什么可以这么定义呢,我们来看下图,假设有一个半径为1的圆,那么对于 θ1,θ2,通过余弦和正弦将其转化到欧氏空间中,再计算它们的欧式距离,就可以衡量两个角度的相似性了。
一些Tips:
可以对切向角非相似性函数做变换,得到一个简单的计算公式:
最后一步就是将两个相似度度量矩阵进行加权求和得到一个总的相似度度量矩阵:
这里Cs对应于形状上下文(Shape Context), CA对应于局部外观(local Appearance),论文给的β=0.1。
四. 匈牙利匹配(Hungarian)策略
匈牙利匹配是一种常见的二部图匹配,复杂度O(N3),常用的场景有:
- 寻找最大匹配问题,也就是寻找增广路径的过程:
给定匹配关系,找出使得匹配个数最多的一种匹配。如下图,最大匹配为3(L1-R2, L2-R3, L3-R1):
这里我们不细说这种情况。
- 寻找最短路径的问题:给定N×N个点对的距离,求出使得距离最小的点对匹配。
在这里我们将之前的相似度度量矩阵抽象成距离矩阵,使用匈牙利算法的目的就是求出使得 总损失(距离) 最小的点对匹配。
吃过饭再写。。。。。。。。。。。。。。。。。。
五. 薄板样条插值(Thin Plate Spline)进行轮廓点拟合及伪点匹配策略
明天再写…
六. 损失函数计算和k-NN分类器进行分类
明天再写…