I am looking for the equivalent implementation of the laplacian of gaussian edge detection.
In matlab we use the following function
[BW,threshold] = edge(I,'log',...)
In python there exist a function for calculating the laplacian of gaussian. It is not giving the edges back definitely.
scipy.ndimage.filters.gaussian_laplace
Any pointer to online implementation or the code
Thanks
This can be calculated using a convolution filter. Since the input image is represented as a set of discrete pixels, we have to find a discrete convolution kernel that can approximate the second derivatives in the definition of the Laplacian. Two commonly used small kernels are shown in Figure 1.
The Laplacian filter is used to detect the edges in the images. But it has a disadvantage over the noisy images. It amplifies the noise in the image. Hence, first, we use a Gaussian filter on the noisy image to smoothen it and then subsequently use the Laplacian filter for edge detection.
The Laplacian Edge Detector Unlike the Sobel edge detector, the Laplacian edge detector uses only one kernel. It calculates second order derivatives in a single pass. Here's the kernel used for it: The kernel for the laplacian operator. You can use either one of these.
What matlab edge() do should be
The LoG filter of scipy only does step 1 above. I implemented the following snippet to mimic step 2~4 above:
import scipy as sp
import numpy as np
import scipy.ndimage as nd
import matplotlib.pyplot as plt
from skimage import data
# lena = sp.misc.lena() this function was deprecated in version 0.17
img = data.camera() # use a standard image from skimage instead
LoG = nd.gaussian_laplace(img , 2)
thres = np.absolute(LoG).mean() * 0.75
output = sp.zeros(LoG.shape)
w = output.shape[1]
h = output.shape[0]
for y in range(1, h - 1):
for x in range(1, w - 1):
patch = LoG[y-1:y+2, x-1:x+2]
p = LoG[y, x]
maxP = patch.max()
minP = patch.min()
if (p > 0):
zeroCross = True if minP < 0 else False
else:
zeroCross = True if maxP > 0 else False
if ((maxP - minP) > thres) and zeroCross:
output[y, x] = 1
plt.imshow(output)
plt.show()
This of course is slow and probably not idiomatic as I am also new to Python, but should show the idea. Any suggestion on how to improve it is also welcomed.
I played a bit with the code of ycyeh (thanks for providing it). In my applications I got better results with using output values proportional to the min-max-range than just binary 0s and 1s. (I then also did not need the thresh anymore but one can easily apply a thresholding on the result.) Also I changed the loops to numpy array operations for faster execution.
import numpy as np
import scipy.misc
import cv2 # using opencv as I am not too familiar w/ scipy yet, sorry
def laplace_of_gaussian(gray_img, sigma=1., kappa=0.75, pad=False):
"""
Applies Laplacian of Gaussians to grayscale image.
:param gray_img: image to apply LoG to
:param sigma: Gauss sigma of Gaussian applied to image, <= 0. for none
:param kappa: difference threshold as factor to mean of image values, <= 0 for none
:param pad: flag to pad output w/ zero border, keeping input image size
"""
assert len(gray_img.shape) == 2
img = cv2.GaussianBlur(gray_img, (0, 0), sigma) if 0. < sigma else gray_img
img = cv2.Laplacian(img, cv2.CV_64F)
rows, cols = img.shape[:2]
# min/max of 3x3-neighbourhoods
min_map = np.minimum.reduce(list(img[r:rows-2+r, c:cols-2+c]
for r in range(3) for c in range(3)))
max_map = np.maximum.reduce(list(img[r:rows-2+r, c:cols-2+c]
for r in range(3) for c in range(3)))
# bool matrix for image value positiv (w/out border pixels)
pos_img = 0 < img[1:rows-1, 1:cols-1]
# bool matrix for min < 0 and 0 < image pixel
neg_min = min_map < 0
neg_min[1 - pos_img] = 0
# bool matrix for 0 < max and image pixel < 0
pos_max = 0 < max_map
pos_max[pos_img] = 0
# sign change at pixel?
zero_cross = neg_min + pos_max
# values: max - min, scaled to 0--255; set to 0 for no sign change
value_scale = 255. / max(1., img.max() - img.min())
values = value_scale * (max_map - min_map)
values[1 - zero_cross] = 0.
# optional thresholding
if 0. <= kappa:
thresh = float(np.absolute(img).mean()) * kappa
values[values < thresh] = 0.
log_img = values.astype(np.uint8)
if pad:
log_img = np.pad(log_img, pad_width=1, mode='constant', constant_values=0)
return log_img
def _main():
"""Test routine"""
# load grayscale image
img = scipy.misc.face() # lena removed from newer scipy versions
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# apply LoG
log = laplace_of_gaussian(img)
# display
cv2.imshow('LoG', log)
cv2.waitKey(0)
if __name__ == '__main__':
_main()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With