Gabor Filter in Edge Detection is a technique for improving image edge detection. Previously in our articles, we explored a simple technique for edge detection using OpenCV – Canny Edge Detection. Apart from reading our image, using only few lines of code we obtained mediocre results. Consequently, we want to explore how to get more accurate results. Upon doing a Google Search on the internet, you will find articles about Gabor Filter that fall into two camps. On one hand are articles that elaborate the complex college level math behind the theory. On the other hand are articles describing results of applying Gabor Filters but fall short of showing how to do so. As a result, we want to show how we can use Gabor Filter in edge detection without all the math.
Concepts
Think of Gabor Filters as a sine wave imposed on a bell curve (Gaussian) in 2D space. In 2D space, the sine wave is directional. Meanwhile the bell curve peaks at a point and tapers off in all directions. Combining the two results in a directional wave that focuses on a point in space within a local area. We suggest searching in your favorite search engine for an image of the Gabor Filter to better visualize this. When applying this to an image, we expose several favorable properties:
- It emphasizes edge pixels.
- Pixels immediately adjacent become suppressed.
- It is directional
- Pixels farther away have less influence (Local area)
Since the filter exhibits both a sine wave and bell curve nature, parameters common to both affect our filter:
- sigma σ – Standard Deviation – Property of our bell curve. Smaller values emphasize values closer to the center
- theta θ – Direction – Identifies direction of our sine wave
- lambda λ – Wavelength – Distance between peaks in our sine wave
- gamma γ – Ellipticity – Determines how elliptic our 2D bell curve is
- psi φ – Offset – Defines the phase offset of our sine wave
At the heart of applying Gabor Filter in edge detection is applying each filter (for each direction) to the pixels of an image. Subsequently, we superimpose each result to create a final image. If you are interested to explore more the parameters, an article from University of Groningen in Netherlands explains this further.
Importing Libraries and OpenCV
Firstly as in all our articles, we begin by importing OpenCV and declaring a helper function. Again, the helper function is to help us display the image using matplotlib in Jupyter notebook.
import cv2
import numpy as np
from matplotlib import pyplot as plt
#The line below is necessary to show Matplotlib's plots inside a Jupyter Notebook
%matplotlib inline
from matplotlib import pyplot as plt
#Use this helper function if you are working in Jupyter Lab
#If not, then directly use cv2.imshow(<window name>, <image>)
def showimage(myimage, figsize=[10,10]):
if (myimage.ndim>2): #This only applies to RGB or RGBA images (e.g. not to Black and White images)
myimage = myimage[:,:,::-1] #OpenCV follows BGR order, while matplotlib likely follows RGB order
fig, ax = plt.subplots(figsize=figsize)
ax.imshow(myimage, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis
plt.show()
At this point, we import an image for processing
myimage = cv2.imread("Burano1.jpg")
showimage(myimage)
Practical application of Gabor Filter in Edge Detection
Now that we have our pre-requisites declared, we will create two functions. Firstly a function to create our Gabor Filters. Secondly a function to apply the filter and superimpose the results.
If you recall, the Gabor Filter has a directional element (Theta). In other words to cover edges in different directions, we need more than one Gabor Filter. Therefore we decided to create 16 filters evenly distributed around 180 degrees. This is greatly simplified using OpenCV’s built-in getGaborKernel function. Owing to this, our function returns 16 filters as a list.
def create_gaborfilter():
# This function is designed to produce a set of GaborFilters
# an even distribution of theta values equally distributed amongst pi rad / 180 degree
filters = []
num_filters = 16
ksize = 35 # The local area to evaluate
sigma = 3.0 # Larger Values produce more edges
lambd = 10.0
gamma = 0.5
psi = 0 # Offset value - lower generates cleaner results
for theta in np.arange(0, np.pi, np.pi / num_filters): # Theta is the orientation for edge detection
kern = cv2.getGaborKernel((ksize, ksize), sigma, theta, lambd, gamma, psi, ktype=cv2.CV_64F)
kern /= 1.0 * kern.sum() # Brightness normalization
filters.append(kern)
return filters
Correspondingly, we create a function to apply our filters.
def apply_filter(img, filters):
# This general function is designed to apply filters to our image
# First create a numpy array the same size as our input image
newimage = np.zeros_like(img)
# Starting with a blank image, we loop through the images and apply our Gabor Filter
# On each iteration, we take the highest value (super impose), until we have the max value across all filters
# The final image is returned
depth = -1 # remain depth same as original image
for kern in filters: # Loop through the kernels in our GaborFilter
image_filter = cv2.filter2D(img, depth, kern) #Apply filter to image
# Using Numpy.maximum to compare our filter and cumulative image, taking the higher value (max)
np.maximum(newimage, image_filter, newimage)
return newimage
At this point, we have our two functions defined and we can proceed to apply this to our image.
# We create our gabor filters, and then apply them to our image
gfilters = create_gaborfilter()
image_g = apply_filter(myimage, gfilters)
showimage(image_g)
Evidently upon closer examination, notice how edges have a “glow” to them. The edges of windows seem highlighted as well as edges of houses and the pier.
Applying Canny Edge Detection again
Up to the present time we have applied our Gabor Filter. Subsequently we apply Canny Edge detection on our new image. Finally we will show the result of Canny Edge detection before and after Gabor Filters.
min_interval = 120
max_interval = 250
image_edge_g = cv2.Canny(image_g,min_interval,max_interval)
# Using Numpy's function to append the two images horizontally
side_by_side = np.hstack((image_edge,image_edge_g))
showimage(side_by_side,[20,10])
Conclusions
Comparatively, applying Gabor Filters in Edge Detection made significant improvements. By and large lines are cleaner and object edges are better detected. Explicitly, the wooden piers and building edges are better highlighted. Straightaway, by applying Gabor Filter, we achieve better results than directly applying Canny. Of course, by further tuning our parameters, we potentially can achieve even better results.