滤波
线性滤波可以说是图像处理最基本的方法,它可以允许我们对图像进行处理,产生很多不同的效果。
卷积
卷积的概念:
卷积的原理与滤波类似。但是卷积却有着细小的差别。 卷积操作也是卷积核与图像对应位置的乘积和。但是卷积操作在做乘积之前,需要先 将卷积核翻转180度,之后再做乘积。
卷积的数学定义:
一般称为g为作用在f上的filter或kernel
卷积解决的问题:
卷积负责提取图像中的局部特征
对于滤波器,也有一定的规则要求:
1)滤波器的大小应该是奇数,这样它才有一个中心,例如3x3,5x5或者7x7。有中心了,也有 了半径的称呼,例如5x5大小的核的半径就是2。
2)滤波器矩阵所有的元素之和应该要等于1,这是为了保证滤波前后图像的亮度保持不变。但 这不是硬性要求。
3)如果滤波器矩阵所有元素之和大于1,那么滤波后的图像就会比原图像更亮,反之,如果小 于1,那么得到的图像就会变暗。如果和为0,图像不会变黑,但也会非常暗。
4)对于滤波后的结构,可能会出现负数或者大于255的数值。对这种情况,我们将他们直接截 断到0和255之间即可。对于负数,也可以取绝对值。
卷积的应用:
第一种卷积:
一个没有任何效果的卷积
将原像素中间像素值乘1,其余全部乘0。 显然像素值不会发生任何变化。
第二种卷积:
平滑均值滤波
取九个值的平均值代替中间像素值 — 起到平滑的效果。
第三种卷积:
高斯平滑
高斯平滑水平和垂直方向呈现高斯分布,更突出了 中心点在像素平滑后的权重,相比于均值滤波而言, 有着更好的平滑效果。
第四种卷积:
图像锐化
图像锐化使用的是拉普拉斯变换核函数
第五种卷积:
边界提取的卷积:
用Gx来卷积下面这张图的话,就会在黑白边界获得比较大的值。
手动计算可以发现Gx对横向边界会有很大的像素值,Gy是对纵向边界有很大的像素值,从而实现边界提取。
第六种卷积:
Sobel边缘检测:
Sobel更强调了和边缘相邻的像素点 对边缘的影响。
(不仅仅考虑横向和纵向的边界提取,其他方向的边界也会得到)
代码实现:
import cv2
import numpy as npimg = cv2.imread("lenna.png", 0)'''
Sobel函数求完导数后会有负值,还有会大于255的值。
而原图像是uint8,即8位无符号数(范围在[0,255]),所以Sobel建立的图像位数不够,会有截断。
因此要使用16位有符号的数据类型,即cv2.CV_16S。
'''
x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
y = cv2.Sobel(img, cv2.CV_16S, 0, 1)'''
在经过处理后,别忘了用convertScaleAbs()函数将其转回原来的uint8形式。
否则将无法显示图像,而只是一副灰色的窗口。
dst = cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])
其中可选参数alpha是伸缩系数,beta是加到结果上的一个值。结果返回uint8类型的图片。
'''absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)'''
由于Sobel算子是在两个方向计算的,最后还需要用cv2.addWeighted(...)函数将其组合起来
。其函数原型为:
dst = cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
其中alpha是第一幅图片中元素的权重,beta是第二个的权重,
gamma是加到最后结果上的一个值。
'''dst = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)cv2.imshow("absX", absX)
cv2.imshow("absY", absY)cv2.imshow("Result", dst)cv2.waitKey(0)
cv2.destroyAllWindows()
实现结果:
竖向:
横向:
总和结果:
对比图中横向和纵向的女生嘴唇可以明显看出来,横向和纵向的提取效果
步长/Stride
如果用(f, f)的过滤器来卷积一张(h, w)大小的图片,每次移动一个像素的话,那么得出的结果 就是(h-f+1, w-f+1)的输出结果。f是过滤器大小,h和w分别是图片的高宽。 如果每次不止移动一个像素,而是s个像素,那么结果就会变为:
这个s就叫做步长。
通俗来讲,就是卷积核移动的一步的大小。
存在的问题:
• 只要是f或s的值比1要大的话,那么每次卷积之后结果的长宽,要比卷积前小一些。(比如说[5×5]的矩阵,在经过[3×3]的卷积核后的结果是[3×3],比原先[5×5]的矩阵要小)
• 丢失信息
填充/Pading
填充就是在原矩阵外边添加一圈或多圈全0的值。
主要用来保证卷积核输出的格式。比如说:[5×5]的矩阵,在经过[3×3]的卷积核后的结果是[3×3],我们要是像得到还是[5×5]的矩阵,就需要将原[5×5]的矩阵填充为[7×7]的矩阵,这样卷积后的结果就是[5×5]的矩阵了
Same(相同)填充:
Vaild(有效)填充:
是分数怎么办?一般的处理是,只取整数部分。
而这种p=0,然后结果取整数部分的处理方式,叫做Valid(有效)填充。
Same(相同)填充和Vaild(有效)填充的区别:
SAME进行填充,,当滑动卷积核之后,若多出一列,“Same”发现余下的窗口不到卷积核大小并不会把多出的一列丢弃,但是只有一列了不够卷积核大小怎么办?填充!会在原图像外围添加一圈或者多圈全“0”(图片卷积后可能不会变小。)
VALID不进行填充,当滑动卷积核之后,若多出一列,“Vaild”发现余下的窗口不到卷积核大小,会就把剩下的一列直接去了(图片卷积后还是会变小。)
其中:W为输入的size,F为filter的size,S为步长
此处参考了网络 wuzqchom的博客
TensorFlow中CNN的两种padding方式“SAME”和“VALID”
卷积的扩展:3通道卷积
卷积核的确定:
CNN厉害的地方在于, 过滤器的特征并不是人为设定的,而是通过大量图片自己训练出来的。