结合此处的代码,重新归纳整理一下算法的流程:
- 输入一幅分辨率的
640
×
480
640\times 480
640×480 的RGB图像,记为
I
0
I_0
I0 ;
- 对
I
0
I_0
I0 高斯平滑,然后再进行
s
=
2
s=2
s=2 降采样。即将图像尺寸行和列方向缩减一半(代码中是用 cv::pyrDown 函数一次处理),得到
I
1
I_1
I1 (注:OpenCV实现了用于创建图像金字塔的两个函数 pyrDown 和 pryUp);
- 重复第2步,得到
I
2
,
I
3
,
I
4
,
I
5
,
I
6
,
I
7
,
I
8
I_2, I_3, I_4, I_5, I_6, I_7, I_8
I2,I3,I4,I5,I6,I7,I8 ,
I
8
I_8
I8 的长宽分别为
I
0
I_0
I0 的
1
/
256
1/256
1/256 (注意 640 和480 都不能被 256 整除,个人觉得输入分辨率应该调整为256的倍数,不过这是小问题) ;
I
0
∼
I
8
I_0\sim I_8
I0∼I8 分别有
r
r
r、
g
g
g、
b
b
b 分量,计算每一个
I
k
I_k
Ik 的“扩展颜色”
R
R
R 、
G
G
G 、
B
B
B、
Y
Y
Y 分量:
R
k
=
r
k
−
g
k
+
b
k
2
G
k
=
g
k
−
r
k
+
b
k
2
B
k
=
b
k
−
r
k
+
g
k
2
Y
k
=
(
r
k
+
g
k
)
−
∣
r
k
−
g
k
∣
2
−
b
k
\begin{aligned} R_k &= r_k-\frac{g_k + b_k}{2}\\ G_k &= g_k-\frac{r_k + b_k}{2} \\ B_k&=b_k-\frac{r_k + g_k}{2} \\ Y_k&=\frac{(r_k + g_k)-| r_k-g_k |}{2}-b_k \end{aligned}
RkGkBkYk=rk−2gk+bk=gk−2rk+bk=bk−2rk+gk=2(rk+gk)−∣rk−gk∣−bk 注意这里计算
r
r
r、
g
g
g、
b
b
b 分量的时候增加了一步:对于每个分量查找最大值,然后每个分量里面那些小于最大值1/10的点都置零。
亮度图I
k
′
=
r
k
+
g
k
+
b
k
3
I’_k=\frac{r_k+g_k+b_k}{3}
Ik′=3rk+gk+bk 亮度图计算时用的
r
r
r、
g
g
g、
b
b
b 分量不作处理,直接用。
方向图O
k
(
θ
)
=
c
o
n
v
2
d
(
I
k
′
,
W
G
(
σ
,
θ
)
)
O_k(\theta)=conv2d\left(I’_k,W_G(\sigma,\theta)\right)
Ok(θ)=conv2d(Ik′,WG(σ,θ))
W
G
W_G
WG 表示 Gabor 滤波器,用于边缘提取的线性滤波器,其频率和方向表达与人类视觉系统类似,能够提供良好的方向选择和尺度选择特性,而且对于光照变化不敏感,因此十分适合纹理分析。参考代码用 cv::getGaborKernel((8, 8), 4,
θ
\theta
θ, 8, 1) 来求得,忽略掉了不同的尺度
σ
\sigma
σ (注意这个
σ
\sigma
σ 是论文中用来表示尺度的符号,不是 Gabor核函数中的
σ
\sigma
σ 。Gabor核函数的详细说明看这里),我感觉这样不行。毕竟对于一幅尺寸为
1024
×
1024
1024 \times 1024
1024×1024 的输入图像,
I
8
I_8
I8 的尺寸才
4
×
4
4\times 4
4×4。
θ
\theta
θ 这里用弧度表示,
[
0
°
,
45
°
,
90
°
,
135
°
]
[0\degree,45\degree,90\degree,135\degree]
[0°,45°,90°,135°] 分别对应
[
0
,
π
/
4
,
π
/
2
,
3
π
/
4
]
[0,\; \pi/4,\;\pi/2,\;3\pi/4]
[0,π/4,π/2,3π/4] 。
c
o
n
v
2
d
conv2d
conv2d 操作用 cv::filter2D 函数实现。
- 计算差分特征图:对以上几步形成的
8
×
9
=
72
8\times 9=72
8×9=72 张图进行差分计算,最终得到42张特征图。论文选
c
=
{
2
,
3
,
4
}
c=\{2,3,4\}
c={2,3,4},代码中似乎取
c
=
{
1
,
2
,
3
}
c=\{1,2,3\}
c={1,2,3} ,以论文为准吧。
s
=
c
+
{
3
,
4
}
s=c+\{3,4\}
s=c+{3,4} 则 尺度
s
s
s 的图像的长宽分别是尺度
c
c
c 的图像的 1/8或者1/16分之一,先用 cv::resize 函数(interpolation=cv::INTER_NEAREST )对尺度
s
s
s 的图像进行放大,得到和 尺度
c
c
c 一样大小的图像,然后逐点减操作。得到
I
(
c
,
s
)
\mathcal{I}(c,s)
I(c,s) 、
R
G
(
c
,
s
)
\mathcal{RG}(c,s)
RG(c,s)、
B
Y
(
c
,
s
)
\mathcal{BY}(c,s)
BY(c,s) 以及
O
(
c
,
s
,
0
°
)
\mathcal{O}(c,s,0\degree)
O(c,s,0°)、
O
(
c
,
s
,
45
°
)
\mathcal{O}(c,s,45\degree)
O(c,s,45°)、
O
(
c
,
s
,
90
°
)
\mathcal{O}(c,s,90\degree)
O(c,s,90°) 、
O
(
c
,
s
,
135
°
)
\mathcal{O}(c,s,135\degree)
O(c,s,135°)。参考公式1、 公式2、公式3、公式4。每一组
(
c
,
s
)
(c,s)
(c,s) 计算7张图,一共42张图。
- 42张特征图合并成一张。在什么尺度上合并呢,在
σ
=
4
\sigma=4
σ=4 的尺度上合并,之前计算的42张特征图尺度分别是
{
2
,
3
,
4
}
\{2,3,4\}
{2,3,4},有24张特征图的长宽需要缩小到原来的1/4,有14张特征图需要缩小到原来的1/2。比如最开始输入的图像是
640
×
480
640\times 480
640×480,则合并的特征图分辨率是
40
×
30
40\times 30
40×30。
- 特征图的合并分两步进行,首先是组内合并,就是亮度特征和亮度特征合并(公式5),颜色特征和颜色特征合并(公式6(#eq7)),角度特征和角度特征合并([公式7]);第二步是这三个角度上的特征合并,求平均(公式8)。不管哪一步,合并之前都要。需要归一化操作。分两步进行归一化。
- 特征图
A
A
A 求
N
(
A
)
\mathcal{N}(A)
N(A) :1) 先找
max
(
a
i
,
j
)
\max(a_{i,j})
max(ai,j);2) 再找除了
a
i
,
j
a_{i,j}
ai,j 之外的局部最大值的平均
m
ˉ
\bar m
mˉ;3)
λ
=
(
max
(
a
i
,
j
)
−
m
ˉ
)
\lambda=(\max(a_{i,j})-\bar m)
λ=(max(ai,j)−mˉ),特征图里面所有的值都乘以
λ
\lambda
λ。参考代码求局部最大值的方法有点粗糙,没考虑“左上”、“右下”、“左下”、“右上”这4个点。