5.2 空间域滤波之高通滤波(图像锐化)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

上一章我们介绍了空间域滤波的低通滤波,低通滤波主要用于图像的平滑处理、降噪等作用。这一章,我们介绍空间域滤波的高通滤波,即:图像的锐化


1. 理论基础

1.1 一阶导和二阶导的几何意义

  • 一阶导判断函数单调性
f ′ ( x ) > 0 f'(x)>0 f(x)>0 f ′ ( x ) < 0 f'(x)<0 f(x)<0
函数单调递增函数单调递减
  • 二阶导判断函数极值
f ′ ( x ) = 0 且 f ′ ′ ( x ) < 0 f'(x)=0且f''(x)<0 f(x)=0f′′(x)<0 f ′ ( x ) = 0 且 f ′ ′ ( x ) > 0 f'(x)=0且f''(x)>0 f(x)=0f′′(x)>0
函数开口向下, f ( x ) f(x) f(x) x = 0 x=0 x=0 处有极大值函数开口向上, f ( x ) f(x) f(x) x = 0 x=0 x=0 处有极小值
  • 二阶导判断函数凹凸性
在某区间 [ a , b ] [a,b] [a,b]内, f ′ ′ ( x ) < 0 f''(x)<0 f′′(x)<0在某区间 [ a , b ] [a,b] [a,b]内, f ′ ′ ( x ) > 0 f''(x)>0 f′′(x)>0
函数开口向下,在区间 [ a , b ] [a,b] [a,b]为凸函数函数开口向上,在区间 [ a , b ] [a,b] [a,b]为凹函数

简而言之:一阶微分(偏导) 反映灰度变化的快慢,而二阶微分(偏导)反映的是灰度变化曲线频率变化的剧烈程度(突变),很多时候仅有灰度的变化(一阶微分),但并不能证明此处出现了边缘或结构信息,而二阶微分恰恰弥补了这一缺陷

1.2 如何利用一阶导和二阶导的几何意义分析图像

在前面的知识讲解中,我们说到可以使用 f ( x , y ) f(x,y) f(x,y) 来表示图像,我们现在研究图像中的一条线(比如第一行像素),则我们可以用 f ( x ) f(x) f(x) 来表示这条线。根据导数的定义可得: 一阶导定义为差分: ∂ f ∂ x = f ( x + 1 ) − f ( x ) 二阶导定义为差分: ∂ 2 f ∂ x 2 = f ( x + 1 ) + f ( x − 1 ) − 2 f ( x ) \begin{aligned} 一阶导定义为差分:&\frac{\partial f}{\partial x}=f(x+1)-f(x) \\ \quad \\ 二阶导定义为差分:&\frac{\partial^2 f}{\partial x^2}=f(x+1)+f(x-1)-2f(x) \end{aligned} 一阶导定义为差分:二阶导定义为差分:xf=f(x+1)f(x)x22f=f(x+1)+f(x1)2f(x)
下面我们分别计算一行像素的一阶导和二阶导,并加以分析:
在这里插入图片描述
从上图中我们可以看出:

  • 斜坡:一阶微分非0二阶微分为0。
  • 斜坡开始处:一阶微分非0,二阶微分非0。
  • 斜坡结束处:二阶微分非0。
  • 台阶开始:一阶微分非0,二阶微分非0。
  • 台阶结束:二阶微分非0。
    我们换一种说法:
  • 对于斜坡:开始和结束的二阶微分为非0,在灰度变化率恒定的斜面上二阶微分值为0,这也是拉普拉斯锐化图像周围出现双边缘的原因,而一阶微分开始到结束都为非0,因此会产生较宽的边缘。
  • 对于阶梯:二阶微分中有一个从正到负的过渡,这一性质用于边缘检测。
  • 对于细线和孤立点:二阶微分对细线和孤立点的响应较强,这也说明了二阶微分对于细节增强的优越性,但同时也说明对噪声非常敏感。

2. 一阶导算子

2.1. Sobel算子

在这里插入图片描述

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

def sobleFilter2D(imgge):
    """
    使用Sobel算子进行图像锐化(cv.filter2D)
    :param imgge:
    :return:
    """
    # 使用函数 filter2D 实现 Sobel 算子
    kernSobelX = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])  # SobelX kernel
    kernSobelY = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])  # SobelY kernel
    SobelX = cv.filter2D(img, -1, kernSobelX, borderType=cv.BORDER_REFLECT)
    SobelY = cv.filter2D(img, -1, kernSobelY, borderType=cv.BORDER_REFLECT)
    SobelXY = cv.addWeighted(SobelX, 1.0, SobelY, 1.0, 0)  # 用绝对值近似平方根

    return SobelX, SobelY, SobelXY

def sobelGradient(image):
    """
    使用Sobel算子进行图像锐化(cv.Sobel)
    :param image: 原图像
    :return:
    """
    # x 方向梯度
    gradX = cv.Sobel(image, cv.CV_32F, 1, 0)
    # y 方向梯度
    gradY = cv.Sobel(image, cv.CV_32F, 0, 1)
    # 分别求绝对值并转化为8位的图像上,这样做方便显示
    imgGradX = cv.convertScaleAbs(gradX)
    imgGradY = cv.convertScaleAbs(gradY)

    # 两个方向梯度的叠加,权重各自一半
    imgGradXY = cv.addWeighted(imgGradX, 1.0, imgGradY, 1.0, 0)

    return imgGradX, imgGradY, imgGradXY

if __name__ == '__main__':

    img = cv.imread('Image/Fig0504.tif', 0)

    img1, img2, img3 = sobleFilter2D(img)
    img4, img5, img6 = sobelGradient(img)

    # 显示结果
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['font.size'] = 18
    plt.figure(figsize=(15, 5))
    plt.subplot(131), plt.title("原图像"), plt.axis('off')
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(132), plt.title("cv.Filter2D图像梯度"), plt.axis('off')
    plt.imshow(cv.cvtColor(img3, cv.COLOR_BGR2RGB))
    plt.subplot(133), plt.title("cv.Sobel图像梯度"), plt.axis('off')
    plt.imshow(cv.cvtColor(img6, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.savefig("Image/tmp.png")
    plt.show()

在这里插入图片描述
上图原图是一个隐形镜片的光学图像,光照突出了4点钟和5点钟方向镜片边界上的两个边缘缺陷。右图是Sobel核得到的梯度。

2.2. Scharr算子

在这里插入图片描述

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

def scharrGradient(image):
    """
    Scharr gradient function(cv.Scharr)
    :param image: Source image
    :return:
    """
    # x 方向梯度
    gradX = cv.Scharr(image, cv.CV_32F, 1, 0)
    # y 方向梯度
    gradY = cv.Scharr(image, cv.CV_32F, 0, 1)
    # 分别求绝对值并转化为8位的图像上,这样做方便显示
    imgGradX = cv.convertScaleAbs(gradX)
    print(imgGradX)
    imgGradY = cv.convertScaleAbs(gradY)

    # 两个方向梯度的叠加,权重各自一半
    imgGradXY = cv.addWeighted(imgGradX, 0.5, imgGradY, 0.5, 0)

    return imgGradX, imgGradY, imgGradXY

def charrFilter2D(imgge):
    """
    Scharr gradient function(cv.filter2D)
    :param image: Source image
    :return:
    """
    # 使用函数 filter2D 实现 Scharr 算子
    kernScharrX = np.array([[-3, 0, 3], [-10, 0, 10], [-3, 0, 3]])  # ScharrX kernel
    kernScharrY = np.array([[-3, -10, -3], [0, 0, 0], [3, 10, 3]])  # ScharrY kernel

    SobelX = cv.filter2D(img, -1, kernScharrX, borderType=cv.BORDER_REFLECT)
    SobelY = cv.filter2D(img, -1, kernScharrY, borderType=cv.BORDER_REFLECT)
    SobelXY = cv.addWeighted(SobelX, 0.5, SobelY, 0.5, 0)  # 用绝对值近似平方根

    return SobelX, SobelY, SobelXY

if __name__ == '__main__':

    img = cv.imread('Image/Fig0504.tif', 0)

    img1, img2, img3 = charrFilter2D(img)
    img4, img5, img6 = scharrGradient(img)

    # 显示结果
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['font.size'] = 18
    plt.figure(figsize=(15, 5))
    plt.subplot(131), plt.title("原图像"), plt.axis('off')
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(132), plt.title("cv.Filter2D图像梯度"), plt.axis('off')
    plt.imshow(cv.cvtColor(img3, cv.COLOR_BGR2RGB))
    plt.subplot(133), plt.title("cv.Scharr图像梯度"), plt.axis('off')
    plt.imshow(cv.cvtColor(img6, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.savefig("Image/tmp.png")
    plt.show()

在这里插入图片描述

2. 二阶导算子

2.1 拉普拉斯算子

2.1.1 原理说明

拉普拉斯图像锐化的基本函数式如下: g ( x , y ) = f ( x , y ) + c [ Δ 2 f ( x , y ) ] ,其中 c [ Δ 2 f ( x , y ) ] 是锐化增强的部分 g(x,y)=f(x,y)+c[\Delta^2f(x,y)],其中\quad c[\Delta^2f(x,y)]\quad是锐化增强的部分 g(x,y)=f(x,y)+c[Δ2f(x,y)],其中c[Δ2f(x,y)]是锐化增强的部分公式推导如下:
Δ 2 f = ∂ 2 f ∂ x 2 + ∂ 2 f ∂ y 2 \Delta^2f=\frac{\partial^2f}{\partial x^2}+\frac{\partial^2f}{\partial y^2} Δ2f=x22f+y22f分别求x, y方向的二阶偏导: ∂ 2 f ∂ x 2 = f ( x + 1 , y ) + f ( x − 1 , y ) − 2 f ( x , y ) \frac{\partial^2f}{\partial x^2}=f(x+1,y)+f(x-1,y)-2f(x,y) x22f=f(x+1,y)+f(x1,y)2f(x,y) ∂ 2 f ∂ y 2 = f ( x , y + 1 ) + f ( x , y − 1 ) − 2 f ( x , y ) \frac{\partial^2f}{\partial y^2}=f(x,y+1)+f(x,y-1)-2f(x,y) y22f=f(x,y+1)+f(x,y1)2f(x,y)可得: Δ 2 f ( x , y ) = f ( x + 1 , y ) + f ( x − 1 , y ) + f ( x , y + 1 ) + f ( x , y − 1 ) − 4 f ( x , y ) \Delta^2f(x,y)=f(x+1,y)+f(x-1,y)+f(x,y+1)+f(x,y-1)-4f(x,y) Δ2f(x,y)=f(x+1,y)+f(x1,y)+f(x,y+1)+f(x,y1)4f(x,y)这个公式可以通过下图中的核进行卷积运算来实现:

在这里插入图片描述
其中,若 g ( x , y ) = f ( x , y ) + c [ Δ 2 f ( x , y ) ] g(x,y)=f(x,y)+c[\Delta^2f(x,y)] g(x,y)=f(x,y)+c[Δ2f(x,y)]使用核 1 , 2 ,则 c = − 1 ,否则 c = 1 1,2,则c = -1,否则 c = 1 12,则c=1,否则c=1

2.1.2 示例分析

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt


def imageSharpening(src, kernel):
    """
    图像锐化:Laplacian
    :param src: 需要锐化的原图像
    :param kernel: 拉普拉斯核
    :return: 返回锐化结果
    """
    laplacian = cv.filter2D(src, -1, kernel)
    dst = src + laplacian
    return [src, laplacian, dst]


if __name__ == '__main__':
    img = cv.imread('Image/Fig0503.tif', 0)

    kernel1 = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]], dtype=np.float32)
    lst1 = imageSharpening(img, kernel1)

    kernel2 = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]], dtype=np.float32)
    lst2 = imageSharpening(img, kernel2)

    kernel3 = np.array([[0, -1, 0], [-1, 4, -1], [0, -1, 0]], dtype=np.float32)
    lst3 = imageSharpening(img, kernel3)

    kernel4 = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], dtype=np.float32)
    lst4 = imageSharpening(img, kernel4)

    # 直接使用 cv.Laplacian 接口
    # laplacian = cv.Laplacian(img, cv.CV_64F)
    # laplacian_abs = np.uint8(np.absolute(laplacian))
    # cv.imshow('Laplacian', laplacian_abs)
    # cv.waitKey(0)

    # 图像显示
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.figure(figsize=(16, 24))
    titleList = ["Original Image", "Laplacian A", "Sharpening","Original Image", "Laplacian B", "Sharpening","Original Image", "Laplacian C", "Sharpening","Original Image", "Laplacian D", "Sharpening"]
    imageList = lst1 + lst2 + lst3 + lst4

    for i in range(12):
        plt.subplot(4, 3, i + 1), plt.title(titleList[i]), plt.axis('off')
        plt.imshow(imageList[i], vmin=0, vmax=255, cmap='gray')
    plt.tight_layout()
    plt.savefig("Image/tmp.png")
    plt.show()

在这里插入图片描述


  • 33
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值