Implementación Python del laplaciano de detección de borde gaussiano.

Estoy buscando la implementación equivalente del laplaciano de detección de borde gaussiano.

En matlab utilizamos la siguiente función.

[BW,threshold] = edge(I,'log',...) 

En python existe una función para calcular el laplaciano de gaussiano. No es devolver los bordes definitivamente.

  scipy.ndimage.filters.gaussian_laplace 

Cualquier puntero a la implementación en línea o el código

Gracias

Lo que debe hacer el borde matlab ()

  1. Computar LoG
  2. Calcular cero cruces en LoG
  3. Calcular un umbral para la diferencia de LoG local
  4. Píxeles de borde = cruce por cero && diferencia local> umbral

El filtro LoG de scipy solo hace el paso 1 anterior. Implementé el siguiente fragmento de código para imitar los pasos 2 ~ 4 anteriores:

 import scipy as sp import numpy as np import scipy.ndimage as nd import matplotlib.pyplot as plt lena = sp.misc.lena() LoG = nd.gaussian_laplace(lena, 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() 

Por supuesto, esto es lento y probablemente no sea idiomático, ya que también soy nuevo en Python, pero debería mostrar la idea. Cualquier sugerencia sobre cómo mejorarla también es bienvenida.

Jugué un poco con el código de ycyeh (gracias por proporcionarlo). En mis aplicaciones obtuve mejores resultados con el uso de valores de salida proporcionales al rango mínimo-máximo que solo los 0 y 1 binarios. (Entonces tampoco necesité la trilla, pero se puede aplicar fácilmente un umbral en el resultado). También cambié los bucles para numerar las operaciones de matriz para una ejecución más rápida.

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