2017-08-16 64 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