使用FFT进行高斯图像滤波 [英] Gaussian Image filtering using FFT

查看:125
本文介绍了使用FFT进行高斯图像滤波的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于图像分割,我使用OpenCV的GaussianBlur(范围为0.8到8.43,指数步长为1.4)使用高斯特征差.我的图像尺寸为4096 x 2160,因此需要花费一些时间(一个核心8秒,这在处理视频时会很长).

For image segmentation I use Difference of Gaussian features using OpenCV's GaussianBlur (ranging from 0.8 to 8.43 with exponential step size of 1.4). My images are of size 4096 x 2160 so this takes quite some time (on one core 8 seconds, which is quite long when processing a video).

您能给我一些有关如何加快速度的建议吗?目前,我正在尝试在FFT中实现高斯滤波.到目前为止,我有以下代码:

Can you give me any suggestions on how to speed things up? Currently I am trying to implement Gaussian filtering in FFT. I have the following code so far:

ftimage = np.fft.fft2(image)
ftimage = np.fft.fftshift(ftimage)
kernel = cv2.getGaussianKernel(11, 3)
kernel = kernel * kernel.T
ftkernel = np.fft.fftshift(np.fft.fft2(kernel, (h, w)))
ftimagep = ftimage * gmask
imagep = np.fft.ifft2(ftimagep)
imageq = cv2.GaussianBlur(image, (11,11), 3))

这里的问题是imagepimageq是彼此移位的版本. 其次,由于高斯的傅立叶也是高斯,我该如何直接计算ftkernel?

The problem here is that imagep and imageq are shifted versions of each other. Secondly, as the Fourier of a Gaussian is also a Gaussian, how can I compute ftkernel in a straight-forward manner?

对于以下答案: 我已经实现了近似过滤:

To the answer below: I have implemented approximate filtering:

 def approx_g(image, sigma_g, n=5):
      w = np.sqrt(12*sigma_g**2/n + 1)
      wu = np.ceil(w) if np.ceil(w) % 2 == 1 else np.ceil(w)+1
      wl = np.floor(w) if np.floor(w) % 2 == 1 else np.floor(w)-1
      if w == w//1:
          wl -= 2
          wu += 2
      m = round((12*sigma_g**2 - n*wl**2 - 4*n*wl - 3*n) / (-4*wl - 4))
      wl = int(wl)
      wu = int(wu)
      for num in range(0,int(m)):
          image = cv2.blur(image, (wl, wl))
      for num in range(0,int(n-m)):
          image = cv2.blur(image, (wu, wu))
      return image

对于n = 4,L2像素差异看起来相当不错:

The L2 pixel difference looks quite good for n=4:

我还对不同的sigma进行了速度比较:

I have also done the speed comparison for different sigma's:

推荐答案

高斯滤波器可以通过级联的框式(平均)滤波器来近似,如积分图像,并允许更快地应用(附近)的高斯滤波,尤其是在高模糊情况下.

A Gaussian filter can be approximated by a cascade of box (averaging) filters, as described in section II of Fast Almost-Gaussian Filtering. This method requires using the Integral Image, and allows faster application of (near) Gaussian filtering, especially for high blur cases.

如问题中所述,使过滤器半径为8.43.

Let the filter radius be 8.43 as in the question.

sigma_g = 8.43

盒式滤波器的连续应用次数决定了近似水平.在此示例中,我将其设置为5:

The number of successive applications of the box filter determines the level of approximation. For this example I set it to 5:

n = 5

首先,使用公式3找到盒式滤波器的理想宽度:

First, find the ideal width of the box filter using equation 3:

w = np.sqrt(12*sigma_g**2/n + 1)

如本文所述,使用两个不同大小的框式过滤器效果更好.为了对称,滤波器的长度必须为奇数,长度相差两个.下面的代码使用w并找到最接近的奇数整数. (可能写得更好):

As discussed in the paper, using two different size box filters works better. The filters need to be of odd length for symmetry, with lengths that differ by two. The code below takes w and finds the nearest odd integers. (it could probably be written better):

wu = np.ceil(w) if np.ceil(w) % 2 == 1 else np.ceil(w)+1
wl = np.floor(w) if np.floor(w) % 2 == 1 else np.floor(w)-1
if w == w//1:
    wl -= 2
    wu += 2

如果需要n个连续的应用程序,则使用宽度为wu的第一个过滤器执行m,使用宽度为wl的第二个过滤器执行(n-m).公式5显示了如何计算m:

If n successive applications are desired, then m are performed using the first filter with width wu and (n-m) are performed with the second, with width wl. Equation 5 shows how to calculate m:

m = round((12*sigma_g**2 - n*wl**2 - 4*n*wl - 3*n) / (-4*wl - 4))

接下来,用于计算水平和垂直积分图像的函数:

Next, the functions to calculate the integral image for both horizontal and vertical:

def integral_image_1d_hor(image):
    ''' Calculated the 1d horizontal integral
    image of an image.'''
    n1, n2 = np.shape(image)
    int_im = np.zeros((n1, n2))
    for row in range(0,n1):
        int_im[row,0] = image[row,0]

    for row in range(0,n1):
        for col in range(1,n2):
            int_im[row,col] = image[row,col] + int_im[row,col-1]

    return int_im


def integral_image_1d_ver(image):
    ''' Calculated the 1d vertical integral
        image of an image.'''
    n1, n2 = np.shape(image)
    int_im = np.zeros((n1, n2))
    for col in range(0,n2):
        int_im[0,col] = image[0,col]

    for col in range(0,n2):
        for row in range(1,n1):
            int_im[row,col] = image[row,col] + int_im[row-1,col]

    return int_im

要使用积分图像进行过滤,我具有以下功能:

To filter using the integral images I have these functions:

def box_1d_filter_hor(int_im_1d, width):
    w = int((width-1)/2)
    fil_im = np.zeros(np.shape(int_im_1d))
    pad = w
    int_im_1d = np.pad(int_im_1d, pad, 'constant')
    n1 = np.shape(int_im_1d)[0]
    n2 = np.shape(int_im_1d)[1]
    for row in range(pad, n1-pad):
        for col in range(pad, n2-pad):
            fil_im[row-pad,col-pad] = (int_im_1d[row,col+w]
                                    - int_im_1d[row,col-w-1])/width
    return fil_im


def box_1d_filter_ver(int_im_1d, width):
    w = int((width-1)/2)
    fil_im = np.zeros(np.shape(int_im_1d))
    pad = w
    int_im_1d = np.pad(int_im_1d, pad, 'constant')
    n1 = np.shape(int_im_1d)[0]
    n2 = np.shape(int_im_1d)[1]
    for col in range(pad, n2-pad):
        for row in range(pad, n1-pad):
            fil_im[row-pad,col-pad] = (int_im_1d[row+w,col]
                                    - int_im_1d[row-w-1,col])/width
    return fil_im

然后我定义了另外两个函数,用于处理水平和垂直方向的图像:

Then I define two more functions, for processing the image in the horizontal and vertical directions:

def process_hor(image, w):
    int_im = integral_image_1d_hor(image)
    fil_im = box_1d_filter_hor(int_im, w)
    return fil_im

def process_ver(image, w):
    int_im = integral_image_1d_ver(image)
    fil_im2 = box_1d_filter_ver(int_im, w)
    return fil_im2

最后,使用以下所有这些功能来近似高斯滤波,请使用以下功能:

Finally, using all these previous functions, to approximate gaussian filtering use the following function:

def approximate_gaussian(image, wl, wu, m, n):
    for num in range(0,int(m)):
        image = process_hor(image, wl)
        image = process_ver(image, wl)
    for num in range(0,int(n-m)):
        image = process_hor(image, wu)
        image = process_ver(image, wu)
    return image

我并没有真正处理图像的边缘,但是可以通过修改上面的功能进行调整.这应该更快一些,尤其是在高斯模糊半径很高的情况下.

I didn't really handle the edges of the image but that can be adjusted by modifying the functions above. This should be faster, especially for cases where the Gaussian blurring radius is very high.

这篇关于使用FFT进行高斯图像滤波的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆