《OpenCv视觉之眼》Python图像处理十三 :Opencv图像轮廓提取之基于二阶导数的Laplacian算法和LOG算法

本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的、不同方法的处理,以达到对图像进行去噪、锐化等一系列的操作。同时,希望观看本专栏的小伙伴可以理解到OpenCv进行图像处理的强大哦,如有转载,请注明出处(原文链接和作者署名),感谢各位小伙伴啦!

前文参考:
《OpenCv视觉之眼》Python图像处理一 :Opencv-python的简介及Python环境搭建
《OpenCv视觉之眼》Python图像处理二 :Opencv图像读取、显示、保存基本函数原型及使用
《OpenCv视觉之眼》Python图像处理三 :Opencv图像属性、ROI区域获取及通道处理
《OpenCv视觉之眼》Python图像处理四 :Opencv图像灰度处理的四种方法及原理
《OpenCv视觉之眼》Python图像处理五 :Opencv图像去噪处理之均值滤波、方框滤波、中值滤波和高斯滤波
《OpenCv视觉之眼》Python图像处理六 :Opencv图像傅里叶变换和傅里叶逆变换原理及实现
《OpenCv视觉之眼》Python图像处理七 :Opencv图像处理之高通滤波和低通滤波原理及构造
《OpenCv视觉之眼》Python图像处理八 :Opencv图像处理之图像阈值化处理原理及函数
《OpenCv视觉之眼》Python图像处理九 :Opencv图像形态学处理之图像腐蚀与膨胀原理及方法
《OpenCv视觉之眼》Python图像处理十 :Opencv图像形态学处理之开运算、闭运算和梯度运算原理及方法
《OpenCv视觉之眼》Python图像处理十一 :Opencv图像形态学处理之顶帽运算与黑帽运算
《OpenCv视觉之眼》Python图像处理十二 :Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法

上次博客我们讲解了图像轮廓提取一阶导数算法Roberts算法、Prewitt算法及Sobel算法,这三种算法需要重点掌握得是Sobel算法,在日常的图像处理中Sobel算法用得较多,在图像轮廓提取中,除了一阶导算法外,还存在二阶导算法

本次博客我们将进行二阶导的Laplacian算法,以及基于Laplacian算法的LOG算法,通过原理编写Laplacian算法的功能函数,并介绍OpenCV中库函数的使用,一起学习吧!

一、Laplacian算法

1、Laplacian算法原理

1)、Laplacian算法简介
拉普拉斯(Laplacian)算子是n维欧几里德空间中的一个二阶微分算子,常用于图像增强领域和边缘提取。它通过灰度差分计算邻域内的像素,基本流程是:判断图像中心像素灰度值与它周围其他像素的灰度值,如果中心像素的灰度更高,则提升中心像素的灰度;反之降低中心像素的灰度,从而实现图像锐化操作。
2)、Laplacian算法优缺点

  • 优点: Laplacian算子是各向同性的,能对任何走向的界线和线条进行锐化,无方向性。这是拉普拉斯算子区别于其他算法的最大优点
  • 缺点:Laplacian 算子对噪声比较敏感,图像如果不去除噪声,提取的轮廓效果将会非常糟糕

3)、Laplacian算法原理
Laplacian算法通过对邻域中心像素的四方向或八方向求梯度,再将梯度相加起来判断中心像素灰度与邻域内其他像素灰度的关系,最后通过梯度运算的结果对像素灰度进行调整。

Laplacian算法分为四邻域和八邻域,四邻域是对邻域中心像素的四方向求梯度,八邻域是对八方向求梯度,然后分别将各个梯度的值进行相加,4邻域个八邻域模板如下所示:
4 = [ 0 1 0 1 4 1 0 1 0 ] , 8 = [ 1 1 1 1 8 1 1 1 1 ] 4邻域=\begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\0 & 1 & 0 \end{bmatrix} , 8邻域=\begin{bmatrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\1 & 1 & 1 \end{bmatrix}

4)、Laplacian算法原理公式
四领域原理:
d x = ( i m g [ i + 1 , j ] i m g [ i , j ] ) ( i m g [ i , j ] i m g [ i 1 , j ] ) d y = ( i m g [ i , j + 1 ] i m g [ i , j ] ) ( i m g [ i , j ] i m g [ i , j 1 ] ) d x d y L a p l a c i a n [ i , j ] = d x + d y dx=(img[i+1,j]-img[i,j])-(img[i,j]-img[i-1,j])\\\\ dy=(img[i,j+1]-img[i,j])-(img[i,j]-img[i,j-1])\\\\ d_x、d_y分别表示图像水平方向和竖直方向的计算出的像素梯度值\\\\ 图像轮廓Laplacian[i,j]=dx+dy
八邻域原理:
d x = ( i m g [ i + 1 , j ] i m g [ i , j ] ) ( i m g [ i , j ] i m g [ i 1 , j ] ) d y = ( i m g [ i , j + 1 ] i m g [ i , j ] ) ( i m g [ i , j ] i m g [ i , j 1 ] ) d b e v e l = ( i m g [ i + 1 , j + 1 ] i m g [ i , j ] ) ( i m g [ i , j ] i m g [ i 1 , j 1 ] ) d b e v e l 2 = ( i m g [ i 1 , j + 1 ] i m g [ i , j ] ) ( i m g [ i , j ] i m g [ i + 1 , j 1 ] ) d x d y d b e v e l d b e v e l 2 线 线 L a p l a c i a n [ i , j ] = d x + d y + d b e v e l + d b e v e l 2 dx=(img[i+1,j]-img[i,j])-(img[i,j]-img[i-1,j])\\\\ dy=(img[i,j+1]-img[i,j])-(img[i,j]-img[i,j-1])\\\\ dbevel=(img[i+1,j+1]-img[i,j])-(img[i,j]-img[i-1,j-1])\\\\ dbevel2=(img[i-1,j+1]-img[i,j])-(img[i,j]-img[i+1,j-1])\\\\ d_x、d_y、dbevel、dbevel2分别表示图像水平方向、竖直方向、正对角线、斜对角线上计算出的像素梯度值\\\\ 图像轮廓Laplacian[i,j]=dx+dy+dbevel+dbevel2
通过以上的计算公式,我们就可以进行Laplacian算法功能函数的构造

2、Laplacian算法功能函数构造

1)、Laplacian算法功能函数构造

'''
Laplacian二阶导数轮廓提取算法
'''
#通过原理,编写对应的Roberts图像轮廓提取算法
def Laplacian(thresh1,Neighborhood):#Neighborhood表示领域参数,0表示4邻域,1表示8邻域
    #获取图像属性
    h,w=thresh1.shape[0:2]
    #定义空白图像,用于存放Laplacian算法提取出来的轮廓图
    Laplacian=np.zeros((h,w),dtype=thresh1.dtype)
    #对阈值化图像进行遍历,进行Laplacian算法
    for i in range(h-1):
        for j in range(w-1):
            if Neighborhood==0:#表示4邻域
                dx=(int(thresh1[i+1,j])-int(thresh1[i,j]))-(int(thresh1[i,j])-int(thresh1[i-1,j]))#x方向梯度
                dy=(int(thresh1[i,j+1])-int(thresh1[i,j]))-(int(thresh1[i,j])-int(thresh1[i,j-1]))#y方向梯度
                Laplacian[i,j]=dx+dy
            else: #八邻域
                dx=(int(thresh1[i+1,j])-int(thresh1[i,j]))-(int(thresh1[i,j])-int(thresh1[i-1,j]))#x方向梯度
                dy=(int(thresh1[i,j+1])-int(thresh1[i,j]))-(int(thresh1[i,j])-int(thresh1[i,j-1]))#y方向梯度
                dbevel=(int(thresh1[i+1,j+1])-int(thresh1[i,j]))-(int(thresh1[i,j])-int(thresh1[i-1,j-1]))#正对角线梯度
                dbevel2=(int(thresh1[i-1,j+1])-int(thresh1[i,j]))-(int(thresh1[i,j])-int(thresh1[i+1,j-1]))#反对角线梯度
                Laplacian[i,j]=dx+dy+dbevel+dbevel2
    return Laplacian

2)、读取图像进行处理,然后调用Laplacian算法进行轮廓提取,观察4邻域和8邻域的图像

import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#图像阈值化处理
ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY)  #二进制阈值化
#调用Laplacian4邻域算法函数进行图像轮廓提取
result=Laplacian(thresh1,0)
#调用Laplacian8邻域算法函数进行图像轮廓提取
result1=Laplacian(thresh1,1)
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
result=cv2.cvtColor(result,cv2.COLOR_BGR2RGB)
result1=cv2.cvtColor(result1,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'Laplacian4邻域算法','Laplacian算法']  #标题
images = [img, result,result1]   #图像对比显示
for i in range(3):
    plt.subplot(1,3,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

在这里插入图片描述

我们可以看出,对于相同图像通过相同预处理,4邻域算法与8邻域算法得出的图像是不一样的,明显的,8领域算法得到的图像更加明显,也就是图像锐化效果更好,这是由于计算梯度多的原因,4邻域算法从四个方向梯度对图像进行计算,而8邻域算法从八个方向梯度对图像进行计算,由此显得图像明亮一些。

3、OpenCV中Laplacian算法使用方法

OpenCV官方将Laplacian算法封装到cv2.Laplacian()函数中,如下介绍
1)、函数原型:result=cv2.Laplacian(img, ddepth,ksize)

  • img:需要进行Laplacian算法的图像
  • ddepth:目标图像深度
  • ksize:二阶导数的滤波器的孔径大小,其值必须是正数和奇数,且默认值为1(4邻域模板)

2)、Laplacian算法库函数使用

'''
Laplacian轮廓提取算法-OpenCV库函数的使用方法
'''
import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#图像阈值化处理
ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY)  #二进制阈值化
#调用Laplacian算法的OpenCV库函数进行图像轮廓提取
result = cv2.Laplacian(thresh1,cv2.CV_16S,ksize=1)
#在进行Laplacian算子处理之后,还需要调用convertScaleAbs()函数计算绝对值,并将图像转换为8位图进行显示。
Laplacian = cv2.convertScaleAbs(result)
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
Laplacian=cv2.cvtColor(Laplacian,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'Laplacian算法']  #标题
images = [img, Laplacian]   #图像对比显示
for i in range(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

在这里插入图片描述
由于Laplacian算法对噪声非常敏感,因此,后面引入LOG算法对Laplacian算法进行增强,如下介绍

二、LOG算法

1、LOG算法原理

1)、LOG算法简介
LOG(Laplacian of Gaussian)边缘检测算子是David Courtnay Marr和Ellen Hildreth在1980年共同提出的,也称为Marr & Hildreth算子,它根据图像的信噪比来求检测边缘的最优滤波器。该算法首先对图像做高斯滤波,然后再求其拉普拉斯(Laplacian)二阶导数,根据二阶导数的过零点来检测图像的边界,即通过检测滤波结果的零交叉(Zero crossings)来获得图像或物体的边缘。常见的LOG算子是5*5模板,如下所示:
[ 2 4 4 4 2 4 0 8 0 4 4 8 24 8 4 4 0 8 0 4 2 4 4 4 2 ] \begin{bmatrix} -2 & -4 & -4 &-4&-2 \\ -4 & 0 & 8 &0&-4 \\ -4 & 8 & 24 &8&-4\\ -4 & 0 & 8 &0&-4\\ -2 & -4 & -4 &-4&-2\end{bmatrix}
2)、LOG算法优缺点

  • 优点:LOG算法该综合考虑了对噪声的抑制和对边缘的检测两个方面,并且把Gauss平滑滤波器和Laplacian锐化滤波器结合了起来,先平滑掉噪声,再进行边缘检测,所以效果会更好;具有抗干扰能力强,边界定位精度高,边缘连续性好,能有效提取对比度弱的边界等特点
  • 缺点:尽管抑制了噪声,但同时也损坏了部分低强度边缘

3)、LOG算法原理
LOG算法原理是建立在Laplacian算法原理之上的,额外再加了一个步骤,如下

  • 第一步:图像进行高斯平滑(去噪、模糊)处理
  • 第二步:将处理的图像通过Laplacian算法进行轮廓提取

以上两步,就为LOG算法的原理

2、LOG算法功能函数构造

1)、通过以上5x5模板对LOG算法进行构造,只构造常用的5x5模板哦,其他模板自行构造吧:

'''
LOG二阶导数轮廓提取5x5模板构造
'''
#通过原理,编写对应的Roberts图像轮廓提取算法
def LOG(thresh1):
    #获取图像属性
    h,w=thresh1.shape[0:2]
    #定义空白图像,用于存放LOG算法提取出来的轮廓图
    LOG=np.zeros((h,w),dtype=thresh1.dtype)
    a=np.array([[-2,-4,-4,-4,-2],[-4,0,8,0,-4],[-4,8,24,8,-4],[-4,0,8,0,-4],[-2,-4,-4,-4,-2]])#5x5LOG模板
    #对阈值化图像进行遍历,进行Laplacian算法
    for i in range(2,h-2):
        for j in range(2,w-2):#得到模板卷积第一个位置
            sum=np.sum(thresh1[i-2:i+2+1,j-2:j+2+1]*a) #原图像5x5邻域内与LOG模板进行卷积
            LOG[i,j]=sum
    return LOG

2)、读取图像,调用LOG 5x5模板函数进行LOG算法处理

import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#图像阈值化处理
ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY)  #二进制阈值化
#调用Laplacian4邻域算法函数进行图像轮廓提取
result=LOG(thresh1)
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
result=cv2.cvtColor(result,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'LOG算法']  #标题
images = [img, result]   #图像对比显示
for i in range(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

在这里插入图片描述
由于LOG算子到中心的距离与位置加权系数的关系曲线像墨西哥草帽的剖面,所以LOG算子也叫墨西哥草帽滤波器,如下图所示:
在这里插入图片描述

3、OpenCV中LOG算法使用方法

早OpenCV官网,对LOG算法并没有对于的库函数,而是通过对图像先进行高斯滤波降噪处理,然后通过Laplacian算法进行轮廓提取,通过这样一个算法来进行LOG算法的模拟,完整代码如下所示:
1)、LOG算法OpenCV函数伪实现

'''
LOG轮廓提取算法-OpenCV库函数的使用方法
'''
import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#调用Laplacian算法的OpenCV库函数进行图像轮廓提取
result = cv2.Laplacian(blur,cv2.CV_16S,ksize=1)
#在进行Laplacian算子处理之后,还需要调用convertScaleAbs()函数计算绝对值,并将图像转换为8位图进行显示。
LOG = cv2.convertScaleAbs(result)#得到LOG算法处理结果
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
Laplacian=cv2.cvtColor(Laplacian,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'LOG算法']  #标题
images = [img, Laplacian]   #图像对比显示
for i in range(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

在这里插入图片描述

以上就是本次博客的全部内容,遇到问题的小伙伴记得留言评论,学长看到会为大家进行解答的,这个学长不太冷!

如果放弃太早,你永远都不知道自己会错过什么。活着不是靠泪水搏取同情,而是靠汗水获得掌声。自卑是剪了双翼的飞鸟,难上青天,这两者都是成才的大忌

陈一月的又一天编程岁月^ _ ^

猜你喜欢

转载自blog.csdn.net/qq_42451251/article/details/107979032