[传统图像处理]-------DOG算子(高斯差分算子)和高斯模糊

一,DOG算子的作用:

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是用于角点检测(也叫特征点提取)的。主要流程如下图:

左边是原图和三种不同σ的高斯模糊后的图。右边是对高斯滤波后的图片(相邻状态下)依次进行两两相减可得到右边的三个高斯函数的差分图(简称DOG)。

红色标记为当前像素点,黄色对应的像素点表示当前像素点邻接的点,共26(上图中27个黄点减去一个红点)个,如果该点(红点)是所有邻接像素点(黄点)的最大值或最小值,则红色标记对应的点为特征点。

DOG代码:

#include <opencv2/opencv.hpp>
#include <iostream>

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<float>(j, i) < DoG2.at<float>(j - 1, i - 1) && DoG2.at<float>(j, i) < DoG2.at<float>(j - 1, i) &&
				DoG2.at<float>(j, i) < DoG2.at<float>(j - 1, i + 1) && DoG2.at<float>(j, i) < DoG2.at<float>(j, i - 1) && DoG2.at<float>(j, i) < DoG2.at<float>(j, i + 1) &&
				DoG2.at<float>(j, i) < DoG2.at<float>(j + 1, i - 1) && DoG2.at<float>(j, i) < DoG2.at<float>(j + 1, i) && DoG2.at<float>(j, i) < DoG2.at<float>(j + 1, i + 1)
				&& DoG2.at<float>(j, i) < DoG1.at<float>(j, i) && DoG2.at<float>(j, i) < DoG1.at<float>(j - 1, i - 1) && DoG2.at<float>(j, i) < DoG1.at<float>(j - 1, i) &&
				DoG2.at<float>(j, i) < DoG1.at<float>(j - 1, i + 1) && DoG2.at<float>(j, i) < DoG1.at<float>(j, i - 1) && DoG2.at<float>(j, i) < DoG1.at<float>(j, i + 1) &&
				DoG2.at<float>(j, i) < DoG1.at<float>(j + 1, i - 1) && DoG2.at<float>(j, i) < DoG1.at<float>(j + 1, i) && DoG2.at<float>(j, i) < DoG1.at<float>(j + 1, i + 1)
				&& DoG2.at<float>(j, i) < DoG3.at<float>(j, i) && DoG2.at<float>(j, i) < DoG3.at<float>(j - 1, i - 1) && DoG2.at<float>(j, i) < DoG3.at<float>(j - 1, i) &&
				DoG2.at<float>(j, i) < DoG3.at<float>(j - 1, i + 1) && DoG2.at<float>(j, i) < DoG3.at<float>(j, i - 1) && DoG2.at<float>(j, i) < DoG3.at<float>(j, i + 1) &&
				DoG2.at<float>(j, i) < DoG3.at<float>(j + 1, i - 1) && DoG2.at<float>(j, i) < DoG3.at<float>(j + 1, i) && DoG2.at<float>(j, i) < DoG3.at<float>(j + 1, i + 1))
			{
				//cout << DoG2.at<float>(j, i);
				if (DoG2.at<float>(j, i) < -3)
				{
					circle(ori_img, Point(i, j), 3, CV_RGB(0, 0, 255));
				}
			}
			else
				if (DoG2.at<float>(j, i) > DoG2.at<float>(j - 1, i - 1) && DoG2.at<float>(j, i) > DoG2.at<float>(j - 1, i) &&
					DoG2.at<float>(j, i) > DoG2.at<float>(j - 1, i + 1) && DoG2.at<float>(j, i) > DoG2.at<float>(j, i - 1) && DoG2.at<float>(j, i) > DoG2.at<float>(j, i + 1) &&
					DoG2.at<float>(j, i) > DoG2.at<float>(j + 1, i - 1) && DoG2.at<float>(j, i) > DoG2.at<float>(j + 1, i) && DoG2.at<float>(j, i) > DoG2.at<float>(j + 1, i + 1)
					&& DoG2.at<float>(j, i) > DoG1.at<float>(j, i) && DoG2.at<float>(j, i) > DoG1.at<float>(j - 1, i - 1) && DoG2.at<float>(j, i) > DoG1.at<float>(j - 1, i) &&
					DoG2.at<float>(j, i) > DoG1.at<float>(j - 1, i + 1) && DoG2.at<float>(j, i) > DoG1.at<float>(j, i - 1) && DoG2.at<float>(j, i) > DoG1.at<float>(j, i + 1) &&
					DoG2.at<float>(j, i) > DoG1.at<float>(j + 1, i - 1) && DoG2.at<float>(j, i) > DoG1.at<float>(j + 1, i) && DoG2.at<float>(j, i) > DoG1.at<float>(j + 1, i + 1)
					&& DoG2.at<float>(j, i) > DoG3.at<float>(j, i) && DoG2.at<float>(j, i) > DoG3.at<float>(j - 1, i - 1) && DoG2.at<float>(j, i) > DoG3.at<float>(j - 1, i) &&
					DoG2.at<float>(j, i) > DoG3.at<float>(j - 1, i + 1) && DoG2.at<float>(j, i) > DoG3.at<float>(j, i - 1) && DoG2.at<float>(j, i) > DoG3.at<float>(j, i + 1) &&
					DoG2.at<float>(j, i) > DoG3.at<float>(j + 1, i - 1) && DoG2.at<float>(j, i) > DoG3.at<float>(j + 1, i) && DoG2.at<float>(j, i) > DoG3.at<float>(j + 1, i + 1))
				{
					if (DoG2.at<float>(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:

  • 14
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
高斯差分算子(Difference of Gaussian,DoG)是一种常用的边缘检测算法。它是通过对图像进行高斯滤波后,计算不同尺度下的高斯滤波结果之间的差异来实现的。具体步骤如下: 1. 对原始图像进行高斯滤波,得到不同尺度下的高斯模糊图像; 2. 计算相邻两个尺度下的高斯模糊图像之差,得到一组差分图像; 3. 对每个差分图像进行非极大值抑制,得到一组非极大值抑制图像; 4. 对所有非极大值抑制图像进行二值化处理,得到一组二值化图像; 5. 将所有二值化图像进行叠加,得到最终的边缘检测结果。 以下是Python实现高斯差分边缘检测算子的代码: ```python import cv2 import numpy as np # 读取图像并加上高斯噪声 img = cv2.imread('lena.jpg', 0) img = cv2.GaussianBlur(img, (5, 5), 0) img = img + np.random.normal(0, 25, img.shape) # 定义高斯差分函数 def DoG(img, ksize, sigma1, sigma2): g1 = cv2.GaussianBlur(img, ksize, sigma1) g2 = cv2.GaussianBlur(img, ksize, sigma2) return g1 - g2 # 计算高斯差分图像 dog1 = DoG(img, (5, 5), 1, 2) dog2 = DoG(img, (5, 5), 2, 4) dog3 = DoG(img, (5, 5), 4, 8) # 非极大值抑制 def non_max_suppression(img): h, w = img.shape out = np.zeros((h, w), dtype=np.float32) for y in range(1, h-1): for x in range(1, w-1): dx = img[y, x+1] - img[y, x-1] dy = img[y+1, x] - img[y-1, x] gradient = np.sqrt(dx**2 + dy**2) if gradient == 0: out[y, x] = 0 else: angle = np.rad2deg(np.arctan(dy/dx)) if angle < 0: angle += 180 if (angle <= 22.5) or (angle > 157.5): if (img[y, x] >= img[y, x+1]) and (img[y, x] >= img[y, x-1]): out[y, x] = img[y, x] elif (22.5 < angle <= 67.5): if (img[y, x] >= img[y-1, x+1]) and (img[y, x] >= img[y+1, x-1]): out[y, x] = img[y, x] elif (67.5 < angle <= 112.5): if (img[y, x] >= img[y-1, x]) and (img[y, x] >= img[y+1, x]): out[y, x] = img[y, x] else: if (img[y, x] >= img[y-1, x-1]) and (img[y, x] >= img[y+1, x+1]): out[y, x] = img[y, x] return out # 非极大值抑制图像 nms1 = non_max_suppression(dog1) nms2 = non_max_suppression(dog2) nms3 = non_max_suppression(dog3) # 二值化处理 th1 = cv2.threshold(nms1, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1] th2 = cv2.threshold(nms2, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1] th3 = cv2.threshold(nms3, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1] # 叠加所有二值化图像 result = th1 + th2 + th3 # 显示结果 cv2.imshow('result', result) cv2.waitKey(0) cv2.destroyAllWindows() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值