2013-12-18 510 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 
"""`