Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

准备工作

读取灰度图的方法:

1
img = imread(<path>,cv2.IMREAD_GRAYSCALE);

滤波操作

来,咱们首先产生些噪点

1
2
3
4
5
6
7
8
9
10
11
12
13
import cv2;
import random;
img = cv2.imread("E:\\avatar_small.jpg");
imgSize = img.shape;
y=imgSize[1]-1;
x=imgSize[0]-1;
for i in range(3000):#创建3000个噪点
a=random.randint(0,x);
b=random.randint(0,y);
img[a,b]=(255,255,255);#把选中的像素点搞成白色
cv2.imwrite("E:\\noise.jpg",img);
cv2.imshow("test",img);
cv2.waitKey(0);

99

均值滤波

原理是将像素点本身,以及像素点周围的八个像素(共九个像素)取平均数

例如图像

21 37 42
52 244 212
112 24 58

对中间像素(244)进行均值滤波的过程就是

$\overline{x}=\frac{21+37+42+52+244+212+112+24+58}{9}$

它的卷积核是这样的

$
\left(
\begin{matrix}
1 & 1 & 1 \
1 & 1 & 1 \
1 & 1 & 1
\end{matrix}
\right)
$

如此往复,把整张图片遍历即可得到滤波后的图形

1
2
3
4
5
import cv2;
img = cv2.imread("E:\\noise.jpg");
cv2.blur(img,(3,3));#使用3*3的卷积核进行均值滤波
cv2.imshow("average",img);
cv2.waitKey(0)

均值滤波的缺点:会导致图片变模糊

均值滤波

高斯滤波

这是高斯滤波公式

$
G(x,y) = \frac{1}{2 \pi \sigma^{2}} \exp\left(-\frac{x^{2}+y^{2}}{2\sigma^{2}}\right)
$

下面是计算高斯核元素的公式

$G(i, j)=\frac{1}{2\pi\sigma^{2}}\exp\left(-\frac{(i - c_x)^{2}+(j - c_y)^{2}}{2\sigma^{2}}\right)$

分别令k和sigema=1后,为了使得权系数为1,需要进行归一化,然后得到的高斯滤波的一个3*3的卷积核是这样的

$
\left(
\begin{matrix}
0.0751 & 0.1238 & 0.751 \
0.1238 & 0.2042 & 0.1238 \
0.7511 & 0.1238 & 0.0751
\end{matrix}
\right)
$

通过观察可以知道,离中间像素最近的元素的权重比边角的权重数值要大,也即高斯滤波是加权平均版本的均值滤波

还好还好,这些复杂的公式不用我们自己算,可以直接食用OpenCV封装好的函数

1
2
3
4
5
6
7
8
9
10
11
12
import cv2;
img = cv2.imread("E:\\noise.jpg");
cv2.GaussianBlur(img,(3,3),1);#使用3*3的卷积核进行高斯滤波

#参数1表示权重,意思是选取的那个最重要的值
#此时的高斯核为
#| 0.6 0.8 0.6 |
#| 0.8 1.0 0.8 |
#| 0.6 0.8 0.6 |

cv2.imshow("Gaussian",img);
cv2.waitKey(0)

中值滤波

这种滤波方式比较简单,我们把均值滤波的表格拿下来

21 37 42
52 244 212
112 24 58

把这些数字从小到大排序得到

21 24 37 42 52 58 112 212 244

52就是这组数据的中间值,那么就把表格中间(2,2)的位置替换成52得到

21 37 42
52 52 212
112 24 58

就结束了

1
2
3
4
5
import cv2;
img = cv2.imread("E:\\noise.jpg");
cv2.medianBlur(img,3);#3*3区域的中值滤波,类似上面的表格
cv2.imshow("Gaussian",img);
cv2.waitKey(0)

互逆运算——腐蚀与膨胀

需要注意的是:腐蚀、膨胀以及开闭运算需要在二值化图像上进行,并且腐蚀并不绝对是腐蚀(也有可能erode函数操作出来的图像是dilate的效果),具体需要看二值化的方法,由于我的图像轮廓线是纯黑色,因此直接使用,imgres = cv2.threshold(img,127,255,cv2.THRESH_BINARY);来进行二值化的话就会出现腐蚀函数算出膨胀效果,因此我们需要将二值化进行反相,也就是这样转换,imgres = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV);

腐蚀

腐蚀就是将卷积核跟二值化图像进行“与”运算,当卷积核覆盖的范围不是全1时,会将卷积核所覆盖的内容全部置0,例如当图像的某一3*3范围内有这样一组数据,

0 1 1
1 0 0
1 1 1

那么腐蚀运算会把它们都变成纯0,通过腐蚀运算,我们可以将图像的边缘部分向内“腐蚀”

1
2
kernel = np.ones((3,3), np.uint8) #新建一个核
erorsion_img = cv2.erode(img, kernel, iterations=1) #将核传入erode函数,核跟iterations(迭代次数)越大,腐蚀巧果越强

image-1

膨胀

膨胀是与腐蚀运算相反的运算,它是将卷积核跟二值化图像进行“或”运算,也就是说,只要卷积核所覆盖的区域中包含“1”的话,那么整个范围都会被置1,正好与腐蚀运算相反

1
2
kernel = np.ones((5,5), np.uint8) #新建一个核
dilation_img = cv2.dilate(img, kernel, iterations=1) #将核传入dilate函数,与腐蚀相似

image-2

开运算、闭运算

开运算是先进行腐蚀、再进行膨胀

闭运算是先进行膨胀、后进行腐蚀

1
2
open = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
clos = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

形态学梯度

形态学梯度=膨胀结果-腐蚀结果

也就是说,形态学梯度就是图像的边缘

1
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)

边缘检测——Sobel算子

NV5F76DXI74KNDHZRTRZI-1-1024x360

左:阈值为127,最大值255的二值化图像

中:灰度图

右:使用Sobel算子对二值化图像处理

评论