Python implementation of the laplacian of gaussian edge detection

后端 未结 2 1984
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-02 00:24

I am looking for the equivalent implementation of the laplacian of gaussian edge detection.

In matlab we use the following function

   [BW,threshold         


        
相关标签:
2条回答
  • 2021-01-02 00:56

    What matlab edge() do should be

    1. Compute LoG
    2. Compute zero crossings on LoG
    3. Compute a threshold for local LoG difference
    4. Edge pixels = zero crossing && local difference > threshold

    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.

    0 讨论(0)
  • 2021-01-02 00:57

    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()
    
    0 讨论(0)
提交回复
热议问题