Python Equivalente para bwmorph

Todavía estoy codificando un preprocesador de imagen de huella digital en Python. Veo que en MATLAB hay una función especial para eliminar los cortes y espuelas de H:

bwmorph(a , 'hbreak') bwmorph(a , 'spur') 

He buscado scikit, OpenCV y otros, pero no pude encontrar un equivalente para estos dos usos de bwmorph . ¿Alguien puede indicarme la dirección correcta o tengo que implementar la mía?

Tendrá que implementarlas por su cuenta, ya que no están presentes en OpenCV o skimage, que yo sepa. Sin embargo, debería ser sencillo verificar el código de MATLAB sobre cómo funciona y escribir su propia versión en Python / NumPy.

Aquí hay una guía que describe en detalle las funciones NumPy exclusivamente para usuarios de MATLAB, con sugerencias sobre funciones equivalentes en MATLAB y NumPy: http://wiki.scipy.org/NumPy_for_Matlab_Users

Editar Octubre 2017

El módulo de skimage ahora tiene al menos 2 opciones: skeletonize y thin

Ejemplo con comparación

 from skimage.morphology import thin, skeletonize import numpy as np import matplotlib.pyplot as plt square = np.zeros((7, 7), dtype=np.uint8) square[1:-1, 2:-2] = 1 square[0, 1] = 1 thinned = thin(square) skel = skeletonize(square) f, ax = plt.subplots(2, 2) ax[0,0].imshow(square) ax[0,0].set_title('original') ax[0,0].get_xaxis().set_visible(False) ax[0,1].axis('off') ax[1,0].imshow(thinned) ax[1,0].set_title('morphology.thin') ax[1,1].imshow(skel) ax[1,1].set_title('morphology.skeletonize') plt.show() 

ejemplo de skimage.morphology.thin / skeletonize

Post original

He encontrado esta solución por joefutrelle en github .

Parece (visualmente) dar resultados similares a la versión de Matlab.

¡Espero que ayude!

Editar:

Como se señaló en los comentarios, extenderé mi publicación inicial ya que el enlace mencionado podría cambiar:

Buscando un sustituto en Python para bwmorph de Matlab, me topé con el siguiente código de joefutrelle en Github (al final de este post, ya que es muy largo).

He descubierto dos formas de implementar esto en mi script (soy un principiante y estoy seguro de que hay mejores formas):

1) copie el código completo en su script y luego llame a la función (pero esto hace que el script sea más difícil de leer)

2) copia el código en un nuevo archivo de python ‘foo’ y guárdalo. Ahora cópielo en la carpeta Python \ Lib (por ejemplo, C: \ Program Files \ Python35 \ Lib). En su script original puede llamar a la función escribiendo:

from foo import bwmorph_thin

Luego alimentarás la función con tu imagen binaria:

Original

 skeleton = bwmorph_thin(foo_image, n_iter = math.inf) 

Esqueleto

 import numpy as np from scipy import ndimage as ndi # lookup tables for bwmorph_thin G123_LUT = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0], dtype=np.bool) G123P_LUT = np.array([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=np.bool) def bwmorph_thin(image, n_iter=None): """ Perform morphological thinning of a binary image Parameters ---------- image : binary (M, N) ndarray The image to be thinned. n_iter : int, number of iterations, optional Regardless of the value of this parameter, the thinned image is returned immediately if an iteration produces no change. If this parameter is specified it thus sets an upper bound on the number of iterations performed. Returns ------- out : ndarray of bools Thinned image. See also -------- skeletonize Notes ----- This algorithm [1]_ works by making multiple passes over the image, removing pixels matching a set of criteria designed to thin connected regions while preserving eight-connected components and 2 x 2 squares [2]_. In each of the two sub-iterations the algorithm correlates the intermediate skeleton image with a neighborhood mask, then looks up each neighborhood in a lookup table indicating whether the central pixel should be deleted in that sub-iteration. References ---------- .. [1] Z. Guo and RW Hall, "Parallel thinning with two-subiteration algorithms," Comm. ACM, vol. 32, no. 3, pp. 359-373, 1989. .. [2] Lam, L., Seong-Whan Lee, and Ching Y. Suen, "Thinning Methodologies-A Comprehensive Survey," IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol 14, No. 9, September 1992, p. 879 Examples -------- >>> square = np.zeros((7, 7), dtype=np.uint8) >>> square[1:-1, 2:-2] = 1 >>> square[0,1] = 1 >>> square array([[0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0]], dtype=uint8) >>> skel = bwmorph_thin(square) >>> skel.astype(np.uint8) array([[0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]], dtype=uint8) """ # check parameters if n_iter is None: n = -1 elif n_iter <= 0: raise ValueError('n_iter must be > 0') else: n = n_iter # check that we have a 2d binary image, and convert it # to uint8 skel = np.array(image).astype(np.uint8) if skel.ndim != 2: raise ValueError('2D array required') if not np.all(np.in1d(image.flat,(0,1))): raise ValueError('Image contains values other than 0 and 1') # neighborhood mask mask = np.array([[ 8, 4, 2], [16, 0, 1], [32, 64,128]],dtype=np.uint8) # iterate either 1) indefinitely or 2) up to iteration limit while n != 0: before = np.sum(skel) # count points before thinning # for each subiteration for lut in [G123_LUT, G123P_LUT]: # correlate image with neighborhood mask N = ndi.correlate(skel, mask, mode='constant') # take deletion decision from this subiteration's LUT D = np.take(lut, N) # perform deletion skel[D] = 0 after = np.sum(skel) # coint points after thinning if before == after: # iteration had no effect: finish break # count down to iteration limit (or endlessly negative) n -= 1 return skel.astype(np.bool) """ # here's how to make the LUTs def nabe(n): return np.array([n>>i&1 for i in range(0,9)]).astype(np.bool) def hood(n): return np.take(nabe(n), np.array([[3, 2, 1], [4, 8, 0], [5, 6, 7]])) def G1(n): s = 0 bits = nabe(n) for i in (0,2,4,6): if not(bits[i]) and (bits[i+1] or bits[(i+2) % 8]): s += 1 return s==1 g1_lut = np.array([G1(n) for n in range(256)]) def G2(n): n1, n2 = 0, 0 bits = nabe(n) for k in (1,3,5,7): if bits[k] or bits[k-1]: n1 += 1 if bits[k] or bits[(k+1) % 8]: n2 += 1 return min(n1,n2) in [2,3] g2_lut = np.array([G2(n) for n in range(256)]) g12_lut = g1_lut & g2_lut def G3(n): bits = nabe(n) return not((bits[1] or bits[2] or not(bits[7])) and bits[0]) def G3p(n): bits = nabe(n) return not((bits[5] or bits[6] or not(bits[3])) and bits[4]) g3_lut = np.array([G3(n) for n in range(256)]) g3p_lut = np.array([G3p(n) for n in range(256)]) g123_lut = g12_lut & g3_lut g123p_lut = g12_lut & g3p_lut """`