九 模糊操作
推文 https://blog.csdn.net/xw20084898/article/details/21822565
推文 https://blog.csdn.net/on2way/article/details/46828567
三种模糊操作
均值模糊
中值模糊
自定义模糊(可以实现上面两种模糊方式)
这个算法类似有:均值,中值,就是取周围所有像素的均值、中值来设置这个像素的大小。
(关于边界问题:有几种填充方法:补零、边界复制、块复制、镜像复制等方法)
原理
图像处理:基础(模板、卷积运算)
图像处理-模板、卷积的整理
基于离散卷积
定义好每个卷积核
不同卷积核得到不同的卷积效果
模糊是卷积的一种表象
一、均值模糊blur
opencv有一个专门的平均滤波模板供使用–归一化卷积模板,所有的滤波模板都是使卷积框覆盖区域所有像素点与模板相乘后得到的值作为中心像素的值。
Opencv中均值模板可以用cv2.blur和cv2.boxFilter,比如一个3*3的模板其实就可以如下表示:
模板大小是m*n是可以设置的。如果你不想要前面的1/9,可以使用非归一化的模板cv2.boxFilter。
1 img = cv.imread('11.jpg') 2 img1 = cv.blur(img,(10,10)) 3 cv.imshow('img',img) 4 cv.imshow('img1',img1) 5 cv.waitKey(0) 6 cv.destroyAllWindows()
均值模糊函数blur():
定义:blur(src,ksize,dst=None, anchor=None, borderType=None)
定义是有5个参数,但最后三个均为none,所以也就2个参数
src:要处理的原图像
ksize: 必须是奇数卷积核,周围关联的像素的范围:代码中(5,5)就是5*5的大小,就是计算这些范围内的均值来确定中心位置的大小
二、中值模糊mediablur
中值滤波模板就是用卷积框中像素的中值代替中心值,达到去噪声的目的。 这个模板一般用于去除椒盐噪声。 前面的滤波器都是用计算得到的一个新值来取代中心像素的值,而中值滤波是用中心像素周围(也可以使他本身)的值来取代他,卷积核的大小也是个奇数。
1 img = cv.imread('11.jpg') 2 gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 3 cv.imshow('gray',gray) 4 for i in range(2000): 5 x = np.random.randint(0,gray.shape[0]) 6 y = np.random.randint(0,gray.shape[1]) 7 gray[x,y] = 255 8 cv.imshow('new_gray',gray) 9 dst = cv.medianBlur(gray,9) #注意,中值模糊的ksize一个数字就可以了,这里是9*9 10 cv.imshow('dst',dst) 11 cv.waitKey(0) 12 cv.destroyAllWindows()
中值模糊函数medianBlur():
定义:medianBlur(src, ksize, dst=None)
ksize与blur()函数不同,不是矩阵,而是一个数字,例如为5,就表示了5*5的方阵
可以看到中值滤波对于这些白点噪声的去除是非常的好的。
三、高斯模糊GaussianBlur
1、原理
2、原理代码
def clamp(pv): #使我们的随机值在0-255之间 if pv > 255: return 255 elif pv < 0: return 0 else: return pv import cv2 as cv import numpy as np def gaussian_noise(image): #对图像加上高斯噪声 h,w,c = image.shape for row in range(h): #十分耗时 for col in range(w): s = np.random.normal(0,20,3) #产生3个随机值,符合正态分布,第一个参数是概率分布的均值,对应分布中心,,第二个是概率分布的标准差,越小越瘦高,第三个是输出的值个数 b = image[row,col,0] #blue g = image[row,col,1] #green r = image[row,col,2] #red image[row,col,0] = clamp(b+s[0]) #为什么像素值是整数的怎么会和float相加呢? image[row,col,1] = clamp(g+s[1]) image[row,col,2] = clamp(r+s[2]) cv.imshow("noise image",image) src = cv.imread("./1.png") #读取图片 cv.namedWindow("input image",cv.WINDOW_AUTOSIZE) #创建GUI窗口,形式为自适应 cv.imshow("input image",src) #通过名字将图像 gaussian_noise(src) cv.waitKey(0) #等待用户操作,里面等待参数是毫秒,我们填写0,代表是永远,等待用户操作 cv.destroyAllWindows() #销毁所有窗口
推文:从np.random.normal()到正态分布的拟合
3、使用opencv高斯模糊
高斯平滑函数GaussianBlur()
定义:GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)
src,输入图像,即源图像,填Mat类的对象即可。它可以是单独的任意通道数的图片,但需要注意,图片深度应该为CV_8U,CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
dst,即目标图像,需要和源图片有一样的尺寸和类型。比如可以用Mat::Clone,以源图片为模板,来初始化得到如假包换的目标图。
ksize,高斯内核的大小。其中ksize.width和ksize.height可以不同,但他们都必须为正数和奇数(并不能理解)。或者,它们可以是零的,它们都是由sigma计算而来。
sigmaX,表示高斯核函数在X方向的的标准偏差。 根据这个可以获取sigmaY,若是sigmaX和sigmaY都没有则根据ksize获取
sigmaY,表示高斯核函数在Y方向的的标准偏差。若sigmaY为零,就将它设为sigmaX,如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height计算出来。
为了结果的正确性着想,最好是把第三个参数Size,第四个参数sigmaX和第五个参数sigmaY全部指定到。
borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
1 img = cv.imread('11.jpg') 2 gaosi = cv.GaussianBlur(img,(0,0),15) #(0,0),然后根据sigmaX=15自动计算ksize 3 cv.imshow('img',img) 4 cv.imshow('gaosi',gaosi) 5 cv.waitKey(0) 6 cv.destroyAllWindows()
4、对高斯噪声图进行高斯模糊(发现高斯噪声的影响不大,高斯模糊对其有抑制作用)
img = cv.imread('11.jpg') cv.imshow('image',img) gaosi_noise(img) gaosi = cv.GaussianBlur(img,(0,0),10) cv.imshow('gaosi',gaosi) cv.waitKey(0) cv.destroyAllWindows()
四、边缘保留滤波EPF
OpenCV经典的两种实现EPF方法:高斯双边和均值迁移
1、双边模糊
只模糊上半部分,下半部分差异太大,没有模糊
差异越大,越会完整保留
双边滤波函数bilateralFilter():
定义:bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None)
值域和空域的两个方差sigma可以简单的设置为相等,小于10,无太大效果,大于150效果太强,像卡通片似的。
滤波器尺寸d:大于5将较慢(5 forreal-time),d=9,for off-lineapplications,d 是像素邻域“直径”。计算的半径,半径之内的像数都会被纳入计算,如果提供-1或者0,会从后面的参数sigmaSpace中自动计算。
Sigma_color(颜色标准差):颜色空间过滤器的sigma值,这个参数的值越大,表明该像素邻域内有越宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
Sigma_space(空间标准差):坐标空间中滤波器的sigma值,如果该值较大,则意味着颜色相近的较远的像素将相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色。当d>0时,d指定了邻域大小且与sigmaSpace五官,否则d正比于sigmaSpace.
双边滤波的内在想法是:在图像的值域(range)上做传统滤波器在空域(domain)上做的工作。空域滤波对空间上邻近的点进行加权平均,加权系数随着距离的增加而减少;值域滤波则是对像素值相近的点进行加权平均,加权系数随着值差的增大而减少。
想要得到比较好的结果,3/4/5参数最好都指定。d>5那么计算会很慢,所以一般都设置为d=5,如果少数情况需要去除比较大的噪声,那么d=9,要去的较好的平滑效果,最好在9附近。
d或者sigma_space设置的越大,包含的范围越大,耗时越长
1 def bi_demo(image): 2 dst = cv.bilateralFilter(image,0,100,15) #第二个参数d是distinct,我们若是输入了d,会根据其去算第3或4个参数,我们最好是使用第3或4个参数反算d,先设为0 3 cv.imshow("dst",dst) 4 5 src = cv.imread("1.jpg") #读取图片 6 cv.namedWindow("img",cv.WINDOW_AUTOSIZE) #创建GUI窗口,形式为自适应 7 cv.imshow("img",src) #通过名字将图像和窗口联系 8 bi_demo(src) 9 cv.waitKey(0) #等待用户操作,里面等待参数是毫秒,我们填写0,代表是永远,等待用户操作 10 cv.destroyAllWindows() #销毁所有窗口
若是高斯模糊,则整体都会模糊掉,实现滤镜效果。
2、均值迁移
推文:Opencv均值漂移pyrMeanShiftFiltering彩色图像分割流程剖析
meanShfit均值漂移算法是一种通用的聚类算法,它的基本原理是:对于给定的一定数量样本,任选其中一个样本,以该样本为中心点划定一个圆形区域,求取该圆形区域内样本的质心,即密度最大处的点,再以该点为中心继续执行上述迭代过程,直至最终收敛。
可以利用均值偏移算法的这个特性,实现彩色图像分割,Opencv中对应的函数是pyrMeanShiftFiltering。这个函数严格来说并不是图像的分割,而是图像在色彩层面的平滑滤波,它可以中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的颜色区域,所以在Opencv中它的后缀是滤波“Filter”,而不是分割“segment”。先列一下这个函数,再说一下它“分割”彩色图像的实现过程。
pyrMeanShiftFiltering(src, sp, sr, dst=None, maxLevel=None, termcrit=None):
第一个参数src,输入图像,8位,三通道的彩色图像,并不要求必须是RGB格式,HSV、YUV等Opencv中的彩色图像格式均可;
第二个参数sp,定义的漂移物理空间半径大小; #越大,细节丢失越多
第三个参数sr,定义的漂移色彩空间半径大小;
第四个参数dst,输出图像,跟输入src有同样的大小和数据格式;
第五个参数maxLevel,定义金字塔的最大层数;
第六个参数termcrit,定义的漂移迭代终止条件,可以设置为迭代次数满足终止,迭代目标与中心点偏差满足终止,或者两者的结合;
dst = cv.pyrMeanShiftFiltering(image,10,50) #一般这三个参数就可以了
五、自定义模糊fileter 2D
推文:图像滤波函数imfilter函数的应用及其扩展
Opencv提供的一个通用的2D滤波函数为cv2.filter2D(),
滤波函数的使用需要一个核模板,对图像的滤波操作过程为:将和模板放在图像的一个像素A上,求与之对应的图像上的每个像素点的和,
核不同,得到的结果不同,而滤波的使用核心也是对于这个核模板的使用,需要注意的是,该滤波函数是单通道运算的,
也就是说对于彩色图像的滤波,需要将彩色图像的各个通道提取出来,对各个通道分别滤波才行。
filter2D(src,ddepth,kernel):
ddepth:深度,输入值为-1时,目标图像和原图像深度保持一致
kernel: 卷积核(或者是相关核),一个单通道浮点型矩阵
1、实现中值模糊
1 img = cv.imread('1.jpg') 2 cv.imshow('img',img) 3 gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 4 cv.imshow('gray',gray) 5 kernel = np.ones([5,5],np.float32)/25
6 dst = cv.filter2D(gray,-1,kernel) 7 cv.imshow('dst',dst) 8 cv.waitKey(0) 9 cv.destroyAllWindows()
声明二维数组5*5,初始化1,保证值不溢出,除以数组大小,实现中值模糊,自定义卷积核的算子
上述生成的5*5核模板其实就是一个均值滤波。,当我们是/25就是中值滤波,归一化处理
2、实现锐化处理
使用的kernel是:,实现锐化处理,提高图像的对比度,提高立体感,轮廓更加清晰。
img = cv.imread('1.jpg') cv.imshow('img',img) kernel = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]],np.float32) dst = cv.filter2D(img,-1,kernel) cv.imshow('dst',dst) cv.waitKey(0) cv.destroyAllWindows()