简体   繁体   English

如何将Gabor滤镜应用于具有六边形采样的图像?

[英]How to apply a Gabor filter to an image with hexagonal sampling?

I want to use a Gabor filter as an interpolation method after the conversion of a square-sampled image to an hexagonally-sampled image. 在将正方形采样的图像转换为六角形采样的图像之后,我想使用Gabor滤波器作为插值方法。

Can I use the normal Gabor filter implementation in an hexagonally-sampled image? 我可以在六边形采样的图像中使用普通的Gabor滤波器实现吗? Or should I modify the code? 还是应该修改代码? If yes, then what part of the Gabor function should I modify for an hexagonally-sampled image? 如果是,那么我应该为六角形采样的图像修改Gabor函数的哪一部分?

I've tried implementing the algorithm but I just can't get it right. 我已经尝试实现算法,但是我做对了。 Here's a code for Gabor filtering taken from GitHub . 这是来自GitHub的 Gabor过滤代码。

import numpy as np
import cv2

# cv2.getGaborKernel(ksize, sigma, theta, lambda, gamma, psi, ktype)
# ksize - size of gabor filter (n, n)
# sigma - standard deviation of the gaussian function
# theta - orientation of the normal to the parallel stripes
# lambda - wavelength of the sunusoidal factor
# gamma - spatial aspect ratio
# psi - phase offset
# ktype - type and range of values that each pixel in the gabor kernel can hold

g_kernel = cv2.getGaborKernel((21, 21), 8.0, np.pi/4, 10.0, 0.5, 0, ktype=cv2.CV_32F)

img = cv2.imread('test.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
filtered_img = cv2.filter2D(img, cv2.CV_8UC3, g_kernel)

cv2.imshow('image', img)
cv2.imshow('filtered image', filtered_img)

h, w = g_kernel.shape[:2]
g_kernel = cv2.resize(g_kernel, (3*w, 3*h), interpolation=cv2.INTER_CUBIC)
cv2.imshow('gabor kernel (resized)', g_kernel)
cv2.waitKey(0)
cv2.destroyAllWindows()

Assuming the ordinary data structure for a hexagonal grid, you can probably apply a 2d filter to a hexagonal-pixel image, but you need to create a filter that is evaluated at the appropriate coordinates. 假定六边形网格的常规数据结构,您可能可以将2d滤镜应用于六边形像素图像,但是您需要创建一个在适当坐标下求值的滤镜。 You see, a 2d filter is just a matrix of values generated by evaluating a function over xy coordinates in a grid. 您会看到,二维过滤器只是通过对网格中xy坐标上的函数求值而生成的值的矩阵。 So, a 5x5 Gabor filter matrix is just a Gabor function evaluated at the xy coordinates shown here: 因此,一个5x5的Gabor滤波器矩阵只是在如下所示的xy坐标处评估的Gabor函数:

在此处输入图片说明

Pixels are "equally spaced" so we can simply pick the distance between each point in the grid to be 1 in x and 1 in y, and we get the Gabor function evaluated at the center of each pixel. 像素“等距”,因此我们可以简单地选择网格中每个点之间的距离,以x为1,以y为1,然后在每个像素的中心进行Gabor函数求值。

However, hexagonal pixels are not arranged this way. 然而,六边形像素没有以这种方式布置。 The centers of hexagonal pixels are arranged as thus: 六角形像素的中心按以下方式排列:

在此处输入图片说明

Thus, in order to apply a filter to this, we need to evaluate the appropriate function at these points. 因此,为了对此应用过滤器,我们需要在这些点上评估适当的功能。 Since the stock filters have been evaluated on a rectangular grid, we cannot use them (although they will produce something that probably looks reasonable). 由于股票过滤器是在矩形网格上评估的,因此我们无法使用它们(尽管它们会产生看起来合理的东西)。

Fortunately, the transformation is relatively easy. 幸运的是,转换相对容易。 If we assume the vertical distance between two rows is 1, then the coordinates are almost just an np.arange . 如果我们假设两行之间的垂直距离为1,则坐标几乎只是np.arange

import numpy as np
import matplotlib.pyplot as plt

ALTERNATE_ROW_SHIFT = 0+np.sqrt(3)/3 # every other row is "offset" by half a hexagon.  If the sides are len 2/3, the shift is root 3 over 3

def hex_grid(rect_grid):
    rect_grid = np.copy(rect_grid)
    rect_grid[0,:,1::2] += ALTERNATE_ROW_SHIFT
    return rect_grid

If you have access to the function that creates your filter, there will usually be some logic that creates a rectangular grid on which the function is subsequently evaluated. 如果您有权访问创建过滤器的函数,通常会有一些逻辑可以创建一个矩形网格,然后在该矩形网格上对函数进行评估。 Drop the hex_grid function in on the line after to get hexagonally-spaced coordinates instead. 之后,将hex_grid函数放到该行上,以获取六角形间隔的坐标。

For example, the wikipedia page on Gabor filters has a python implementation to create a Gabor filter, shown here: 例如, Gabor过滤器上的Wikipedia页面具有一个创建Gabor过滤的python实现,如下所示:

def gabor_fn(sigma, theta, Lambda, psi, gamma):
    sigma_x = sigma
    sigma_y = float(sigma) / gamma

    # Bounding box
    nstds = 3 # Number of standard deviation sigma
    xmax = max(abs(nstds * sigma_x * np.cos(theta)), abs(nstds * sigma_y * np.sin(theta)))
    xmax = np.ceil(max(1, xmax))
    ymax = max(abs(nstds * sigma_x * np.sin(theta)), abs(nstds * sigma_y * np.cos(theta)))
    ymax = np.ceil(max(1, ymax))
    xmin = -xmax
    ymin = -ymax

    (y,x) = np.meshgrid(np.arange(ymin, ymax + 1), np.arange(xmin, xmax + 1))

    # Rotation 
    x_theta = x * np.cos(theta) + y * np.sin(theta)
    y_theta = -x * np.sin(theta) + y * np.cos(theta)

    gb = np.exp(-.5 * (x_theta ** 2 / sigma_x ** 2 + y_theta ** 2 / sigma_y ** 2)) * np.cos(2 * np.pi / Lambda * x_theta + psi)
    return gb

Note the line involving a np.meshgrid . 请注意涉及np.meshgrid的行。 This creates a rectagular grid with spacing 1 that is used on subsequent lines. 这将创建一个间距为1的矩形网格,该网格将用于后续的行。 We can simply transform those coordinates to create a new hex_gabor function (Note that this is 95% identical to the gabor_fn code): 我们可以简单地转换这些坐标以创建一个新的hex_gabor函数(请注意,这与gabor_fn代码具有95%的相同性):

def hex_gabor_fn(sigma, theta, Lambda, psi, gamma):
    sigma_x = sigma
    sigma_y = float(sigma) / gamma

    # Bounding box
    nstds = 3 # Number of standard deviation sigma
    xmax = max(abs(nstds * sigma_x * np.cos(theta)), abs(nstds * sigma_y * np.sin(theta)))
    xmax = np.ceil(max(1, xmax))
    ymax = max(abs(nstds * sigma_x * np.sin(theta)), abs(nstds * sigma_y * np.cos(theta)))
    ymax = np.ceil(max(1, ymax))
    xmin = -xmax
    ymin = -ymax

    yx = np.meshgrid(np.arange(ymin, ymax + 1), np.arange(xmin, xmax + 1))
    (y,x) = hex_grid(yx)

    # Rotation 
    x_theta = x * np.cos(theta) + y * np.sin(theta)
    y_theta = -x * np.sin(theta) + y * np.cos(theta)

    gb = np.exp(-.5 * (x_theta ** 2 / sigma_x ** 2 + y_theta ** 2 / sigma_y ** 2)) * np.cos(2 * np.pi / Lambda * x_theta + psi)
    return gb

if __name__ == "__main__":
    g = gabor_fn(4,np.pi/4,4,0,2)
    hg = hex_gabor_fn(4,np.pi/4,4,0,2)
    plt.imshow(g)
    plt.show()
    plt.imshow(hg)
    plt.show() 

You should be able to drop the resulting kernel into this line cv2.filter2D(img, cv2.CV_8UC3, g_kernel) . 您应该能够将生成的内核放入此行cv2.filter2D(img, cv2.CV_8UC3, g_kernel)

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

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