2012-06-18 103 views
6

我有一個100x200的二維數組,表示爲由黑色(0)和白色(255)單元組成的numpy數組。這是一個位圖文件。然後我有二維形狀(最簡單的把它們想象成字母),它們也是2D黑白單元格。查找矩陣內的匹配子矩陣

我知道我可以天真地遍歷矩陣,但這將是我的代碼的'熱'部分,所以速度是一個問題。在numpy/scipy中有快速的方法嗎?

我簡單看了一下Scipy的相關函數。我對'模糊匹配'不感興趣,只有完全匹配。我也看了一些學術論文,但他們高於我的頭腦。

回答

8

可以使用相關。您需要將黑色值設置爲-1,將白色值設置爲1(反之亦然),以便知道相關峯值的值,並且只會出現正確的字母。

下面的代碼做我認爲你想要的。

import numpy 
from scipy import signal 

# Set up the inputs 
a = numpy.random.randn(100, 200) 
a[a<0] = 0 
a[a>0] = 255 

b = numpy.random.randn(20, 20) 
b[b<0] = 0 
b[b>0] = 255 

# put b somewhere in a 
a[37:37+b.shape[0], 84:84+b.shape[1]] = b 

# Now the actual solution... 

# Set the black values to -1 
a[a==0] = -1 
b[b==0] = -1 

# and the white values to 1 
a[a==255] = 1 
b[b==255] = 1 

max_peak = numpy.prod(b.shape) 

# c will contain max_peak where the overlap is perfect 
c = signal.correlate(a, b, 'valid') 

overlaps = numpy.where(c == max_peak) 

print overlaps 

此輸出(array([37]), array([84])),在代碼中設置的偏移量的位置。

您可能會發現,如果您的字母大小乘以大數組大小大於Nlog(N),其中N是您要搜索的大數組的相應大小(對於每個維度),則您可能會通過使用基於fft的算法(如scipy.signal.fftconvolve)(考慮到如果您使用卷積而非相關性 - flipudfliplr)需要翻轉其中一個數據集的每個軸來加快速度。唯一的修改是將分配C:

c = signal.fftconvolve(a, numpy.fliplr(numpy.flipud(b)), 'valid') 

上面的時序上的尺寸比較:

In [5]: timeit c = signal.fftconvolve(a, numpy.fliplr(numpy.flipud(b)), 'valid') 
100 loops, best of 3: 6.78 ms per loop 

In [6]: timeit c = signal.correlate(a, b, 'valid') 
10 loops, best of 3: 151 ms per loop 
+0

哇,偉大的答案!我有一些測試運行。 – DaveO

+1

剛剛發生的事情,您可以通過將值設置爲0來「不關心」您的子矩陣的區域。這意味着這些值將不會影響交叉關聯。然後'max_peak'值可以被找到爲'max_peak = b [b!= 0] .size'(無論你有沒有0值,這都會起作用)。 –

+0

所以我花了下午編輯我的代碼,並使它工作!假設在array([0,6]),array([1,7]))處發現了2個2x3形狀,意味着左上角是[0,1]和[6,7]。我想要做的是能夠索引形狀中的所有2x3單元格,並將它們賦值爲0,因此在下一個要查找的形狀中,我們將不檢查圖像的部分(根據上面的註釋)。我如何使用correlate/fftconvolve的返回值在不使用循環的情況下索引2d形狀?對位置列表片段進行排序。 – DaveO

7

這裏是您可以使用,或適應,這取決於細節的方法你的要求。它採用ndimage.label and ndimage.find_objects:

  1. 標籤使用ndimage.label此找到所有斑點的陣列中,並將其標籤爲整數的圖像。

    import scipy 
    from scipy import ndimage 
    import matplotlib.pyplot as plt 
    
    #flatten to ensure greyscale. 
    im = scipy.misc.imread('letters.png',flatten=1) 
    objects, number_of_objects = ndimage.label(im) 
    letters = ndimage.find_objects(objects) 
    
    #to save the images for illustrative purposes only: 
    plt.imsave('ob.png',objects) 
    for i,j in enumerate(letters): 
        plt.imsave('ob'+str(i)+'.png',objects[j]) 
    

    例如輸入:

  2. 使用ndimage.find_objects
  3. 然後使用交集,看是否found blobs符合您的wanted blobs

代碼1.2.獲取這些斑點的片

enter image description here

標記:

enter image description here

孤立的斑點再次進行測試:(甚至計時)

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here

+0

令人驚歎!這幾乎是我想要做的。我將不得不嘗試兩個答案,並看看什麼效果最好。感謝您花時間發佈此信息! – DaveO