2017-08-16 11 views
1

numpyのfloat32値(rgbなし)のみからなる2つの大きな(2000x2000以上の).tiff画像を作成します。私は特別な方法でそれらを乗算したい画像AとBそれらを呼び出す:Python:numpyによる画像処理の改善

  • は 左上ほとんどの隅に(numpy.rollを使用して)Bに最大値を検索し、それをロールバックします。
  • 乗算AとB
  • Bの最大値は、圧延したA
  • ロール
  • のすべての要素のBの最大一つの要素、さらに
  • 繰り返しのインデックスにBの合計を追加します。
  • 結果イメージを保存

両方のイメージは常に同じ形状です。 私はこのアイデアを作ってみた:それは、配列を再形成した後、仕事をして、それを救うのようにこれが見えます

#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の画像では約40秒かかり、処理するのにはかなりの時間がかかります。 質問:どのようにこれを改善できますか?または、このタスクのために少し速くするために良いソリューションがありますか?事前に

おかげ

答えて

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

1つのノート:flattend画像が10000〜100000要素の長さ(数秒)しかない場合、提案されたソリューションは本当に高速です。 2000x2000(4ミルの要素)の画像では、実際にはかなり長い時間がかかっています(まだ10分間もやっていない)。イメージが不安定になっても、それはまだ非常に速いですが、結果は期待通りです。 – user3759978

+1

@ user3759978それは 'ベクトル化された'解を持つものです。あなたがそれを記憶の限界まで伸ばすならば、あなたは虚偽のものに頼るほうが良いです。一致しない結果については、私たちが質問から始めたときに解決策が平らになっていると仮定していると思います。 – Divakar

関連する問題