QQ:3020889729 小蔡
我们对于一维数据或者说信号,我们通常有许多的处理方法——而其中对信号滤波处理是为了数据更为理想所必要的。对于一维的信息滤波——有低通(LPF)和高通(HPF)。低通,通常用来去噪等操作。
到这里,可以顺着思路想到二维图像呢?当然啦,同样的,二维图像也是有属于自己的同一维一样的滤波形式——低通用于除去图像的噪点和实现模糊图像,而高通可以用来实现边缘查找(这个在后边介绍。)
——滤波简单介绍:用一维的信号来说吧
滤波电路——实现相应频率的输出/控制:
即只允许一定频率范围内的信号成分正常通过,而阻止另一部分频率成分通过的电路(也叫做经典滤波器)。——这样的只允许一部分满足条件的信号/数据得以展现/或者说有效,就是滤波的基本体现。
cv. filter2D()——这里使用的卷积函数实际上知识直接计算——并未真的实现卷积,若是真要卷积的话需要对内核提前进行cv.flip翻转内核才行。
计算方法如下:x,y为输入图像的数据。
~kernel是内核
cv. filter2D()参数如下:
代码:
import cv2 as cv
import numpy as np
if __name__ == "__main__":
img = cv.imread('../imag_in_save/class1.jpg')
kernel = np.ones((5, 5), np.float32)/25
# 注意哦,内核应该保证内核每一个值之和为1
print("原图形:\n", img[:, :, 2], end='\n'*4) # 输出比较处理前后的像素信息发生的变化
dst = cv.filter2D(img, -1, kernel)
print("处理后的图形:\n", dst[:, :, 2])
cv.imshow('imag1', img)
cv.imshow('imag2', dst)
cv.waitKey(0)
cv.destroyAllWindows()
相对于采用filter2D实现根据内核变化的任意模糊(滤波)处理,我们有时更倾向于专门用来解决某一问题的方法——比如接下来这几个常用模糊方法。
有两种方法:
其一,也是自己用着比较习惯的(主要是方便):
cv.blur()——使用归一化框滤镜模糊图像。
参数如下:
其二,采用boxFilter()实现平滑模糊
参数如下:依次为:输入图像,输出图像(用返回值接收,所以省略),深度(默认-1),大小(内核大小)——以及后边不常用的锚点,是否采用归一化处理数据,边缘像素的处理方法。
import cv2 as cv
import numpy as np
# 图像平均模糊处理——blur实现内核模糊
if __name__ == "__main__":
img = cv.imread('../imag_in_save/class1.jpg')
dst = cv.blur(img, (5, 5))
# 彩色图形——第一个维度为高——也就是行数
# 第二个维度为宽——也就是列数
# 第三个维度——对应像素信息参数
cv.imshow('imag1', img)
cv.imshow('imag2', dst)
cv.waitKey(0)
与上边的blur形成对比——
import cv2 as cv
import numpy as np
# 图像平均模糊处理——boxFilter实现内核模糊
if __name__ == "__main__":
img = cv.imread('../imag_in_save/class1.jpg')
dst2 = cv.boxFilter(img, -1, (5, 5))
dst = cv.blur(img, (5, 5))
# 彩色图形——第一个维度为高——也就是行数
# 第二个维度为宽——也就是列数
# 第三个维度——对应像素信息参数
cv.imshow('imag1', img)
cv.imshow('imag2', dst)
cv.imshow('imag3', dst2)
cv.waitKey(0)
cv.destroyAllWindows()
效果:观察可以得知,用法和效果是相同的~
采用cv.GaussianBlur()实现高斯模糊,其参数如下:
import cv2 as cv
import numpy as np
# 图像高斯模糊处理——GaussianBlur
if __name__ == "__main__":
img = cv.imread('../imag_in_save/class1.jpg')
dst = cv.GaussianBlur(img, (21, 21), 2, 3)
# 彩色图形——第一个维度为高——也就是行数
# 第二个维度为宽——也就是列数
# 第三个维度——对应像素信息参数
cv.imshow('imag1', img)
cv.imshow('imag2', dst)
cv.waitKey(0)
cv.destroyAllWindows()
补充——如果有需要可以使用cv.getGaussianKernel()创建高斯内核——方法如下:
getGaussianKernel(需要的内核大小, 高斯计算需要的标准差, 滤波器数据类型)
以上参数——对应ksize,二元元组;
标准差任意值,不过若为负数,那么就根据ksize计算为sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8的值设置;
最后的数据类型可以选择:CV_32F或CV_64F——这里一般选用32,具体看图像参数运算需要吧。
函数cv.medianBlur()提取内核区域下所有像素的中值,并将中心元素替换为该中值。
该滤波器中,中心元素是新计算的值,该值可以是图像中的像素值或新值。但是在中位模糊中,中心元素始终被图像中的某些像素值代替。能有效降低噪音。
采用的是cv.medianBlur()实现中位模糊,参数如下:
import cv2 as cv
import numpy as np
# 图像中位模糊处理——medianBlur
if __name__ == "__main__":
img = cv.imread('../imag_in_save/class1.jpg')
dst = cv.medianBlur(img, 7)
# 彩色图形——第一个维度为高——也就是行数
# 第二个维度为宽——也就是列数
# 第三个维度——对应像素信息参数
cv.imshow('imag1', img)
cv.imshow('imag2', dst)
cv.waitKey(0)
cv.destroyAllWindows()
cv.bilateralFilter()在消除噪声的同时保持边缘清晰的方面非常有效。缺点:该操作速度较慢。
需要知道的是,高斯滤波器采用像素周围的邻域并找到其高斯加权平均值。且高斯滤波器是空间的函数,也就是说,滤波时会考虑附近的像素。但它不考虑像素是否具有几乎相同的强度。它不考虑像素是否是边缘像素。因此,它也模糊了边缘,这是我们不想做的。所以有了双边过滤——也就是对高斯滤波的掌控。
双边滤波的实现,是在空间中需要一个高斯滤波器,同时又有一个高斯滤波器,它是像素差异的函数——控制像素的强度差。空间的高斯函数可确保只考虑附近的像素进行模糊处理,而强度差的高斯函数可确保考虑强度与中央像素相似的像素进行模糊处理。由于边缘的像素强度变化较大,因此可以保留边缘。
cv.bilateralFilter()的参数如下:
import cv2 as cv
import numpy as np
# 图像双边模糊处理——bilateralFilter
if __name__ == "__main__":
img = cv.imread('../imag_in_save/class1.jpg')
dst = cv.bilateralFilter(img, 20, 55, 20)
# 彩色图形——第一个维度为高——也就是行数
# 第二个维度为宽——也就是列数
# 第三个维度——对应像素信息参数
cv.imshow('imag1', img)
cv.imshow('imag2', dst)
cv.waitKey(0)
cv.destroyAllWindows()
效果:sigmaColor为55的效果
sigmaColor为100的效果——像素颜色混合范围增大,会越来越混合
之后的补充内容,是为了方便一些参数的理解——不必深究,仅是为了引入理解,可能会有些描述上的问题,或者其它一些错误,如有问题,还望指出。
前往平均模糊的实现(2D卷积)
锚点——即定位点(这个定位点又有些特殊,由比例组成,也就是x,y均满足绝对值小于等于1)。
游轮有抛锚停靠,只要假设抛锚后,锚固定不动,,并且把船体比作一个点,那么无论长潮或者水面下降,船体与锚的相对位置不变——而对于岸边(即其它视角的位置)可能会改变哦。
即图像的排布位置取决于锚点的值——这里不需要很深的理解。
下面用一种比较一般的
图解:(这里的(-1, -1)就是锚点(0, 0),实际上在一些不同的应用环境中是不能有(-1, -1)的),只需要理解锚点的大概意思——及决定图像的相对位置即可,无需深究这个图。因为opencv中锚点值对应的不尽相同,比如在opencv中(-1, -1)代表着内核中心,相当于这里图中的(0.5, 0.5)
前往原参数列表位置
有兴趣可以尝试下:(就直接贴图了,具体的处理效果,可以参考以下指出的几个。)
到这里,全部内容就结束了。或许,文中错误还是有的,如有错误还望大家能批评指出。让我能及时矫正,更改。