【问题标题】:How to perform a fast cut zero edge in python?如何在python中执行快速切割零边缘?
【发布时间】:2018-11-29 16:10:57
【问题描述】:

我的二进制图像大小为256x256x256,其中前景区域位于一个小区域中,并且我有很多零边距。我想通过找到图像中像素非零的点的最小和最大坐标来切割零边缘。它奏效了,但它很耗时。我发布了我的代码,你能告诉我如何让它更快吗?

对于256x256x256的图片大小,大约需要0.13024640083312988秒。这是代码,你可以在线运行https://repl.it/repls/AnxiousExoticBackup

import numpy as np
import time

def cut_edge(image, keep_margin):
    '''
    function that cuts zero edge
    '''
    D, H, W = image.shape
    D_s, D_e = 0, D - 1
    H_s, H_e = 0, H - 1
    W_s, W_e = 0, W - 1

    while D_s < D:
        if image[D_s].sum() != 0:
            break
        D_s += 1
    while D_e > D_s:
        if image[D_e].sum() != 0:
            break
        D_e -= 1
    while H_s < H:
        if image[:, H_s].sum() != 0:
            break
        H_s += 1
    while H_e > H_s:
        if image[:, H_e].sum() != 0:
            break
        H_e -= 1
    while W_s < W:
        if image[:, :, W_s].sum() != 0:
            break
        W_s += 1
    while W_e > W_s:
        if image[:, :, W_e].sum() != 0:
            break
        W_e -= 1

    if keep_margin != 0:
        D_s = max(0, D_s - keep_margin)
        D_e = min(D - 1, D_e + keep_margin)
        H_s = max(0, H_s - keep_margin)
        H_e = min(H - 1, H_e + keep_margin)
        W_s = max(0, W_s - keep_margin)
        W_e = min(W - 1, W_e + keep_margin)

    return int(D_s), int(D_e)+1, int(H_s), int(H_e)+1, int(W_s), int(W_e)+1

image = np.zeros ((256,256,256),dtype=np.float32)
ones_D_min, ones_D_max, ones_H_min, ones_H_max,ones_W_min, ones_W_max= 100,200, 90,150, 60,200
image[ones_D_min: ones_D_max,ones_H_min:ones_H_max, ones_W_min:ones_W_max]=1
t0=time.time()
ones_D_min_result, ones_D_max_result, ones_H_min_result, ones_H_max_result, ones_W_min_result, ones_W_max_result= cut_edge(image,0)
t1=time.time()
print ('Time consuming ', t1-t0)
print (ones_D_min, ones_D_max, ones_H_min, ones_H_max,ones_W_min, ones_W_max)
print (ones_D_min_result, ones_D_max_result, ones_H_min_result, ones_H_max_result, ones_W_min_result, ones_W_max_result)

【问题讨论】:

    标签: arrays python-3.x numpy image-processing


    【解决方案1】:

    使用 numpy 的内置函数可以显着改进您的功能:

    def cut_edge(image, keep_margin):
        '''
        function that cuts zero edge
        '''
    
        #Calculate sum along each axis
        D_sum = np.sum(image, axis=(1,2)) #0
        H_sum = np.sum(image, axis=(0,2)) #1
        W_sum = np.sum(image, axis=(0,1)) #2
    
        #Find the non-zero values
        W_nz = np.nonzero(W_sum)[0]
        H_nz = np.nonzero(H_sum)[0]
        D_nz = np.nonzero(D_sum)[0]
    
        #Take the first and last entries for start and end
        D_s = D_nz[0]
        D_e = D_nz[-1]
        H_s = H_nz[0]
        H_e = H_nz[-1]
        W_s = W_nz[0]
        W_e = W_nz[-1]
    
    
        if keep_margin != 0:
            D_s = max(0, D_s - keep_margin)
            D_e = min(D - 1, D_e + keep_margin)
            H_s = max(0, H_s - keep_margin)
            H_e = min(H - 1, H_e + keep_margin)
            W_s = max(0, W_s - keep_margin)
            W_e = min(W - 1, W_e + keep_margin)
    
        return D_s, D_e+1, H_s, H_e+1, W_s, W_e+1
    

    结果:

    Time consuming  0.0963144302368164
    

    【讨论】:

      【解决方案2】:

      您可以使用这样一个事实,即如果您在 3D 数组的轴上 sum,则该值仍将为 0,其中行(或列或第三维)中没有 1,具体取决于 axis范围。然后通过在其他两个方向之一上使用anynp.argwhere,您将获得另一个轴上至少有一个 1 的索引。使用 minmax 将给出您正在寻找的值。这是函数:

      def cut_edge_2(image, keep_margin):
          im_sum0 = (image.sum(0) !=0)
          im_sum1 = (image.sum(1) !=0)
          ones_D = np.argwhere(im_sum1.any(1))
          ones_H = np.argwhere(im_sum0.any(1))
          ones_W = np.argwhere(im_sum0.any(0))
          if keep_margin != 0:
              D, H, W = image.shape
              return (max( 0, ones_D.min() - keep_margin), min(D, ones_D.max() + keep_margin+1), 
                      max( 0, ones_H.min() - keep_margin), min(H, ones_H.max() + keep_margin+1),
                      max( 0, ones_W.min() - keep_margin), min(W, ones_W.max() + keep_margin+1))
          return (ones_D.min(), ones_D.max() +1, 
                  ones_H.min(), ones_H.max() +1,           
                  ones_W.min(), ones_W.max() +1)
      

      你得到的结果与你的函数相同:

      print (cut_edge(image,0))
      #(100, 200, 90, 150, 60, 200)
      print (cut_edge_2(image,0))
      #(100, 200, 90, 150, 60, 200)
      
      print (cut_edge(image,60))
      #(40, 256, 30, 210, 0, 256)
      print (cut_edge_2(image,60))
      #(40, 256, 30, 210, 0, 256)
      

      还有一些timeit

      %timeit cut_edge(image,0)
      #93 ms ± 7.62 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
      %timeit cut_edge_2(image,0)
      #25.3 ms ± 8.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
      %timeit cut_edge_2(image,1)
      #26.2 ms ± 4.73 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
      %timeit cut_edge(image,1)
      #95.4 ms ± 6.63 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
      

      速度更快。

      【讨论】:

      • 完美!。让我检查一下我的电脑
      • T:我发现了一个错误。结果与设置不正确。让我们检查一下repl.it/repls/AnxiousExoticBackup
      • @John 确实,这是一个糟糕的复制和粘贴。我在答案中修复了它。在min 中,它始终是D,而不是H,然后是W,因为它应该适用于每个方向。很抱歉
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多