Как выполнить быстрый разрез нулевого края в питоне? - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть двоичный размер изображения 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)

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Вы можете использовать тот факт, что если вы sum находитесь над осью вашего трехмерного массива, тогда значение все равно будет 0, если в строке нет ни 1 (ни столбца, ни третьего измерения), в зависимости от того, какой axisпараметр.Затем, используя any в одном из двух других направлений и np.argwhere, вы получите индекс, где есть хотя бы один 1 на другой оси.Использование min и max даст значение, которое вы ищете.Вот функция:

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)

ЭтоБыстрее.

0 голосов
/ 29 ноября 2018

Ваша функция может быть значительно улучшена с помощью встроенных функций 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...