2017-08-16 42 views
1

讓有兩個大(2000x2000或更高).tiff圖像只包含numpy float32值(無rgb)。我打電話給他們的圖像A和B.我想乘他們以特殊的方式:Python:改善圖像處理與numpy

  • 查找B中的最大值,並把它卷(使用numpy.roll)到 上,最左邊的角落。
  • 乘法甲乙
  • B的總和添加到其中,B的最大值進行壓延
  • 輥B中的一個元件進一步的最大A的索引
  • 重複對於A
  • 的所有元素
  • 保存生成的圖像

兩個圖像總是相同的形狀。 我想出了這個主意:

#A,B are loaded with PIL as numpy images and are flattend 
B = np.roll(B, len(mult_img)-distance_to_max) #roll max to the first element 

sum_arr = np.sum(B) #sum of B 

for i in range(len(A)): 
    A = np.multiply(A, np.roll(B, i)) #roll B with i-increment and multiply 
    A[i] += sum_arr #add sum to A at index 

這看起來像它會做的工作,重塑後陣和保存。但是對於2000x2000的圖像大約需要40s,並且會有處理它們的條件。 問題是:如何改進?或者是否有更好的numpy解決方案來完成這項任務以加快速度?

在此先感謝

回答

2

前瞻性方法

考慮一下:

In [154]: B = np.arange(5) 

In [155]: B 
Out[155]: array([0, 1, 2, 3, 4]) 

使用B軋製版本:

In [156]: for i in range(len(B)): 
    ...:  print np.roll(B, i) 
    ...:  
[0 1 2 3 4] 
[4 0 1 2 3] 
[3 4 0 1 2] 
[2 3 4 0 1] 
[1 2 3 4 0] 

所以,我們所需要的技巧聘請是創建一個擴展數組,可以切片以獲取滾動版本。這個想法在NumPy中切片基本上是免費的。由此,擴展陣列將是 -

In [157]: B_ext = np.concatenate((B[1:], B)) 

In [158]: B_ext 
Out[158]: array([1, 2, 3, 4, 0, 1, 2, 3, 4]) 

因此,在切片步驟將是 -

[1, 2, 3, 4, 0, 1, 2, 3, 4] 
      [   ] 
      [   ] 
     [   ] 
    [   ] 
[   ] 

用它

然後,擴展陣列可以使用像這樣 -

n = len(A) 
for i in range(n-1,-1,-1): 
    Ac *= B_ext[i:i+n] #roll B with i-increment and multiply 
    Ac[n-1-i] += sum_arr #add sum to A at index 

完成

結束寫入,所述方法將是 -

def org_app(A, B, sum_arr): # Original approach 
    for i in range(len(A)): 
     A = np.multiply(A, np.roll(B, i)) #roll B with i-increment and multiply 
     A[i] += sum_arr #add sum to A at index 
    return A 

def app1(A, B, sum_arr): # Proposed approach 
    B_ext = np.concatenate((B[1:], B)) 
    n = len(A) 
    for i in range(n-1,-1,-1): 
     A *= B_ext[i:i+n] #roll B with i-increment and multiply 
     A[n-1-i] += sum_arr #add sum to A at index 
    return A 

標杆

1)驗證 -

In [144]: # Setup inputs 
    ...: np.random.seed(1234) 
    ...: N = 10000 
    ...: A = np.random.randint(0,255,(N)) 
    ...: B = np.random.randint(0,255,(N)) 
    ...: A_copy = A.copy() 
    ...: sum_arr = np.sum(B) #sum of B 
    ...: 

In [145]: out1 = org_app(A, B, sum_arr) 
    ...: out2 = app1(A_copy, B, sum_arr) 
    ...: print "Abs. Max. Error : " + str(np.abs(out1-out2).max()) 
    ...: 
Abs. Max. Error : 0 

2)運行測試 -

In [146]: # Setup inputs 
    ...: np.random.seed(1234) 
    ...: N = 10000 
    ...: A = np.random.randint(0,255,(N)) 
    ...: B = np.random.randint(0,255,(N)) 
    ...: A_copy = A.copy() 
    ...: sum_arr = np.sum(B) #sum of B 
    ...: 

In [147]: %timeit org_app(A, B, sum_arr) 
1 loop, best of 3: 196 ms per loop 

In [148]: %timeit app1(A_copy, B, sum_arr) 
10 loops, best of 3: 51.9 ms per loop 
+0

哇!快4倍!相當漂亮的想法,我沒有想過切片:) – user3759978

+0

一個注意:當flattend圖像只有10000到100000個元素(幾秒)時,所提出的解決方案確實更快。對於2000x2000(4毫米的元素)圖像來說,它需要更長的時間(10分鐘後仍然沒有完成)。奇怪的是,當圖像不平坦時仍然非常快,但結果並不像預期的那樣。 – user3759978

+1

@ user3759978這就是'矢量化'解決方案。如果你把它擴展到內存限制,你最好使用一個loopy。關於結果不匹配,我認爲這是因爲解決方案在我們開始討論問題時採用了扁平化版本。 – Divakar