Cómo establecer eficientemente todos los valores por encima de una línea en una imagen binaria a 1?

Lucas Gibson:

Actualmente tengo una imagen binaria, almacenado como un array 2D de [col] [fila]. La imagen se divide en 2 por una línea y Quiero configurar todos los valores de la matriz por encima de la línea a 1.

Actualmente, bucle a través de las columnas de la matriz, bucle a través de las filas de la columna (de abajo a arriba) para encontrar la primera fila donde el valor de la matriz [col] [fila] es 1. entonces descanso de bucle a través de la filas y establecer todos los valores por encima de la fila que rompí de a 1 para esa columna.

Por desgracia para una imagen de 1920x1080, esto toma alrededor de 3 segundos. ¿Cómo podría lograrse de manera más 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 y después de fotos de abajo ...

introducir descripción de la imagen aquí introducir descripción de la imagen aquí

norok2:

Aquí un par de métodos que requieren una entrada de 2D. Puede ser necesario ajustar para asegurar que están trabajando en el lado correcto y en la dimensión correcta, pero la idea central sostiene.

  • el uso np.where()y la colocación sobre una tenue con rebanado:
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 un bucle completo explícita (similar a la suya, pero de alguna manera más limpia), pero se aceleró con 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 la prueba de que estamos consiguiendo el resultado correcto, generamos alguna 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

y la prueba se lee:

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]]

Ahora, para los tiempos de aprox. el tamaño 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 se puede ver, con el enfoque NumPy (que es tanto como vectorizado lo que podía pensar) se obtiene aprox. 2 órdenes de magnitud de aceleración, con la Numba aceleraron código se obtiene aprox. 3 órdenes de magnitud de aceleración.

Supongo que te gusta

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