2013-12-18 83 views
3

我仍然在Python上编写指纹图像预处理器。我看到在MATLAB有一个特殊的功能,以除去H2S休息和马刺:Python等价于bwmorph

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

我已搜查scikit,OpenCV的和其他人,但找不到这两个使用bwmorph等效。任何人都可以指向正确的方向,还是必须实施我自己的方向?

回答

1

据我所知,你必须自己实现这些,因为它们不在OpenCV或skimage中。 但是,应该很直接地检查MATLAB代码的工作原理,并在Python/NumPy中编写自己的版本。

下面是一个指南中详细NumPy的功能描述专为MATLAB用户,在MATLAB和NumPy的同等功能提示: http://wiki.scipy.org/NumPy_for_Matlab_Users

+0

谢谢你的回答。接受它作为答案就足够了。 –

+1

嘿,我在这里有同样的问题。你在哪里找到bwmorph的Matlab代码来编写你自己的代码? – fmonegaglia

2

编辑2017年10月

的skimage模块现在有至少2种选择: skeletonizethin

与比较实施例

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

example of skimage.morphology.thin/skeletonize

原帖

我发现通过joefutrelle这个解决方案上github

看起来(视觉上)给出与Matlab版本类似的结果。

希望有帮助!

编辑:

正如在评论中指出,我会致以战后初期作为提及链接可能会改变:

寻找从MATLAB我Python中的替代bwmorph在Github上偶然发现了joefutrelle的下面的代码(在这篇文章的最后,因为它很长)。

我已经想通了两种方法来实现此为我的脚本(我是初学者,我敢肯定有更好的方法!):

1)整个代码复制到你的脚本,然后调用该功能(但这使得脚本更难阅读)

2)将代码复制到一个新的python文件'foo'并保存。现在将它复制到Python \ Lib(例如C:\ Program Files \ Python35 \ Lib)文件夹中。在您的原始脚本可以通过编写调用该函数:

from foo import bwmorph_thin

然后你会养活功能与您的二进制图像:

Original

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

Skeleton

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 R. W. 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 
"""`