简体   繁体   English

使用FFT的高斯图像滤波

[英]Gaussian Image filtering using FFT

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). 对于图像分割,我使用OpenCV的GaussianBlur的高斯特征差异(范围从0.8到8.43,指数步长为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). 我的图像尺寸为4096 x 2160,所以这需要相当长的时间(在一个核心8秒,处理视频时相当长)。

Can you give me any suggestions on how to speed things up? 你能给我一些关于如何加快速度的建议吗? Currently I am trying to implement Gaussian filtering in FFT. 目前我正在尝试在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))

The problem here is that imagep and imageq are shifted versions of each other. 这里的问题是imagepimageq是彼此的移位版本。 Secondly, as the Fourier of a Gaussian is also a Gaussian, how can I compute ftkernel in a straight-forward manner? 其次,由于高斯的傅立叶也是高斯的,我如何以直接的方式计算ftkernel


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

The L2 pixel difference looks quite good for n=4: 对于n = 4,L2像素差异看起来非常好:

I have also done the speed comparison for different sigma's: 我也为不同的sigma做了速度比较:

A Gaussian filter can be approximated by a cascade of box (averaging) filters, as described in section II of Fast Almost-Gaussian Filtering . 高斯滤波器可以通过级联的盒(平均)滤波器来近似,如快速几乎高斯滤波的第II部分所述。 This method requires using the Integral Image , and allows faster application of (near) Gaussian filtering, especially for high blur cases. 该方法需要使用积分图像 ,并允许更快地应用(近)高斯滤波,尤其是对于高模糊情况。

The code below demonstrates how one might do this using the steps from the paper linked above. 下面的代码演示了如何使用上面链接的论文中的步骤执行此操作。

Let the filter radius be 8.43 as in the question. 如问题所示,让滤波器半径为8.43。

sigma_g = 8.43

The number of successive applications of the box filter determines the level of approximation. 盒式滤波器的连续应用的数量决定了近似的水平。 For this example I set it to 5: 在本例中,我将其设置为5:

n = 5

First, find the ideal width of the box filter using equation 3: 首先,使用等式3找到箱式滤波器的理想宽度:

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

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. 对于对称性,滤波器需要具有奇数长度,长度相差2。 The code below takes w and finds the nearest odd integers. 下面的代码取w并找到最接近的奇数整数。 (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

If n successive applications are desired, then m are performed using the first filter with width wu and (nm) are performed with the second, with width wl. 如果需要n次连续应用,则使用宽度为wu的第一滤波器执行m,并且使用宽度为w1的第二滤波器执行(nm)。 Equation 5 shows how to calculate m: 公式5显示了如何计算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. 这应该更快,特别是对于高斯模糊半径非常高的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM