使用tensorflow,opencv,scipy实现高斯模糊

概念

图像的高斯模糊就是图像与高斯权重(高斯核)做卷积。

简单来说,就是把每个像素点变成周围像素点的加权平均。


对比

本文展示三种不同软件包tensorflow,opencv,scipy实现高斯模糊的方法。代码见Gaussian blur-tensorflow,opencv,scipy.

tensorflow版本可以嵌入到深度学习模型的代码中,方便求导等运算。

opencv 相对scipy方便的多:灰度图和彩色图可使用同一函数,并且可直接指定高斯核大小。

几种实现方法的简要对比:

灰度图(单通道) 彩色图(多通道) 备注
tensorflow tf.nn.conv2dtf tf.nn.conv2d 多通道图分别卷积,然后合并
opencv cv.GaussianBlurcv cv.GaussianBlur
scipy filters.gaussian_filterfilters filters.gaussian_filter 多通道图分别卷积,然后合并。核大小只能间接指定。


过程

高斯核的计算分成两步: (1) 计算正态权重 (2) 归一化正态权重得到高斯核。

正态权重$G$的计算公式

其中

  • $\sigma$是模糊因子(blurring factor). 越大模糊的越厉害;
  • $x$是水平方向上像素点离中心点的距离;
  • $y$是竖直方向上像素点离中心点的距离。

一个$3\times3$的卷积核,假设其中心点坐标为$(x_c,y_c)=(0,0)$, 则其相邻像素点坐标$(x,y)$如下:

假设$\sigma=1.5$, 则$G$的计算结果如下:

gaus

image from How to program a Gaussian Blur without using 3rd party libraries

对$G$做归一化,可得高斯核$K​$为(保留2位小数):

通用高斯核的python实现

1
2
3
4
5
6
7
8
9
10
11
12
def gaussian_kernel(size=5,sigma=2):
'''
size: int,一般取为奇数
sigma: blur factor

return: (normalized) Gaussian kernel,大小 size*size
'''
x_points = np.arange(-(size-1)//2,(size-1)//2+1,1)
y_points = x_points[::-1]
xs,ys = np.meshgrid(x_points,y_points)
kernel = np.exp(-(xs**2+ys**2)/(2*sigma**2))/(2*np.pi*sigma**2)
return kernel/kernel.sum()

可视化高斯核

1
2
plt.imshow(gaussian_kernel(20,5),cmap='Reds')
plt.colorbar()

灰度图高斯模糊

将图形与$K$做卷积,得到模糊图。

彩色图(RGB)高斯模糊

将原图的3个通道分别与高斯核$K$做卷积,得到不同通道的模糊图,然后合并得到最终模糊图。


实现

tensorflow

灰度图

  1. 计算kernel的值,然后将其扩展为tensorflow可用的维度

    1
    2
    kernel = gaussian_kernel(size=10,sigma=5)
    kernel = kernel[:, :, np.newaxis, np.newaxis] # height,width, channel_in, channel_out
  2. 灰度图高斯卷积

    1
    2
    x = tf.placeholder(tf.float32,shape=(None,200,300,1))    # (batch_size, height, width, channel)
    x_blur = tf.nn.conv2d(x, kernel, strides=[1, 1, 1, 1], padding='SAME')
  3. 计算模糊图(图像image_gray也需要调整为tensorflow可用的维度

    1
    2
    3
    4
    s = tf.InteractiveSession()
    image_batch = image_gray[np.newaxis,:,:,np.newaxis] # (batch_size, height, width, channel)
    blur_imgs = s.run(x_blur,feed_dict={x:image_batch})
    s.close()
  4. 可视化结果

彩色图

第2步需要将原图分开为单通道图xr,xg,xb, 然后分别做卷积得到xr_blur,xg_blur,xb_blur, 最后合并得到彩色图的模糊图xrgb_blur:

1
2
3
4
5
6
7
x = tf.placeholder(tf.float32,shape=(None,200,300,3))    # (batch_size, height, width, channel)
xr,xg,xb =tf.expand_dims(x[:,:,:,0],-1),tf.expand_dims(x[:,:,:,1],-1),tf.expand_dims(x[:,:,:,2],-1)

xr_blur = tf.nn.conv2d(xr, kernel, strides=[1, 1, 1, 1], padding='SAME')
xg_blur = tf.nn.conv2d(xg, kernel, strides=[1, 1, 1, 1], padding='SAME')
xb_blur = tf.nn.conv2d(xb, kernel, strides=[1, 1, 1, 1], padding='SAME')
xrgb_blur = tf.concat([xr_blur,xg_blur,xb_blur],axis=3)

结果:

opencv

使用cv.GaussianBlur。灰度图和彩色图都使用该函数。

可以指定高斯核大小及模糊因子大小。

1
2
3
4
5
import cv2 as cv

size = 5
sigma = 5
blur = cv.GaussianBlur(image,(size,size),sigma)

scipy

使用scipy.ndimage.filters.gaussian_filter.

灰度图可直接使用gaussian_filter, 彩色图需要分别对不同通道做模糊处理。

该函数通过truncate参数指定高斯核的大小$s$,truncate与$s$和模糊因子$\sigma$的关系是truncate$=(s-3)/ (2\sigma)​$解释.

高斯模糊函数定义为

1
2
3
4
5
6
7
8
9
10
11
12
13
def gaussian_blur(image, sigma=2, size = 3):
'''
image: [h,w,c]
size: 高斯核大小
sigma:模糊因子
'''
# compute the truncate using size
t = (((size - 1)/2)-0.5)/sigma
im = np.zeros_like(image)
channels = image.shape[-1]
for i in range(channels):
im[:, :, i] = filters.gaussian_filter(image[:, :, i], sigma,truncate=t)
return im

结果:




解释. 参考https://stackoverflow.com/questions/25216382/gaussian-filter-in-scipy
tf. import tensorflow as tf
cv. import cv2 as cv
filters. from scipy.ndimage import filters