1
votes

I want to use a Gabor filter as an interpolation method after the conversion of a square-sampled image to an hexagonally-sampled image.

Can I use the normal Gabor filter implementation in an hexagonally-sampled image? Or should I modify the code? If yes, then what part of the Gabor function should I modify for an hexagonally-sampled image?

I've tried implementing the algorithm but I just can't get it right. Here's a code for Gabor filtering taken from GitHub.

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()
1
Oh, Im sorry. I shouldve reviewes my question. Thanks tho. . Hmm do you have any idea about my question sir?? Thanks.franco jigo pacana
I sincerely doubt it's going to be so easy. You'll just need to roll your own. All of these image processing libraries are doing matrix multiplication and slicing. None of that translates to hex grids in a way that you could just "patch up." Notably, that convolution operation is just doing some slicing and multiplying over squares. Speaking of which, what is the shape of your filter? Do you want it to be hexagonal or square?Him
@Scott i have already found an implementation for Converting Square image to Hexagonal. I am stuck after that since the imsge need interpolation after the transformation so I want to apply hex-gabor to it and wavelet denoising. So is it ok to apply a square shaped filtee to a Hexagonally sampled image or not? Thank you I really appreciate your reply. Ive been looking everywhere but all I know is i should implement this on my own since there is no open library for hexagonal image processing.franco jigo pacana
What is the orientation of your hexagonal grid? (i.e. do the hexagons' flat edges go horizonal or vertical?)Him
So, new questions come up: (1) How do you use a Gabor filter for interpolation? I have never heard of such a thing. Are you sure you need a Gabor filer? Maybe you confuse it with something else? (2) "I've tried implementing the algorithm", yet you post code you've copied from elsewhere. Why don't you show your attempts? It would be helpful to know how far you got, and see where the problem is. Also, it will help us see how you implemented the hexagonal sampling.Cris Luengo

1 Answers

0
votes

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. You see, a 2d filter is just a matrix of values generated by evaluating a function over xy coordinates in a grid. So, a 5x5 Gabor filter matrix is just a Gabor function evaluated at the xy coordinates shown here:

enter image description here

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.

However, hexagonal pixels are not arranged this way. The centers of hexagonal pixels are arranged as thus:

enter image description here

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.

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.

For example, the wikipedia page on Gabor filters has a python implementation to create a Gabor filter, shown here:

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. This creates a rectagular grid with spacing 1 that is used on subsequent lines. We can simply transform those coordinates to create a new hex_gabor function (Note that this is 95% identical to the gabor_fn code):

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).