Python OpenCV 滤波

该文章已生成可运行项目,

低通滤波器

均值滤波器

均值滤波(normalized box filter)就是用其像素点周围像素平均值代替元像素值,在滤除噪声的同时也会滤掉图像的边缘信息的方法。

但均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。特别是椒盐噪声。

blur
cv2.blur(src, ksize, dst=None, anchor=None, borderType=None)

方盒滤波的参数为True时,就是均值滤波,所以这个API用的不多。
dst = cv2.blur(scr, ksize, anchor, borderType)

  • scr:源图像(图像矩阵)
  • ksize:卷积核大小(x,y)(滤波窗口(算子)尺寸)
  • anchor:锚点
  • borderType:有映射类型,加一个黑边,默认不设置(边界扩充类型)

该函数使用内核将图像平滑化,表示为:
在这里插入图片描述
作用:使用归一化卷积模板模糊图像

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

# 均值滤波器
# 读取灰度图像 
img = cv2.imread("D:/Study/digital image processing/test/saltLena.bmp",0)
# 模板大虚5*5
blur = cv2.blur(img,(5,5))
plt.subplot(121),plt.imshow(img,'gray')
plt.subplot(122),plt.imshow(blur,'gray')
plt.show()

在这里插入图片描述

boxFilter()
import cv2
import numpy as np

img = cv2.imread('./image/lena.jpg')

# 方盒滤波(当为True时)变成均值滤波,当为False时,就只加和不变化,超过255的结果设置为255
img2 = cv2.boxFilter(img, -1, (5, 5), normalize=True)
img3 = cv2.boxFilter(img, -1, (5, 5), normalize=False)
# 展示图像
cv2.imshow('img', img)
cv2.imshow('img2', img2)
cv2.imshow('img3', img3)

cv2.waitKey(0)

dst = cv2.boxFilter(src, ddepth, ksize , anchor, normalize, borderType)

  • src:输入图像
  • ddepth:输出图像的尺寸,默认为-1
  • ksize :卷积核大小(x, y)
  • anchor:锚点,默认随卷积核变化
  • normalize:布尔类型默认为True;True:a为1/W*H(均值滤波),false:a=1
  • borderType:有映射类型,加一个黑边,默认不设置

在这里插入图片描述

高斯滤波器

高斯滤波是一种线性平滑滤波器,对于服从正态分布的噪声有很好的抑制作用。在实际场景中,我们通常会假定图像包含的噪声为高斯白噪声,所以在许多实际应用的预处理部分,都会采用高斯滤波抑制噪声,如传统车牌识别等。

高斯滤波和均值滤波一样,都是利用一个掩膜和图像进行卷积求解。不同之处在于:均值滤波器的模板系数都是相同的为1,而高斯滤波器的模板系数,则随着距离模板中心的增大而系数减小(服从二维高斯分布)。所以,高斯滤波器相比于均值滤波器对图像个模糊程度较小,更能够保持图像的整体细节。

高斯滤波常见模板如下。

在这里插入图片描述

cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])

作用:根据像素距离使用高斯函数生成权重进行滤波

  • dst:输出图像
  • src:输入图像
  • ksize:卷积核的大小
  • sigmaX:x方向上的标准差
  • sigmaY:y方向上的标准差
  • borderType:边界模式,默认为BORDER_DEFAULT
  • 一般只需要看前三个参数
    在这里插入图片描述
# 高斯滤波器
img = cv2.imread("D:/Study/digital image processing/test/saltLena.bmp",0)
# 若只给了一个sigma则同时视为两轴的sigma,若均为0则根据尺寸自动生成。
dst = cv2.GaussianBlur(img,(5,5),0)

plt.subplot(121),plt.imshow(img,'gray')
plt.subplot(122),plt.imshow(dst,'gray')
plt.show()

在这里插入图片描述

import cv2
import numpy as np

img = cv2.imread('./image/Gaussian.png')

# 高斯去噪
img2 = cv2.GaussianBlur(img, (3, 3), 0)

# 展示图像
cv2.imshow('img', img)
cv2.imshow('img2', img2)

cv2.waitKey(0)

在这里插入图片描述

中值滤波(胡椒噪音)

对胡椒噪音去噪明显,取中间的值作为卷积结果
dst = cv2.medianBlur(img, ksize)

  • img:输入图像
  • ksize:卷积核大小一个数字
import cv2
import numpy as np

img = cv2.imread('./image/median.png')

# 胡椒噪声
img2 = cv2.medianBlur(img, 5)

# 展示图像
cv2.imshow('img', img)
cv2.imshow('img2', img2)

cv2.waitKey(0)

双边滤波

双边滤波的主要应用场景是视频美颜
cv2.bilateralFilter(img, d, sigmaColor, sigmaSpace, …)

  • img:输入图像
  • d:直径,与卷积核中心点的距离,一般取5
  • sigmaColor:颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
  • sigmaSpace:sigmaSpace坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。

双边滤波的作用:图像去噪保边,对相关分析的结果有较大的影响,对于裂缝比较强,噪声比较少的图像来说,可以将去噪的程度放大,对以后的相关分析的结果就会有更少的噪声。对于噪声不是很集中的图像,并有较多细节的图像,增加保边的效果,让相关分析及后续进行进一步的结构处理,去噪。

import cv2
import numpy as np

img = cv2.imread('./image/lena.jpg')


# 双边滤波
img2 = cv2.bilateralFilter(img, 5, 20, 50)

# 展示图像
cv2.imshow('img', img)
cv2.imshow('img2', img2)

cv2.waitKey(0)

在这里插入图片描述

高通滤波器

允许高于某个值的通过而阻断低于该值的滤波器。主要是有保留边缘的功能。
在这里插入图片描述

Sobel算子

Sobel算子是一种用于边缘检测的离散的离散微分算子,它结合了高斯平滑和微分求导。该算子用于计算图像明暗程度近似值,根据图像边缘化旁边明暗程度把该区域内超过某个数的特定点记为边缘。

Sobel算子在Prewitt算子的基础上增加了权重的概念,认为相邻点的距离远近对当前像素点的影响是不同的,距离越近的像素点对应当前像素的影响越大 ,从而实现图像锐化并突出边缘轮廓

Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息。因为Sobel算子结合了高斯平滑和微分求导(分化),因此结果会具有更多的抗噪性,当对精度要求不是很高时,Sobel算子是一种较为常用的边缘检测方法。

Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
  • src:输入图像
  • dst:输出的边缘图,其大小和通道数与输入图像相同
  • ddepth:目标图像所需的深度,针对不同的输入图像,输出目标图像有不同的深度
  • dx:x方向上的差分阶数,取值1或0
  • dy:y方向上的差分阶数,取值1或0
  • ksize:Sobel算子的大小,其值必须是正数和奇数
  • scale:缩放导数的比例常数,默认情况下没有伸缩系数
  • delta:将结果存入目标图像之前,添加到结果中的可选增量值
# Sobel算子
# 读取图像
img = cv2.imread("D:/Study/digital image processing/test/LenaRGB.bmp")
lenna_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 灰度化处理图像
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

x = cv2.Sobel(grayImage,cv2.CV_16S,1,0)
y = cv2.Sobel(grayImage,cv2.CV_16S,0,1)
# 转uint8
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
imgSobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)

# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 显示图形
titles = [u'原始图像', u'Sobel算子']
images = [lenna_img, imgSobel]
for i in xrange(2):
    plt.subplot(1,2,i + 1), plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

在这里插入图片描述
dst1 = cv2.Sobel(src, ddepth, dx, dy, ksize = 3, scale = 1, delta = 0, borderType = BORDER_DEFAULT )

  • src:输入原图像
  • ddepth:位深,默认为-1
  • dx,dy:只能选择一个方向上要么0、1,要么1、0
  • ksize:卷积核大小,默认为3,当-1时为沙尔
  • scale:缩放大小,一般就用默认值
  • delta:偏移量,一般就用默认值
  • borderType:边界扩充类型,一般就用默认值
  • 可以改变卷积核大小
import cv2
import numpy as np

img = cv2.imread('./image/lena.jpg')


# 索贝尔
dx = cv2.Sobel(img, -1, 1, 0, ksize=3)
dy = cv2.Sobel(img, -1, 0, 1, ksize=3)

# dst = dx+dy
dst = cv2.add(dx,dy)
# 展示图像
cv2.imshow('img', img)
cv2.imshow('dx', dx)
cv2.imshow('dy', dy)
cv2.imshow('dst', dst)

cv2.waitKey(0)

在这里插入图片描述

Prewitt算子

Prewitt是一种图像边缘检测的微分算子,其原理是利用特定区域内像素值产生的差分实现边缘检测

由于Prewitt算子采用3x3模型对区域内的像素值进行计算,而Robert算子的模板为2x2,故Prewitt算子的边缘检测结果在水平/垂直方向均比Robert算子更加明显。Prewitt算子适合用来识别噪声较多,灰度渐变的图像。

Prewitt算子的实现过程与Roberts算子比较相似。通过Numpy定义模板,再调用OpenCV的 filter2D() 函数实现对图像的卷积运算,最终通过convertScaleAbs() 和 addWeighted() 函数实现边缘提取。

其计算公式如下所示。在这里插入图片描述

# Prewitt算子
# 读取图像
img = cv2.imread("D:/Study/digital image processing/test/LenaRGB.bmp")
lenna_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 灰度化处理图像
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Prewitt算子
kernelx = np.array([[1,1,1],[0,0,0],[-1,-1,-1]], dtype=int)
kernely = np.array([[-1,0,1],[-1,0,1],[-1,0,1]], dtype=int)
x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
# 转uint8
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
imgPrewitt = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)

# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 显示图形
titles = [u'原始图像', u'Prewitt算子']
images = [lenna_img,imgPrewitt]
for i in xrange(2):
    plt.subplot(1,2,i + 1), plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

Prewitt算子图像锐化提取的边缘轮廓,其效果图比Robert算子的更加明显。

在这里插入图片描述

Scharr(沙尔)

与Sobel类似,只不过使用的ksize值不同,Scharr不能改变卷积核的大小,只能是3*3的。同样只能求一个方向上的边缘

cv2.Scharr(src, ddepth, dx, dy, scale = 1, delta = 0, borderType = BORDER_DEFAULT).
  • src:输入原图像
  • ddepth:位深,默认为-1
  • dx,dy:只能选择一个方向上要么0、1,要么1、0
  • scale:缩放大小,一般就用默认值
  • delta:偏移量,一般就用默认值
  • borderType:边界扩充类型,一般就用默认值
import cv2
import numpy as np

img = cv2.imread('./image/lena.jpg')


# # 索贝尔,当ksize=-1时,就是沙尔
# dx = cv2.Sobel(img, -1, 1, 0, ksize=-1)
# dy = cv2.Sobel(img, -1, 0, 1, ksize=-1)

dx = cv2.Scharr(img, -1, 1, 0)
dy = cv2.Scharr(img, -1, 0, 1)

# dst = dx+dy
dst = cv2.add(dx,dy)
# 展示图像
cv2.imshow('img', img)
cv2.imshow('dx', dx)
cv2.imshow('dy', dy)
cv2.imshow('dst', dst)

cv2.waitKey(0)

在这里插入图片描述

Roberts算子

采用对角相差的差分法来代替微分,其计算公式如下所示。
在这里插入图片描述

cv2.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
  • 作用:实现边缘提取
  • src:输入图像
  • dst:输出的边缘图,其大小和通道数与输入图像相同
  • ddepth:目标图像所需的深度
  • kernel:卷积核,一个单通道浮点型矩阵
  • anchor:内核的基准点,其默认值为(-1,-1),位于中心位置
  • delta:在储存目标图像前可选的添加到像素的值,默认值为0
  • borderType:边框模式
cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])

作用:返回uint8类型的图片
可选参数alpha是伸缩系数,beta是加到结果上的一个值。

# Roberts算子
# 读取图像
img = cv2.imread("D:/Study/digital image processing/test/LenaRGB.bmp")
lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
# 灰度化处理
grayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# Roberts算子
kernelx = np.array([[-1, 0],[0, 1]],dtype=int)
kernely = np.array([[0, -1],[1, 0]],dtype=int)

# 对图像求导后,结果有正有负,且有可能超出255,所以求梯度时要注意像素的数值类型
# 求梯度时将像素的数值类型转换为cv2.CV_16S来存放可能超出范围的结果
# cv2.CV_16S,16位有符号的数据类型,以防止截断
x = cv2.filter2D(grayImage,cv2.CV_16S,kernelx)
y = cv2.filter2D(grayImage,cv2.CV_16S,kernely)
# 用convertScaleAbs()函数将其转为uint8形式,否则将无法显示图像,而只是一副灰色的窗口
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Roberts = cv2.addWeighted(absX,0.5,absY,0.5,0) # 图像融合

# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 显示图形
titles = [u'原始图像', u'Roberts算子']
images = [lenna_img, Roberts]
for i in xrange(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

Laplacian算子

拉普拉斯(Laplacian)算子是n维欧几里德空间中的一个二阶微分算子,常用于图像增强领域和边缘提取

它通过灰度差分计算邻域内的像素基本流程是:判断图像中心像素灰度值与它周围其他像素的灰度值,如果中心像素的灰度更高,则提升中心像素的灰度;反之降低中心像素的灰度,从而实现图像锐化操作。

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

Laplacian算子分为四邻域和八邻域,四邻域是对邻域中心像素的四方向求梯度,八邻域是对八方向求梯度。

四邻域模板如公式所示。
在这里插入图片描述Laplacian算子的八邻域模板如下。在这里插入图片描述

cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
  • src:输入原图像
  • ddepth:位深,默认为-1
  • ksize:卷积核大小,默认为1
  • scale:缩放大小,一般就用默认值
  • delta:偏移量,一般就用默认值
  • borderType:边界扩充类型,一般就用默认值
# Laplacian算子
# 读取图像
img = cv2.imread("D:/Study/digital image processing/test/LenaRGB.bmp")
lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
# 灰度化处理图像
grayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 拉普拉斯算法
# ksize=1时,Laplacian()函数采用3×3的孔径(四邻域模板)进行变换处理
dst = cv2.Laplacian(grayImage,cv2.CV_16S,ksize=3)
Laplacian = cv2.convertScaleAbs(dst)

# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']

# 显示图形
titles = [u'原始图像', u'Laplacian算子']
images = [lenna_img,Laplacian]
for i in xrange(2):
    plt.subplot(1,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

在这里插入图片描述

Canny

使用5*5高斯滤波消除噪声,可以计算图像的四个方向上的边缘(0,45,90,135),取局部的最大值,多了一个阈值计算。高于阈值我们认为是边缘,低于阈值就不是边缘,显然A为边缘,如果,但是B和C介于最大值最小值之间,BC既不是边缘也是边缘,但是C与A在一条直线上,所以C也是边缘。

在这里插入图片描述
dst = cv2.Canny(img, minVal, maxVal)

  • img:原图像
  • minVal:最小阈值
  • maxVal:最大阈值
  • 低于最小阈值就不是边缘,高于最大阈值是边缘。
import cv2
import numpy as np

img = cv2.imread('./image/lena.jpg')


# canny
dst = cv2.Canny(img, 100, 200)

cv2.imshow('img',img)
cv2.imshow('dst',dst)

cv2.waitKey(0)

在这里插入图片描述

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值