OpenCV-DoG
DoG(Difference of Gaussian) 常用于边缘检测、特征检测, 是高斯函数的差分。我们已经知道可以通过将图像与高斯函数进行卷积得到一幅图像的低通滤波结果,即去噪过程,为一个正态分布函数,而 某一尺度上的特征检测可以通过对两个相邻高斯尺度空间的图像相减,得到 DoG 的响应值图像。
首先,高斯函数表示定义为:
G
σ
1
(
x
,
y
)
=
1
2
π
σ
1
2
exp
(
−
x
2
+
y
2
2
σ
1
2
)
G_{\sigma_{1}}(x, y)=\frac{1}{\sqrt{2 \pi \sigma_{1}^{2}}} \exp \left(-\frac{x^{2}+y^{2}}{2 \sigma_{1}^{2}}\right)
Gσ1(x,y)=2πσ121exp(−2σ12x2+y2)其次,两幅图像的高斯滤波表示为:
g
1
(
x
,
y
)
=
G
σ
1
(
x
,
y
)
∗
f
(
x
,
y
)
g
2
(
x
,
y
)
=
G
σ
2
(
x
,
y
)
∗
f
(
x
,
y
)
\begin{array}{l} g_{1}(x, y)=G_{\sigma_{1}}(x, y) * f(x, y) \\ g_{2}(x, y)=G_{\sigma_{2}}(x, y) * f(x, y) \end{array}
g1(x,y)=Gσ1(x,y)∗f(x,y)g2(x,y)=Gσ2(x,y)∗f(x,y)最后,将上面滤波得到的两幅图像
g
1
g_1
g1 与
g
2
g_2
g2 相减得到:
g
1
(
x
,
y
)
−
g
2
(
x
,
y
)
=
G
σ
1
∗
f
(
x
,
y
)
−
G
σ
2
∗
f
(
x
,
y
)
=
(
G
σ
1
−
G
σ
2
)
∗
f
(
x
,
y
)
=
D
o
G
∗
f
(
x
,
y
)
g_{1}(x, y)-g_{2}(x, y)=G_{\sigma_{1}} * f(x, y)-G_{\sigma_{2}} * f(x, y)=\left(G_{\sigma_{1}}-G_{\sigma_{2}}\right) * f(x, y)=D o G * f(x, y)
g1(x,y)−g2(x,y)=Gσ1∗f(x,y)−Gσ2∗f(x,y)=(Gσ1−Gσ2)∗f(x,y)=DoG∗f(x,y)即,DoG 表达式为:
D
o
G
≜
G
σ
1
−
G
σ
2
=
1
2
π
(
1
σ
1
e
−
(
x
2
+
y
2
)
/
2
σ
1
2
−
1
σ
2
e
−
(
x
2
+
y
2
)
/
2
σ
2
2
)
D o G \triangleq G_{\sigma_{1}}-G_{\sigma_{2}}=\frac{1}{\sqrt{2 \pi}}\left(\frac{1}{\sigma_{1}} e^{-\left(x^{2}+y^{2}\right) / 2 \sigma_{1}^{2}}-\frac{1}{\sigma_{2}} e^{-\left(x^{2}+y^{2}\right) / 2 \sigma_{2}^{2}}\right)
DoG≜Gσ1−Gσ2=2π1(σ11e−(x2+y2)/2σ12−σ21e−(x2+y2)/2σ22)具体图像处理中,就是将两幅图像在不同参数下的高斯滤波结果相减,得到 DoG 图:
- 求出不同参数下的高斯滤波输出并求出其 DoG 图像,如下图所示:
在 SIFT 的同一组中,每一层图像的尺寸都是一样的,但是平滑系数不一样。平滑系数分别为:0, σ \sigma σ, k σ k\sigma kσ, k 2 σ k^2\sigma k2σ, … …
![](https://img-blog.csdnimg.cn/e70ae27ad5de49fda9539f60a47cf5c5.png)
![](https://img-blog.csdnimg.cn/296eea9be000462b86847aab1aa45397.png)
![](https://img-blog.csdnimg.cn/296eea9be000462b86847aab1aa45397.png)
- 根据 DoG,求角点:三维图中的最大值和最小值的点是角点,如图所示:
标记的红色为当前像素点,黄色的圈标记邻接像素点。用这个方式最多检测相邻尺度的 26 个像素点。如果它是所有邻接像素点的最大值或最小值点,则标记红色被标记为特征点,如此依次进行,则可以完成图像的特征点提取。
我们可以计算出第一步中三个 DoG 图像中的极值点,如下图所示:
黑色为极小值;白色为极大值。
因此,原始图像上以显示的 DoG 角点检测结果,如下图所示:
OpenCV 代码帮助理解:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("2.jpg");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
//创建显示窗口
char INPUT_WIN[] = "input image";
char OUTPUT_WIN[] = "result image";
namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
imshow(INPUT_WIN, src);
//上采样
/*pyrUp(src, dst, Size(src.cols*2, src.rows*2));
imshow(OUTPUT_WIN, dst);*/
//降采样
Mat s_down;
pyrDown(src,s_down, Size(src.cols/2, src.rows/2));
imshow("sample_down", s_down);
//DOG----高斯不同
Mat gray_src, g1, g2, dogImg;
cvtColor(s_down, gray_src, CV_BGR2GRAY);
//两次高斯模糊
GaussianBlur(gray_src, g1, Size(3,3), 0.6, 0);
GaussianBlur(gray_src, g2, Size(3,3), 1.2, 0);
subtract(g1, g2, dogImg, Mat()); //差分图的灰度值比较小,图比较暗。
//归一化显示
normalize(dogImg, dogImg, 255, 0, NORM_MINMAX); //归一化,放到0-255显示。
imshow("DOG_img", dogImg);
waitKey(0);
return 0;
}