2017-01-01 68 views
3

因此,我目前正試圖找出一個更優化的解決方案來確定圖像中的連通組件。目前,我有一個具有特定值的座標的數組。我想根據它們是否觸摸來創建這些座標的組。我正在使用一個numpy數組,並且目前我必須檢查每個值(左上角,上中角,右上角,中間左側,中間右側,左下角,中下角,右下角)是否在該數組中。我這樣做是通過此代碼:檢查相鄰值是否在Numpy矩陣中

for x in range (0, groupCoords.shape[0]): 
      global tgroup 
      xCoord = groupCoords.item((x,0)) 
      yCoord = groupCoords.item((x,1)) 
      new = np.array([[xCoord, yCoord]]) 
      if np.equal(Arr,[xCoord, yCoord+1]).all(1).any(): 
       tgroup = np.append(tgroup, [[xCoord,yCoord+1]], axis=0) 
       new = np.append(new, [[xCoord,yCoord+1]], axis=0) 
       index = np.argwhere((Arr == [xCoord,yCoord+1]).all(1)) 
       Arr = np.delete(Arr, (index), axis=0) 

      if np.equal(Arr,[xCoord, yCoord-1]).all(1).any(): 
       tgroup = np.append(tgroup, [[xCoord, yCoord-1]],axis=0) 
       new = np.append(new, [[xCoord,yCoord-1]], axis=0) 
       index = np.argwhere((Arr == [xCoord,yCoord-1]).all(1)) 
       Arr = np.delete(Arr, (index), axis=0) 

      if np.equal(Arr,[xCoord+1, yCoord]).all(1).any(): 
       tgroup = np.append(tgroup, [[xCoord+1,yCoord]],axis=0) 
       new = np.append(new, [[xCoord+1,yCoord]], axis=0) 
       index = np.argwhere((Arr == [xCoord+1,yCoord]).all(1)) 
       Arr = np.delete(Arr, (index), axis=0) 

      if np.equal(Arr,[xCoord+1, yCoord+1]).all(1).any(): 
       tgroup = np.append(tgroup, [[xCoord+1,yCoord+1]],axis=0) 
       new = np.append(new, [[xCoord+1,yCoord+1]], axis=0) 
       index = np.argwhere((Arr == [xCoord+1,yCoord+1]).all(1)) 
       Arr = np.delete(Arr, (index), axis=0) 

      if np.equal(Arr,[xCoord+1, yCoord-1]).all(1).any(): 
       tgroup = np.append(tgroup, [[xCoord+1,yCoord-1]],axis=0) 
       new = np.append(new, [[xCoord+1,yCoord-1]], axis=0) 
       index = np.argwhere((Arr == [xCoord+1,yCoord-1]).all(1)) 
       Arr = np.delete(Arr, (index), axis=0) 

      if np.equal(Arr,[xCoord-1, yCoord]).all(1).any(): 
       tgroup = np.append(tgroup, [[xCoord-1,yCoord]],axis=0) 
       new = np.append(new, [[xCoord-1,yCoord]], axis=0) 
       index = np.argwhere((Arr == [xCoord-1,yCoord]).all(1)) 
       Arr = np.delete(Arr, (index), axis=0) 

      if np.equal(Arr,[xCoord-1, yCoord+1]).all(1).any(): 
       tgroup = np.append(tgroup, [[xCoord-1,yCoord+1]],axis=0) 
       new = np.append(new, [[xCoord-1,yCoord+1]], axis=0) 
       index = np.argwhere((Arr == [xCoord-1,yCoord+1]).all(1)) 
       Arr = np.delete(Arr, (index), axis=0) 

      if np.equal(Arr,[xCoord-1, yCoord-1]).all(1).any(): 
       tgroup = np.append(tgroup, [[xCoord-1,yCoord-1]],axis=0) 
       new = np.append(new, [[xCoord-1,yCoord-1]], axis=0) 
       index = np.argwhere((Arr == [xCoord-1,yCoord-1]).all(1)) 
       Arr = np.delete(Arr, (index), axis=0) 

但是,如果圖像很大,這顯然需要大量的時間。我的想法是創建一個帶有圖像寬度和高度尺寸的布爾矩陣,然後將值「true」賦值給矩陣中對應於圖像中像素的值(圖像爲黑白)。

我想知道,是否有可能,而不是像這樣檢查每個值,確定它們是否是包含另一個「真實」值的「true」元素?

這是輸入數組會是什麼樣子:

[ 
[0 0] 
[0 1] 
[0 2] 
[10 2] 

] 

輸出看起來像

[ 
[0 0] 
[0 1] 
[0 2] 
] 

功能我希望能改進會檢查是否「真」值是感人,並創建一個所有觸及的值的「網絡」(它會繼續運行新的值)。

+0

請問座標的順序很重要?我想我們正在篩選出那裏的座標。同樣,你是否需要他們從一端連接到另一端(如果適用)或其他標準的順序? – Divakar

+0

你能給一個輸入的小例子(比如4x4數組)和期望的輸出嗎? –

+0

@Divakar順序並不重要,我只需要將它們組合成一個數組。我將它用作OCR方法,因此它所做的是創建連接組件的列表,最終成爲圖像中的每個字符。 –

回答

1

方法#1

我們可以得到的歐氏距離,看看是否有任何距離的距離sqrt(2),這將覆蓋up-downdistance = 1和對角線distance = sqrt(2)。這會給我們一個掩碼,當它被索引到組座標數組中時,它會給我們連接它的掩碼。

因此,使用Scipy's cdist爲得到這些歐幾里得距離的實現,將是 -

from scipy.spatial.distance import cdist 

out = groupCoords[(cdist(groupCoords,Arr)<1.5).any(1)] 

採樣運行 -

In [401]: Arr 
Out[401]: 
array([[ 5, 4], 
     [11, 12], 
     [ 5, 3], 
     [ 1, 3], 
     [15, 8], 
     [55, 21]]) 

In [402]: groupCoords 
Out[402]: 
array([[2, 3], # In neighbourhood of (1,3) 
     [5, 6], 
     [6, 2], # In neighbourhood of (5,3) 
     [5, 3], # In neighbourhood of (5,4) 
     [5, 8]]) 

In [403]: groupCoords[(cdist(groupCoords,Arr)<1.5).any(1)] 
Out[403]: 
array([[2, 3], 
     [6, 2], 
     [5, 3]]) 

方法2

另一種方式會檢查在兩個數組的第一列之間具有絕對的元素方面的差異,並且對於第二列也是如此。最後,從這兩個掩碼中獲取一個聯合掩碼,然後檢查任何匹配並再次檢索過濾後坐標的組數組。

因此,實施這樣的方法是 -

col0_mask = (np.abs(groupCoords[:,0,None] - Arr[:,0])<=1) 
col1_mask = (np.abs(groupCoords[:,1,None] - Arr[:,1])<=1) 
out = groupCoords[(col0_mask & col1_mask).any(1)] 

方法3

另一種方法,可能會更好,如果你有Arr作爲一個布爾數組,而不是作爲2列座標數組。這個想法是dilate this boolean arrayArr,然後看看哪個座標groupCoords也將位於這張膨脹的圖像。對於擴張,我們將使用所有的內核來覆蓋所有這些鄰近的地方。爲了檢測這些共同的點,我們需要用那些groupCoords來繪製圖像。

因此,該代碼將是 -

from scipy.ndimage.morphology import binary_dilation 

img = np.zeros(Arr.shape,dtype=bool) 
img[groupCoords[:,0],groupCoords[:,1]] = 1 
out = np.argwhere(binary_dilation(Arr,np.ones((3,3))) & img) 

採樣運行 -

In [444]: # Inputs : groupCoords and let's create a sample array for Arr 
    ...: groupCoords = np.array([[2,3],[5,6],[6,2],[5,3],[5,8]]) 
    ...: 
    ...: Arr_Coords = np.array([[5,4],[11,12],[5,3],[1,3],[15,8],[55,21]]) 
    ...: Arr = np.zeros(Arr_Coords.max(0)+1,dtype=bool) 
    ...: Arr[Arr_Coords[:,0], Arr_Coords[:,1]] = 1 
    ...: 

In [445]: img = np.zeros(Arr.shape,dtype=bool) 
    ...: img[groupCoords[:,0],groupCoords[:,1]] = 1 
    ...: out = np.argwhere(binary_dilation(Arr,np.ones((3,3))) & img) 
    ...: 

In [446]: out 
Out[446]: 
array([[2, 3], 
     [5, 3], 
     [6, 2]]) 
1

根據您的代碼的最終目標,你可能會發現scipy.ndimage.label及其親屬有用。

例如,

In [44]: from scipy.ndimage import label 

In [45]: x 
Out[45]: 
array([[ True, True, False, False, True], 
     [False, False, False, True, True], 
     [False, True, False, True, False], 
     [ True, True, False, False, False]], dtype=bool) 

In [46]: x.astype(int) # More concise, easier to read 
Out[46]: 
array([[1, 1, 0, 0, 1], 
     [0, 0, 0, 1, 1], 
     [0, 1, 0, 1, 0], 
     [1, 1, 0, 0, 0]]) 

label返回兩個值。第一個是與輸入數組大小相同的數組。輸入中每個不同的連接組件都分配一個整數值,從1開始。背景爲0.第二個返回值是找到的組件數。

In [47]: labeled_arr, nlabels = label(x) 

In [48]: nlabels 
Out[48]: 3 

In [49]: labeled_arr 
Out[49]: 
array([[1, 1, 0, 0, 2], 
     [0, 0, 0, 2, 2], 
     [0, 3, 0, 2, 0], 
     [3, 3, 0, 0, 0]], dtype=int32) 

在下面的例子中,where(labeled_array = i)返回一個包含兩個數組的數組。這些陣列的行和列索引,RESP,連接的部分組成:

In [50]: for i in range(1, nlabels+1): 
    ...:  print(where(labeled_arr == i)) 
    ...:  
(array([0, 0]), array([0, 1])) 
(array([0, 1, 1, 2]), array([4, 3, 4, 3])) 
(array([2, 3, 3]), array([1, 0, 1])) 

您可以壓縮這些一起將它們轉換成的(行,列)對名單:

In [52]: for i in range(1, nlabels+1): 
    ...:  print(list(zip(*where(labeled_arr == i)))) 
    ...:  
[(0, 0), (0, 1)] 
[(0, 4), (1, 3), (1, 4), (2, 3)] 
[(2, 1), (3, 0), (3, 1)]