实验内容
2-1:实现图像的高斯滤波处理
实验要求:
1)通过调整高斯函数的标准差(sigma)来控制平滑程度;
给定函数:void Gaussian(const MyImage &input, MyImage &output, double sigma);
2)滤波窗口大小取为[6sigma-1]/22+1,[.]表示取整;
3)利用二维高斯函数的行列可分离性进行加速;
先对每行进行一维高斯滤波,再对结果的每列进行同样的一维高斯滤波;
空间滤波=图像卷积;
高斯滤波=以高斯函数为卷积核的图像卷积。
2-2:实现图像的联合双边滤波处理
实验要求:
给定函数:function im = jbf(D,C,w, sigma_f, sigma_g)
其中:D为输入图像;C为引导图像;W为滤波窗口大小;
sigma_f 为spatial kernel标准差;
sigma_g为range kernel 标准差;
给定公式:
其中:p是q的邻域 中的一个像素。 f和g是空间和距离内核,通常以高斯的形式表示,I是输入图像。
f 是空间滤波器内核,定义为:exp([-d_f2]/[2*sigma_f2])
其中:d_f 为输入图像I的像素位置差,sigma_f为空间滤波核函数的标准差
g是距离滤波器内核,定义为:exp([-d_g2]/[2*sigma_g2])
其中:d_g为引导图像 的像素灰度值差,sigma_g为滤波核函数的标准差
输入图像I下采样(1/2)得到LR低分辨率图像,再由LR图像上采样2倍得到引导图像。
注:图像缩放采用双线性插值。
实验过程:
2.1 高斯滤波处理
使用cv2做高斯模糊,只要一行代码调用GaussianBlur函数,给出高斯矩阵的尺寸和标准差就可以,也可以自己构造高斯核,相关函数为:cv2.GaussianKernel()。
根据要求sigma自己规定,窗口大小用[6*sigma-1]/2 *2+1计算,刚开始在想这个为什么要先除2再乘2,结果在python中因为自动转换类型没有区别,但是在C++里就不一样了,他会使这个式子永远是基数,所以在python中跑出来报错,输入参数只能是大于0 的奇数;修改后可以正常运行,代码如下:
img = cv2.imread(r"F:\CVcode\lab21\a.jpg")
sigma = float(input())
ksize = int((int(6*sigma - 1)) /2 )*2 + 1
if sigma <= 0: #扩展的公式,如果 sigma 非法
sigma = int(0.3*((ksize-1)*0.5 - 1) + 0.8)
blur = cv2.GaussianBlur(img,(ksize,ksize),sigma)
while(1):
cv2.imshow('image',img)
cv2.imshow('blur',blur)
k=cv2.waitKey(1)
if k == ord('q'):#按q键退出
break
cv2.destroyAllWindows()1
2
3
4
5
6
7
8
9
10
11
12
13
14
当Alpha = 0.8时ksize = 3,变化不是很大:
当Alpha = 1.5 时ksize = 9,有明显模糊感:
趋势是高斯矩阵尺寸和标准差越大,处理后的图片越模糊;
接下来利用二维高斯函数的行列可分离性进行加速(高斯卷积算子是可分离卷积核):
高斯卷积核可以分成一维水平方向上的高斯核和一维垂直方向上的高斯核,或者反过来,即满足交换律。使用Mat getGaussianKernel(int ksize,doable sigma,int ktype = CV_64F)返回ksize*1的垂直方向上的高斯核,而对于一位数水平方向上的高斯核,只需要对垂直方向上的转置处理即可。
def gaussBlur(image,sigma,H,W,_boundary = 'fill',_fillvalue = 0):
'''
通过内置函数得到高斯算子
'''
gaussKenrnel_x = np.array(cv2.getGaussianKernel(sigma,1,W))
gaussBlur_x = signal.convolve2d(image,gaussKenrnel_x,mode='same',boundary = _boundary,fillvalue=_fillvalue)
gaussKenrnel_y = np.array(cv2.getGaussianKernel(sigma,H,1))
gaussBlur_xy = signal.convolve2d(gaussBlur_x,gaussKenrnel_y,mode='same',boundary = _boundary,fillvalue=_fillvalue)
return gaussBlur_xy1
2
3
4
5
6
7
8
9
但根据老师给的实验要求好像是要自己写函数得到高斯平滑算子,下面是代码:
def getGaussKernel(sigma,H,W):
# 第一步:构建高斯矩阵gaussMatrix
gaussMatrix = np.zeros([H,W],np.float32)
#得到中心点的位置
cH = (H-1)/2
cW = (W-1)/2
#计算1/(2*pi*sigma^2)
coefficient = 1.0/(2*np.pi*math.pow(sigma,2))
for r in range(H):
for c in range(W):
norm2 = math.pow(r-cH,2) + math.pow(c-cW,2)
gaussMatrix[r][c] = coefficient*math.exp(-norm2/(2*math.pow(sigma,2)))
#第二步:计算高斯矩阵的和
sumGM = np.sum(gaussMatrix)
#第三步:归一化,gaussMatrix/sumGM
gaussKernel = gaussMatrix/sumGM
return gaussKernel1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
然后在主代码改一行就可。
2.2 联合双边滤波处理
第一步:双线性插值的放缩函数
只是改变图像的尺寸大小,cv2.resize()可以实现这个功能。默认情况下所有改变图像尺寸大小的操作使用的是插值法都是cv2.INTER_LINEAR(双线性插值):
然后再放大2倍就可以得到引导图像(左为引导图,右为原图):
第二步:联合双边滤波
通过定义函数jbf实现联合双边滤波,I代表输入矩阵,H/W分别代表权重模板的高和宽,都为奇数,sigma_g和sigma_d分别代表空间距离权重模板和相似性权重模板的标准差,代码如下:
主函数(由于jbf函数定义时是一个通道一个通道处理,所以在主函数中使用了split分离通道分别处理后merge)先是只对灰度值图像处理,得到左图,然后想显示彩图就用了opencv自带的split,在执行时明显速度慢了很多不推荐用,效果图为右图:
如果哪位大佬有更好的方法请多指教呀!python写的我想哭了,大家都是C++和matlab,只想用python的我好难啊(T_T)