目录
一、二阶算子简介
二、laplace(拉普拉斯算子)
1、什么是拉普拉斯算子
(1)连续二维函数的二阶导
(2)离散二维函数的二阶导数
2、常用算子模块及代码
3、结果
三、log算子
1、什么是log算子
2、计算流程
3、log算子模板
4、代码
5、结果
四、dog算子
1、什么是dog算子
2、计算流程
(1)灰度化图像
(2)计算方差为2和3.2的两个高斯滤波后的图像
(3)求两个之差——将二者之差再除以2(归一化)
3、代码
4、代码
五、各种算子的比较(一阶和二阶)
一阶算子可见:《【图像处理】——Python图像分割边缘检测算法之一阶梯度算子(Roberts、Prewitt、Sobel、 Kirsch、Canny算子)》
基于二 阶微分的边缘检测算子是通过计算图像二阶导数的零交叉点来测图像的边缘,LOG(高斯拉普拉斯)算子是最常用的二阶微分算子。
如果对像素值求二阶导数,会发现边缘处的导数值为0
拉普拉斯算子是n维欧几里德空间中的一个二阶微分算子,定义为梯度(▽f)的散度(▽·f)。拉普拉斯算子也是最简单的各向同性微分算子,具有旋转不变性,即将原图像旋转后进行滤波处理给出的结果与先对图像滤波然后再旋转的结果相同。一个二维图像的拉普拉斯算子定义为:
推导过程如下:
import numpy as np
import matplotlib.pyplot as plt
import cv2
def sys_laplace(img):
'''
调用系统函数进行图像的边缘二阶算子laplace检测
:param img: 待测图像
:return: 返回的是边缘图像矩阵
'''
gray = cv2.imread(img,0)#读取图片为灰色
edeg_img = cv2.Laplacian(gray,cv2.CV_16S,ksize=3)#将原始图片进行边缘检测,边缘图像放在16位中防止溢出,使用的卷积核是3
edge_img = cv2.convertScaleAbs(edeg_img)#转回8位图像,brief Scales, calculates absolute values, and converts the result to 8-bit
return edge_img
def def_laplace4(img):
'''
自定义二阶算子边缘检测4邻域laplace
:param img:待测图像
:return: 返回4邻域边缘检测的图像矩阵
'''
gray_img = cv2.imread(img,0)
w,h = gray_img.shape
# 在灰度图像的四周填充一行/一列0,卷积核为3x3,要想对原始图像的每一个像素进行卷积则需要进行填充
ori_pad = np.pad(gray_img,((1,1),(1,1)),'constant')
#定义两个不同的laplace算子
#不同的算子涉及到的邻域像素点的个数也不一样
lap4_filter = np.array([[0,1,0],[1,-4,1],[0,1,0]]) #4邻域laplacian算子
#4邻域
edge4_img = np.zeros((w,h))
for i in range(w-2):
for j in range(h-2):
edge4_img[i,j]=np.sum(ori_pad[i:i+3,j:j+3]*lap4_filter)#进行卷积
if edge4_img[i,j] < 0:
edge4_img[i,j] = 0 #把所有负值修剪为0
edge4_img = cv2.convertScaleAbs(edge4_img)#将图像变成8位的图像,其实就是一个映射关系,类似于均衡化中的映射关系
return edge4_img
def def_laplace8(img):
'''
自定义二阶算子边缘检测8邻域laplace
:param img:待测图像
:return: 返回8邻域边缘检测的图像矩阵
'''
gray_img = cv2.imread(img, 0)
w, h = gray_img.shape
# 在灰度图像的四周填充一行/一列0,卷积核为3x3,要想对原始图像的每一个像素进行卷积则需要进行填充
ori_pad = np.pad(gray_img, ((1, 1), (1, 1)), 'constant')
# 定义两个不同的laplace算子
# 不同的算子涉及到的邻域像素点的个数也不一样
lap8_filter = np.array([[0, 1, 0], [1, -8, 1], [0, 1, 0]]) # 8邻域laplacian算子
# 8邻域
edge8_img = np.zeros((w, h))
for i in range(w - 2):
for j in range(h - 2):
edge8_img[i, j] = np.sum(ori_pad[i:i + 3, j:j + 3] * lap8_filter) # 进行卷积
if edge8_img[i, j] < 0:
edge8_img[i, j] = 0
edge8_img = cv2.convertScaleAbs(edge8_img)
return edge8_img
if __name__ == '__main__':
img = 'colorful_lena.jpg'
sys_img = sys_laplace(img)
edge4_img = def_laplace4(img)
edge8_img = def_laplace8(img)
cv2.imshow('sys',sys_img)
cv2.imshow('def3',edge4_img)
cv2.imshow('def4',edge8_img)
cv2.waitKey(0)
拉普拉斯边缘检测算子没有对图像做平滑处理,所以对噪声很敏感。因此可以想到先对图像进行高斯平滑处理,然后再与Laplacian算子进行卷积。这就是高斯拉普拉斯算子(laplacian of gaussian)。
from skimage import data,color,filters
import matplotlib.pyplot as plt
import numpy as np
import cv2
from cv2 import GaussianBlur
def sys_log(img):
'''
系统自带函数
:param img: 待测图像
:return: 返回边缘图像矩阵
'''
gray_img = cv2.imread(img,0)#读取图片为灰色
g_img = cv2.GaussianBlur(gray_img,(3,3),sigmaX=0)#以核大小为3x3,方差为0的高斯函数进行高斯滤波
system_edge_img=cv2.Laplacian(g_img,cv2.CV_16S,ksize=3)#laplace检测
system_edge_img = cv2.convertScaleAbs(system_edge_img)#转为8位
return system_edge_img
def def_log(img):
#第一步灰度化
gray_img = cv2.imread(img,0)
#第二步高斯滤波
#高斯算子
g_filter=np.array([[0,0,1,0,0],
[0,1,2,1,0],
[1,2,16,2,1],
[0,1,2,1,0],
[0,0,1,0,0]])
self_g_img=np.pad(gray_img,((2,2),(2,2)),'constant')#扩展操作
#以下进行的其实就是滤波操作
w,h=self_g_img.shape
for i in range(w-4):
for j in range(h-4):
self_g_img[i][j]=np.sum(self_g_img[i:i+5,j:j+5]*g_filter)
# 第三步:计算laplace二阶导数,操作和laplace算子一样
lap4_filter = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]]) # 4邻域laplacian算子
g_pad=np.pad(self_g_img,((1,1),(1,1)),'constant')
# 4邻域
edge4_img = np.zeros((w, h))
for i in range(w - 2):
for j in range(h - 2):
edge4_img[i, j] = np.sum(g_pad[i:i + 3, j:j + 3] * lap4_filter)
if edge4_img[i, j] < 0:
edge4_img[i, j] = 0 # 把所有负值修剪为0
lap8_filter = np.array([[0, 1, 0], [1, -8, 1], [0, 1, 0]]) # 8邻域laplacian算子
# 8邻域
g_pad = np.pad(self_g_img, ((1, 1), (1, 1)), 'constant')
edge8_img = np.zeros((w, h))
for i in range(1,w - 1):
for j in range(1,h - 1):
edge8_img[i, j] = np.sum(g_pad[i-1:i + 2, j-1:j + 2] * lap8_filter)
if edge8_img[i, j] < 0:
edge8_img[i, j] = 0
return [edge4_img,edge8_img]
if __name__ == '__main__':
img = 'test1.png'
edge_img = sys_log(img)
edge4_img,edge8_img = def_log(img)
cv2.imshow('',edge4_img)
cv2.waitKey(0)
考虑到灰度变化取决于数值范围的事实,有时所用的过程是使用各种σσ值来对一幅图像进行滤波。然后,所得零交叉边缘图与仅为全部图形保留的公共边缘相结合。这种方法可得到很有用的信息,但由于其复杂性,实践中它多被用做使用单一滤波器选择合适的σσ值的设计工具。
Marr and Hildreth[1980]指出过,使用高斯差分(DoG)来近似LoG滤波器是可能的:
最后得到的结果即为dog算子边缘检测的图像
from skimage import data,color,filters
import numpy as np
import matplotlib.pyplot as plt
import cv2
gray_img = cv2.imread('test1.png',0)
#先对图像进行两次高斯滤波运算
gimg1=filters.gaussian(gray_img,sigma=2)
gimg2=filters.gaussian(gray_img,sigma=1.6*2)
#两个高斯运算的差分
dimg=gimg2-gimg1
#将差归一化
dimg/=2
cv2.imshow('',dimg)
cv2.waitKey(0)
figure=plt.figure()
plt.subplot(141).set_title('original_img1')
plt.imshow(gray_img)
plt.subplot(142).set_title('LoG_img1')
plt.imshow(gimg1)
plt.subplot(143).set_title('LoG_img2')
plt.imshow(gimg2)
plt.subplot(144).set_title('DoG_edge')
plt.imshow(dimg,cmap='gray')
plt.show()
from skimage import data,color,filters
import numpy as np
import matplotlib.pyplot as plt
import cv2
gray_img = cv2.imread('test1.png',0)
#先对图像进行两次高斯滤波运算
gimg1=filters.gaussian(gray_img,sigma=2)
gimg2=filters.gaussian(gray_img,sigma=1.6*2)
#两个高斯运算的差分
dimg=gimg2-gimg1
#将差归一化
dimg/=2
cv2.imshow('',dimg)
cv2.waitKey(0)
figure=plt.figure()
plt.subplot(141).set_title('original_img1')
plt.imshow(gray_img)
plt.subplot(142).set_title('LoG_img1')
plt.imshow(gimg1)
plt.subplot(143).set_title('LoG_img2')
plt.imshow(gimg2)
plt.subplot(144).set_title('DoG_edge')
plt.imshow(dimg,cmap='gray')
plt.show()
from skimage import data,color,filters
import numpy as np
import matplotlib.pyplot as plt
import cv2
gray_img = cv2.imread('test1.png',0)
#先对图像进行两次高斯滤波运算
gimg1=filters.gaussian(gray_img,sigma=2)
gimg2=filters.gaussian(gray_img,sigma=1.6*2)
#两个高斯运算的差分
dimg=gimg2-gimg1
#将差归一化
dimg/=2
cv2.imshow('',dimg)
cv2.waitKey(0)
figure=plt.figure()
plt.subplot(141).set_title('original_img1')
plt.imshow(gray_img)
plt.subplot(142).set_title('LoG_img1')
plt.imshow(gimg1)
plt.subplot(143).set_title('LoG_img2')
plt.imshow(gimg2)
plt.subplot(144).set_title('DoG_edge')
plt.imshow(dimg,cmap='gray')
plt.show()