1. DoG 算子
DoG(Difference of Gaussians)高斯差分是计算机视觉中一种用于图像增强和角点检测的算子。它是将两个不同尺度的高斯模糊图像进行差分得到的。
高斯模糊可以平滑图像中的噪声和细节,而差分可以突出图像中的边缘和角点。DoG 算子利用这两个特性,在保留图像边缘和角点的同时,去除噪声和细节。
DoG 在图像处理领域有着广泛的应用,例如:
-
图像增强
-
角点检测
-
边缘检测
-
图像分割
2. DoG 算子的推导
二维高斯函数的公式:
可写成
对 求导,则
而在该系列的上一篇文章中,我们得到 LoG 算子的公式:
所以,
根据极限,又可得:
当 k 1 时,
因此可以用 DoG 算子来近似 LoG 算子,DoG 算子和 LoG 算子在理论上是等价的。
DoG和LoG的对比.pngMarr 和 Hildreth 证明,如果两个高斯模糊图像的标准差比率为 1.6,那么 DoG 算子可以近似 LoG 算子。在实践中,DoG 算子通常比 LoG 算子更容易实现,而且计算速度更快。但是 LoG 算子的精确度更高,LoG 算子是使用一个特定的二维高斯函数来滤波图像,该函数可以准确地捕捉图像中的边缘和角点。
3. DoG 算子的实现
下面用高斯模糊和 absdiff() 函数变换来实现 DoG :
int main(int argc,char *argv[])
{
Mat src = imread(".../street.jpg");
imshow("src",src);
Mat gray;
cvtColor(src, gray, cv::COLOR_BGR2GRAY); // 灰度化
// 使用不同的 sigma ,实现不同尺度特征
Mat blurred1, blurred2;
double sigma1 = 1.6*2;
double sigma2 = 2;
GaussianBlur(gray, blurred1, Size(7,7), sigma1, sigma1);
GaussianBlur(gray, blurred2, Size(7,7), sigma2, sigma2);
// 通过差分计算 DoG 图像
Mat dst;
absdiff(blurred1, blurred2, dst);
normalize(dst, dst, 0, 255, NORM_MINMAX, CV_8UC1);
imshow("DoG", dst);
waitKey(0);
return 0;
}
GaussianBlur实现的DoG.png
在这里,使用 absdiff() 函数实现差分,就是将两幅图像作差。使用归一化函数 normalize() 的作用是将 DoG 响应的图像范围从其最小值和最大值映射到 0-255 的范围内。这样,可以方便地使用 OpenCV 库中的函数对图像进行可视化。
不使用 OpenCV 的 GaussianBlur() 函数,按照高斯函数的公式来实现一个 GaussianFilter()
// x,y 方向联合实现获取高斯模板
void generateGaussMask(Mat& mask, Size size, double sigma) {
mask.create(size, CV_64F);
int h = size.height;
int w = size.width;
int center_h = (h - 1) / 2;
int center_w = (w - 1) / 2;
double sum = 0.0;
double x, y;
for (int i = 0; i < h; ++i) {
y = pow(i - center_h, 2);
for (int j = 0; j < w; ++j) {
x = pow(j - center_w, 2);
//常数部分不计算,因为最后都要归一化
double g = exp(-(x + y) / (2 * sigma*sigma));
mask.at<double>(i, j) = g;
sum += g;
}
}
mask = mask / sum;
}
//按二维高斯函数实现高斯滤波
void GaussianFilter(Mat& src, Mat& dst, Mat window) {
int hh = (window.rows - 1) / 2;
int hw = (window.cols - 1) / 2;
dst = Mat::zeros(src.size(), src.type());
//边界填充
Mat newSrc;
copyMakeBorder(src, newSrc, hh, hh, hw, hw, BORDER_REPLICATE);//边界复制
//高斯滤波
for (int i = hh; i < src.rows + hh; ++i) {
for (int j = hw; j < src.cols + hw; ++j) {
double sum[3] = { 0 };
for (int r = -hh; r <= hh; ++r) {
for (int c = -hw; c <= hw; ++c) {
if (src.channels() == 1) {
sum[0] = sum[0] + newSrc.at<uchar>(i + r, j + c) * window.at<double>(r + hh, c + hw);
} else if (src.channels() == 3) {
Vec3b rgb = newSrc.at<Vec3b>(i + r, j + c);
sum[0] = sum[0] + rgb[0] * window.at<double>(r + hh, c + hw);//B
sum[1] = sum[1] + rgb[1] * window.at<double>(r + hh, c + hw);//G
sum[2] = sum[2] + rgb[2] * window.at<double>(r + hh, c + hw);//R
}
}
}
if (src.channels() == 1)
{
dst.at<uchar>(i - hh, j - hw) = static_cast<uchar>(sum[0]);
} else if (src.channels() == 3) {
Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
dst.at<Vec3b>(i - hh, j - hw) = rgb;
}
}
}
}
int main(int argc,char *argv[])
{
Mat src = imread(".../street.jpg");
imshow("src",src);
Mat gray;
cvtColor(src, gray, cv::COLOR_BGR2GRAY); // 灰度化
Mat mask1, mask2, blurred1, blurred2;
double sigma1 = 1.6*2;
double sigma2 = 2;
generateGaussMask(mask1, Size(7, 7), sigma1);
generateGaussMask(mask2, Size(7, 7), sigma2);
GaussianFilter(src, blurred1, mask1);
GaussianFilter(src, blurred2, mask2);
// 通过差分计算 DoG 图像
Mat dst;
absdiff(blurred1, blurred2, dst);
normalize(dst, dst, 0, 255, NORM_MINMAX, CV_8UC1);
imshow("DoG", dst);
waitKey(0);
return 0;
}
自定义GaussianFilter实现的DoG.png
4. 总结
DoG 算子在一定程度上可以替代 LoG 算子,DoG 算子是 LoG 算子的一种近似实现,而且具有计算速度快、对噪声敏感性低等优点。
DoG 算子在图像处理领域有广泛应用,例如图像角点检测、图像特征提取(例如 SIFT 算法、FAST 算法)等。
网友评论