2013-05-04 60 views
0

我想在python中掃描閾值編輯的圖像來檢測白色像素並存儲它們的位置的簡單嵌套循環。的問題是,雖然它是從讀取該陣列是隻有160×120(19200),它仍然需要大約6秒來執行,我的代碼如下所示和任何幫助或指導將不勝感激:Python簡單的嵌套循環

im = Image.open('PYGAMEPIC') 

r, g, b = np.array(im).T 
x = np.zeros_like(b) 

height = len(x[0]) 
width = len(x) 

x[r > 120] = 255           
x[g > 100] = 0          
x[b > 100] = 0    

row_array = np.zeros(shape = (19200,1)) 
col_array = np.zeros(shape = (19200,1)) 

z = 0 
for i in range (0,width-1): 
    for j in range (0,height-1): 
     if x[i][j] == 255: 
      z = z+1 
      row_array[z] = i 

      col_array[z] = j 

回答

2

首先,它不應該需要6秒鐘。在160x120圖片上試用你的代碼需要0.2秒。

這就是說,對於良好的numpy性能,你通常希望避免循環。有時候,除了最小軸和沿着它的所有循環外,沿着所有的方向矢量化更簡單,但是如果可能的話,你應該儘量一次完成所有的工作。這通常會使事情變得更快(將循環向下推到C)並且更容易。

您的循環本身似乎有點陌生,我 - 你似乎有一個差一錯誤都在你開始存儲結果,其中的條款(第一個值放入z=1,不z=0 )以及在多大程度上你正在尋找(range(0, x-1)不包括x-1方面,所以你錯過了最後一排/ column--可能是你想要range(x)。)

如果你想要的是指數,其中r > 120但既不g > 100也不b > 100,有更簡單的方法。我們可以創建布爾數組。例如,第一,我們可以做一些假的數據:

>>> r = np.random.randint(0, 255, size=(8,8)) 
>>> g = np.random.randint(0, 255, size=(8,8)) 
>>> b = np.random.randint(0, 255, size=(8,8)) 

然後,我們可以在其中找到我們的條件得到滿足的地方:

>>> (r > 120) & ~(g > 100) & ~(b > 100) 
array([[False, True, False, False, False, False, False, False], 
     [False, False, True, False, False, False, False, False], 
     [False, True, False, False, False, False, False, False], 
     [False, False, False, True, False, True, False, False], 
     [False, False, False, False, False, False, False, False], 
     [False, True, False, False, False, False, False, False], 
     [False, False, False, False, False, False, False, False], 
     [False, False, False, False, False, False, False, False]], dtype=bool) 

然後我們可以使用np.where得到的座標:

>>> r_idx, c_idx = np.where((r > 120) & ~(g > 100) & ~(b > 100)) 
>>> r_idx 
array([0, 1, 2, 3, 3, 5]) 
>>> c_idx 
array([1, 2, 1, 3, 5, 1]) 

而且我們可以通過索引回rgb

>>> r[r_idx, c_idx] 
array([166, 175, 155, 150, 241, 222]) 
>>> g[r_idx, c_idx] 
array([ 6, 29, 19, 62, 85, 31]) 
>>> b[r_idx, c_idx] 
array([67, 97, 30, 4, 50, 71]) 
+0

爲了您的迴應,我忘記提及我正在使用Raspberry Pi來實現此目的。用你的方法實現布爾數組非常容易,但它仍然不能解決這個問題,我必須確定這個圖像中的白色像素並存儲它們的位置。我仍然需要一種掃描圖像的方式,我可以識別白色像素並存儲它們,而不需要花費6秒左右來實現 – RR1 2013-05-04 18:38:02

+0

我不明白。上面的代碼使用你的規則來構成一個白色像素 - '(r> 120)&〜(g> 100)&〜(b> 100))' - 並且給出白色像素所在的索引, r_idx'和'c_idx'是你的'row_array'和'col_array',沒有浪費的零空間。無論如何,希望別人能夠幫助你! – DSM 2013-05-04 18:43:55

+0

哦,哇,對不起,我的頭被整天看着電腦屏幕燒壞了!這很好,非常感謝你!現在我可以擺脫這些邪惡的循環!它只需要0.0117s!非常感謝!! – RR1 2013-05-04 19:01:37

0

ë你在Python 2.x(2.6或2.7)。在python 2中,每當你打電話給range時,你都會創建一個包含很多元素的列表。 (在這種情況下,你要創建width - 1長度的1名列表,然後的height - 1長度。一種方法width - 1列表加快這是使每提前一個列表,並使用該列表中的每個時間。

例如

height_indices = range(0, height - 1) 
for i in range(0, width - 1): 
    for j in height_indices: 
     # etc 

爲了防止不必創建任一列表,你可以使用xrange返回發電機,這將節省內存和時間,如蟒蛇,

for i in xrange(0, width - 1): 
    for j in xrange(0, height - 1): 
     # etc. 

你也應該使用filter函數來研究一個函數並執行它。它將返回函數返回的項目列表,但如果您所做的只是遞增全局計數器並修改全局數組,則不必返回任何內容或關注返回的列表。

+0

嗨,那裏,謝謝你的迴應,我忘了提及我使用2.7版本的python樹莓派。我已經嘗試過提前製作清單的方法,這樣可以節約大約0.2秒,但仍然讓我的執行時間大約爲5秒。你會有任何其他想法檢查圖像(黑色與白色像素一團),並確定這些像素和存儲它們? – RR1 2013-05-04 18:41:00