Como definir efficently todos os valores acima de uma linha em uma imagem binária para 1?

Luke Gibson:

Atualmente tenho uma imagem binária, armazenado como uma matriz 2D de [col] [linha]. A imagem é dividida em duas por uma linha e que deseja definir todos os valores da matriz acima da linha para uma.

Actualmente, eu percorrer as colunas da matriz, looping através das linhas de coluna (de baixo para cima) para encontrar a primeira linha, onde o valor da matriz [col] [row] é 1. Em seguida, a partir de quebrar o ciclo através linhas e definir todos os valores acima da linha que rompeu a partir de uma coluna para que.

Infelizmente para uma imagem de 1920x1080, este leva cerca de 3 segundos. Como isso pode ser alcançado de forma mais eficiente?

for x in range(len(image)):
    col = image[x]
    minY= -1

    for y in range(len(col)):
        if image[x][-y] != 0:
            minY = y
            break

    if minY != -1:
        under = [0] * minY 
        over = [1] * (len(col) - minY)
        newCol = over + under
        image[x] = newCol

Antes e depois fotos abaixo ...

digite descrição da imagem aqui digite descrição da imagem aqui

norok2:

Aqui um par de métodos que exigem uma entrada 2D. Pode ter de ser ajustada para garantir que eles estão trabalhando no lado correto e sobre a dimensão correta, mas a idéia central detém.

  • usando np.where()e looping sobre um dim com corte:
import numpy as np


def side_fill_np(arr, value, flag):
    rows, cols = arr.shape
    idx = np.where(arr == flag)
    for i in range(cols):
        arr[idx[0][i]:, idx[1][i]] = value
    return arr
  • usando looping completo explícita (semelhante ao seu, mas de alguma forma mais limpa), mas acelerou com numba
import numba as nb


@nb.jit
def side_fill_nb(arr, value, flag):
    rows, cols = arr.shape
    for j in range(cols):
        found = False
        for i in range(rows):
            if found:
                arr[i, j] = value
            elif arr[i, j] == flag:
                found = True

Para testar se estamos recebendo o resultado correto, geramos alguma entrada usando:

def gen_data(shape):
    rows, cols = shape
    arr = np.zeros(shape, dtype=bool)
    indexes = (np.random.randint(0, rows - 1, cols), np.arange(cols))
    arr[indexes] = True
    return arr

eo teste lê:

np.random.seed(0)  # for reproducible results
arr = gen_data((10, 20))
print(arr.astype(int))
# [[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
#  [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0]
#  [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0]
#  [0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
#  [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
#  [1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1]
#  [0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0]
#  [0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0]
#  [0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0]
#  [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]

side_fill_np(arr, True, True)
print(arr.astype(int))
# [[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
#  [0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0]
#  [0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0]
#  [0 1 1 1 0 1 0 1 0 0 0 0 0 1 0 0 0 0 1 0]
#  [0 1 1 1 0 1 0 1 1 0 0 0 0 1 0 0 0 0 1 0]
#  [1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 0 0 0 1 1]
#  [1 1 1 1 0 1 1 1 1 0 1 0 0 1 1 0 0 0 1 1]
#  [1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 1 1]
#  [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
#  [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]]

Agora, para os horários para aprox. o seu tamanho de entrada:

arr = gen_data((2000, 2000))
%timeit side_fill(arr, True, True)
# 1 loop, best of 3: 2.48 s per loop
%timeit side_fill_np(arr, True, True)
# 10 loops, best of 3: 52.6 ms per loop
%timeit side_fill_nb(arr, True, True)
# 100 loops, best of 3: 6.14 ms per loop

Como você pode ver, com a abordagem NumPy (que é tanto vetorizado como eu poderia pensar), obtém aprox. 2 ordens de velocidade-up magnitude, com o Numba acelerado código que você obter aprox. 3 ordens de magnitude velocidade-up.

Acho que você gosta

Origin http://10.200.1.11:23101/article/api/json?id=383343&siteId=1
Recomendado
Clasificación