opencv-python 卷积操作和图像滤波
1 图像卷积
图像卷积就是卷积核在图像上按行滑动遍历像素时不断的相乘求和的过程,卷积可以用来提取特征,去噪,平滑等。
如下图:
常用概念:
1)步长:卷积核在图像上移动的步幅(每次移动一个像素步长,两个像素步长。。。)
2)padding:通过卷积后图片的长宽都会变小,如果要保持图片大小不变,需要在原始图片周围填充0,padding指的是填充0的圈数。
3)卷积核必须是奇数,3*3,5*5,7*7;否则padding填充会出现非整数的填充情况。
RGB彩色图像的卷积过程如下:
可以看到:
- 两个神经元,即depth=2,意味着有两个滤波器。
- 数据窗口每次移动两个步长取3*3的局部数据,即stride=2。
- zero-padding=1。
然后分别以两个滤波器filter为轴滑动数组进行卷积计算,得到两组不同的结果。
opencv提供的卷积函数是:filter2D(src,ddepth,kernel[,dst[,anchor[,delta[,borderType[)。
ddepth是卷积之后图片的位深(卷积后图片的数据类型),一般设为-1,表示和原图一致
kernel是卷积核,用元组或者ndarray表示,数据类型必须是float类型
anchor是锚点,卷积和的中心点,默认(-1,-1),delta是偏置项,默认0
2 均值滤波和方盒滤波
图像滤波也称为图像平滑或图像模糊,是为了减少噪声核伪影的一种图像处理操作。图像滤波分为线性滤波和非线性滤波,线性滤波包括方盒滤波、均值滤波和高斯滤波;非线性滤波包括中值滤波和双边滤波。各种滤波其实是不同的卷积核对图像的卷积操作。
方盒滤波的滤波器是矩形的,滤波器中所有元素值相等。均值滤波是方盒滤波的特殊形式,均值滤波的输出图像的深度和输入图像的深度一致,而方盒滤波可以用归一化的形式调用,且输出图像深度可以控制。opencv中提供了方盒滤波 boxFilter(str, ddepth,ksize,anchor=None,normalize=None,borderType=None) 其中,ksize是滤波运算的核尺寸,normalize表示核是否需要归一化处理。
opencv提供的均值滤波函数blur(src,ksize,anchor=None,borderType=None) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import cv2 import numpy as np img = cv2.imread( './cat.jpg' ) kernel = np.ones(( 5 , 5 ),np.float32) / 25 #均值卷积核,平滑模糊 #kernel = np.array([[-1,-1,-1],[-1,8,-1],[-1,-1,-1]]) #突出轮廓的卷积核 #kernel = np.array([[-2,-1,0],[-1,1,1],[0,1,2]]) # 类似浮雕的卷积核 #kernel = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]]) #锐化的卷积核 filter_img = cv2.filter2D(img, - 1 ,kernel) #卷积操作,自动padding补偿0,ddepth=-1表示和原图深度一样。 box_img = cv2.boxFilter(img, - 1 ,( 5 , 5 )) #方盒滤波,平滑模糊,不需要创建卷积核,只需要参数中指定位深和size就行 blur_img = cv2.blur(img,( 5 , 5 )) #均值滤波,不需要创建卷积核,只需要参数中指定size就行 cv2.imshow( 'img' ,np.hstack([img,filter_img])) cv2.imshow( 'box_img' ,box_img) cv2.imshow( 'blur_img' ,blur_img) cv2.waitKey( 0 ) cv2.destroyAllWindows() |
直接进行卷积操作(卷积核是5*5的归一化的核),以及进行5*5的方盒滤波和均值滤波效果如下:
根据卷积核设置的不同,也可以通过卷积操作得到其他的效果,比如可以突出图像的轮廓:
用图片做出浮雕的效果:
可以对图片进行锐化增强:
3 高斯滤波
首先,高斯函数的特点是以x轴某一点(这一点称为均值)为对称轴,越靠近中心数据发生的概率越高,最终形成一个两边平缓,中间陡峭的钟形的图形。
高斯滤波的卷积核的元素是符合高斯分布的,比如3*3的高斯核的每个元素可以用高斯函数计算出来,中心点是(0,0),计算出来后再进行归一化处理得到的3*3矩阵就是高斯卷积核矩阵。
二维高斯函数如下:
根据高斯函数可以计算出对应的高斯概率密度函数:
然后对上面的结果进行归一化处理,除以这9个数的总和,得到最终的高斯模板:
高斯滤波一般用于去噪模糊 GaussianBlur(src, ksize, sigmaX, sigmaY=None) sigma越大,去噪能力越强(过滤高斯噪声),如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import cv2 import numpy as np img = cv2.imread( './img_gauss.png' ) gauss_img1 = cv2.GaussianBlur(img,( 5 , 5 ),sigmaX = 1 ) gauss_img2 = cv2.GaussianBlur(img,( 5 , 5 ),sigmaX = 10 ) cv2.imshow( 'img' ,img) cv2.imshow( 'gauss_img1' ,gauss_img1) cv2.imshow( 'gauss_img2' ,gauss_img2) cv2.waitKey( 0 ) cv2.destroyAllWindows() |
4 中值滤波
中值滤波原理比较简单,就是取对应数据的中位数作为结果,但是中值滤波对椒盐噪声有很好的去除效果。opencv中值滤波函数为 medianBlur(src, ksize)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import cv2 import numpy as np img = cv2.imread( './lenaNoise.png' ) median_img = cv2.medianBlur(img, 5 ) #gauss_img = cv2.GaussianBlur(img,(5,5),sigmaX=1) cv2.imshow( 'img' ,np.hstack([img,median_img])) cv2.imshow( 'lena2.jpg' ,median_img) #cv2.imshow('img2',np.hstack([img,gauss_img])) cv2.waitKey( 0 ) cv2.destroyAllWindows() |
5 对图形添加高斯、椒盐噪声
1)添加高斯噪声
高斯噪声是指在每个像素点上添加一个高斯分布的随机噪声,其传统的生成方式是使用numpy库的random函数生成随机数,利用OpenCV对每个像素点进行操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import cv2 import numpy as np img = cv2.imread( './lena2.jpg' ) mean = 0 std = 0.4 # np.random.normal(loc=0.0, scale=1.0, size=None) 生成的数据需要转换为uint8格式。 noise = np.random.normal(mean,std,img.shape).astype(np.uint8) #生成均值为0,标准差为0.5的高斯分布,数据大小跟图像大小一样。 # print(noise) img_gauss = cv2.add(img,noise) cv2.imshow( 'img' ,img) cv2.imshow( 'img_gauss' ,img_gauss) cv2.waitKey( 0 ) cv2.destroyAllWindows() |
2)添加椒盐噪声
椒盐噪声就是图像上的黑白点,即只需要给图像上的随机位置添加黑白点像素就行。利用numpy的random.randint产生随机数(也可以单独加黑噪声或者白噪声)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import cv2 import numpy as np img = cv2.imread( './lena2.jpg' ) img_copy = img.copy() h,w,c = img.shape noise_num = 3000 #添加噪声数量 for i in range (noise_num): x = np.random.randint( 0 ,h) #获取随机的横纵坐标 y = np.random.randint( 0 ,w) img_copy[x,y,:] = [ 255 , 255 , 255 ] #切片把对应位置赋值为白点 for i in range (noise_num): x = np.random.randint( 0 ,h) y = np.random.randint( 0 ,w) img_copy[x,y,:] = [ 0 , 0 , 0 ] #切片把对应位置赋值为黑点 cv2.imshow( 'img' ,img) cv2.imshow( 'img_copy' ,img_copy) cv2.waitKey( 0 ) cv2.destroyAllWindows() |
3)直接使用 skimage.util 包里面的 random_noise 函数来添加噪声
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from skimage.util import random_noise #添加噪声模块 import cv2 image = cv2.imread( './lena2.jpg' ) noise_gaussian = random_noise(image,mode = "gaussian" ,var = 0.1 ,clip = True ) noise_salt = random_noise(image,mode = "salt" ,amount = 0.5 ,clip = True ) noise_pepper = random_noise(image,mode = "pepper" ,amount = 0.5 ,clip = True ) noise = random_noise(image,mode = "s&p" ,amount = 0.5 ,clip = True ) cv2.imshow( 'img' ,img) cv2.imshow( 'noise_gaussian' ,noise_gaussian) cv2.imshow( 'noise_pepper' ,noise_pepper) cv2.imshow( 'noise_pepper' ,noise_pepper) cv2.imshow( 'noise' ,noise) cv2.waitKey( 0 ) cv2.destroyAllWindows() |
6 双边滤波
在降噪平滑的同时保留图像边缘信息(相当于美颜,对椒盐噪声没啥用),原理为一个与空间距离相关的高斯函数与一个与灰度距离相关的高斯函数相乘。双边滤波本质上是高斯滤波,但是双边滤波既利用了位置信息又利用了像素信息来定义滤波窗口的权重值。高斯滤波只利用了位置信息。
高斯滤波:滤波图是钟型,利用空间距离的权值系数核与图像卷积后,确定中心点的灰度值。离中心点越近,权重系数越大。双边滤波加入了对灰度信息的权重,在邻域内,其灰度值越接近中心点的灰度值,权重越大。这个权重由高斯函数确定。
opencv中提供的双边滤波的函数是:bilateralFilter(img,d,sigmaColor,sigmaSpace) d表示滤波过程中每个像素领域的直径范围;sigmaColor表示颜色空间滤波器的sigma值;sigmaSpace表示坐标空间滤波器的sigma值。
1 2 3 4 5 6 7 8 9 10 11 12 | import cv2 import numpy as np img = cv2.imread( './face.jpg' ) dst = cv2.bilateralFilter(img, 9 ,sigmaColor = 10 ,sigmaSpace = 10 ) #双边滤波(原图,滤波size,灰度高斯函数的sigma,空间高斯函数的sigma) cv2.imshow( 'img' ,np.hstack([img,dst])) cv2.waitKey( 0 ) cv2.destroyAllWindows() |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)