DOG(Difference of Gaussian)意为高斯函数的差分。是灰度图像增强和角点检测的一种方法。
由于DOG是利用高斯模糊(也叫高斯平滑)实现的,所以有必要先讲一下高斯模糊是什么:
对于一个图像而言,如果某个像素点跟一个卷积核进行卷积,如下图的,卷积核的尺寸为3x3,且中心点为1,其余为0,则卷积的前后图像是一样的。原因是当前像素点的值,只跟这一点本身有关(且权重为1),跟周边点无关,所以卷积前后都是一样的。
那么如果卷积核不是这样的呢?是符合高斯分布的呢?
高斯函数我们都看过,就是呈现中间高,四周低的形状(如下图):
在二维的情况下(即图像),二维高斯函数公式如下:
其中σ(sigma)是方差,σ越小高斯函数的峰(中间部分)就越高,σ越大,则峰就越平滑,图像卷积效果也越模糊,更平滑。
所以高斯模糊就是卷积核中的权重跟高斯函数一样,中间高,向四周逐渐趋于平缓。那这样子造成的一个效果就是,当前像素点的值跟四周的值有关系,且越近的点对当前点的贡献就越大,越远的点则贡献越小。所以会起到一个模糊的作用。
高斯模糊代码:
import cv2
import numpy as np
img = cv2.imread('D://fangzi.jpg')
cv2.imshow('img',img)
cv2.resizeWindow('img',640,480)
#img_ = cv2.GaussianBlur(img,ksize=(9,9),sigmaX=0,sigmaY=0)
img_ = cv2.GaussianBlur(img,(9,9),2)
cv2.imshow('img_',img_)
cv2.resizeWindow('img_',640,480)
cv2.waitKey()
效果:
我们知道高斯模糊后,就开始看看DOG算子了。
DOG是用于角点检测(也叫特征点提取)的。主要流程如下图:
左边是原图和三种不同σ的高斯模糊后的图。右边是对高斯滤波后的图片(相邻状态下)依次进行两两相减可得到右边的三个高斯函数的差分图(简称DOG)。
红色标记为当前像素点,黄色对应的像素点表示当前像素点邻接的点,共26(上图中27个黄点减去一个红点)个,如果该点(红点)是所有邻接像素点(黄点)的最大值或最小值,则红色标记对应的点为特征点。
DOG代码:
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat ori_img = imread("D://lena.png");
Mat gray_img;
cvtColor(ori_img, gray_img, CV_RGB2GRAY);
imshow("gray", gray_img);
gray_img.convertTo(gray_img, CV_32F);// float -像素是在0-1.0之间的任意值,这对于一些数据集的计算很有用,但是它必须通过将每个像素乘以255来转换成8位来保存或显示。
Mat gauss1, gauss2;
GaussianBlur(gray_img, gauss1, Size(5, 5), 0.3, 0.3);
GaussianBlur(gray_img, gauss2, Size(5, 5), 0.4, 0.4);
Mat DoG1, DoG2, DoG3;
DoG1 = gauss1 - gauss2;
imshow("DOG1", DoG1);
GaussianBlur(gray_img, gauss1, Size(5, 5), 0.6, 0.6);
GaussianBlur(gray_img, gauss2, Size(5, 5), 0.7, 0.7);
DoG2 = gauss1 - gauss2;
imshow("DOG2", DoG2);
GaussianBlur(gray_img, gauss1, Size(5, 5), 0.7, 0.7);
GaussianBlur(gray_img, gauss2, Size(5, 5), 0.8, 0.8);
DoG3 = gauss1 - gauss2;
imshow("DOG3", DoG3);
for (int j = 1; j < gray_img.rows - 1; j++)
{
for (int i = 1; i < gray_img.cols - 1; i++)
{
if (DoG2.at(j, i) < DoG2.at(j - 1, i - 1) && DoG2.at(j, i) < DoG2.at(j - 1, i) &&
DoG2.at(j, i) < DoG2.at(j - 1, i + 1) && DoG2.at(j, i) < DoG2.at(j, i - 1) && DoG2.at(j, i) < DoG2.at(j, i + 1) &&
DoG2.at(j, i) < DoG2.at(j + 1, i - 1) && DoG2.at(j, i) < DoG2.at(j + 1, i) && DoG2.at(j, i) < DoG2.at(j + 1, i + 1)
&& DoG2.at(j, i) < DoG1.at(j, i) && DoG2.at(j, i) < DoG1.at(j - 1, i - 1) && DoG2.at(j, i) < DoG1.at(j - 1, i) &&
DoG2.at(j, i) < DoG1.at(j - 1, i + 1) && DoG2.at(j, i) < DoG1.at(j, i - 1) && DoG2.at(j, i) < DoG1.at(j, i + 1) &&
DoG2.at(j, i) < DoG1.at(j + 1, i - 1) && DoG2.at(j, i) < DoG1.at(j + 1, i) && DoG2.at(j, i) < DoG1.at(j + 1, i + 1)
&& DoG2.at(j, i) < DoG3.at(j, i) && DoG2.at(j, i) < DoG3.at(j - 1, i - 1) && DoG2.at(j, i) < DoG3.at(j - 1, i) &&
DoG2.at(j, i) < DoG3.at(j - 1, i + 1) && DoG2.at(j, i) < DoG3.at(j, i - 1) && DoG2.at(j, i) < DoG3.at(j, i + 1) &&
DoG2.at(j, i) < DoG3.at(j + 1, i - 1) && DoG2.at(j, i) < DoG3.at(j + 1, i) && DoG2.at(j, i) < DoG3.at(j + 1, i + 1))
{
//cout << DoG2.at(j, i);
if (DoG2.at(j, i) < -3)
{
circle(ori_img, Point(i, j), 3, CV_RGB(0, 0, 255));
}
}
else
if (DoG2.at(j, i) > DoG2.at(j - 1, i - 1) && DoG2.at(j, i) > DoG2.at(j - 1, i) &&
DoG2.at(j, i) > DoG2.at(j - 1, i + 1) && DoG2.at(j, i) > DoG2.at(j, i - 1) && DoG2.at(j, i) > DoG2.at(j, i + 1) &&
DoG2.at(j, i) > DoG2.at(j + 1, i - 1) && DoG2.at(j, i) > DoG2.at(j + 1, i) && DoG2.at(j, i) > DoG2.at(j + 1, i + 1)
&& DoG2.at(j, i) > DoG1.at(j, i) && DoG2.at(j, i) > DoG1.at(j - 1, i - 1) && DoG2.at(j, i) > DoG1.at(j - 1, i) &&
DoG2.at(j, i) > DoG1.at(j - 1, i + 1) && DoG2.at(j, i) > DoG1.at(j, i - 1) && DoG2.at(j, i) > DoG1.at(j, i + 1) &&
DoG2.at(j, i) > DoG1.at(j + 1, i - 1) && DoG2.at(j, i) > DoG1.at(j + 1, i) && DoG2.at(j, i) > DoG1.at(j + 1, i + 1)
&& DoG2.at(j, i) > DoG3.at(j, i) && DoG2.at(j, i) > DoG3.at(j - 1, i - 1) && DoG2.at(j, i) > DoG3.at(j - 1, i) &&
DoG2.at(j, i) > DoG3.at(j - 1, i + 1) && DoG2.at(j, i) > DoG3.at(j, i - 1) && DoG2.at(j, i) > DoG3.at(j, i + 1) &&
DoG2.at(j, i) > DoG3.at(j + 1, i - 1) && DoG2.at(j, i) > DoG3.at(j + 1, i) && DoG2.at(j, i) > DoG3.at(j + 1, i + 1))
{
if (DoG2.at(j, i) > 3)
{
circle(ori_img, Point(i, j), 3, CV_RGB(255, 0, 0));
}
}
}
}
imshow("result", ori_img);
waitKey(0);
效果:
输入的灰度图:
dog1:
dog2:
dog3:
result: