Análise das soluções do programa Rampa

Esta página apresenta as principais soluções apresentadas no programa Rampa. O objetivo é entender as discrepâncias entre elas e comparar suas vantagens e desvantagens.

Solução conceitual com indices:

Nesta abordagem, a matriz das coordenadas das colunas "c" já é a rampa desejada. O único cuidado é que como um dos valores de teste a rampa ultrapassa o valor 255, é importante que o tipo de pixel seja inteiro com no mínimo 16 bits.


In [19]:
def rr_indices( lado):
    import numpy as np
    r,c = np.indices( (lado, lado), dtype='uint16' )
    return c
    
print(rr_indices(11))


[[ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]]

Soluções mais eficientes:

Existem no mínimo três soluções que se classificam como as mais eficientes. Todas elas tem o custo de escrever uma linha e depois copiar esta linha em todas as linhas da imagem de saída.

Cópia com broadcast

A mais interessante e mais eficiente é a cópia por broadcast (assunto do módulo 3). Nesta solução declara-se a imagem final com empty e depois copia-se uma linha criada pelo arange para cada linha da imagem utilizando-se da propriedade de broadcast do numpy.


In [20]:
def rr_broadcast( lado):
    import numpy as np
    row = np.arange(lado, dtype='uint16')
    g = np.empty ( (lado,lado), dtype='uint16')
    g[:,:] = row
    return g

print(rr_broadcast(11))


[[ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]]

Cópia na forma de ladrilho

Na solução usando ladrilho (tile), cria-se um ladrilho com a linha rampa pelo arange e depois ladrilha-se esta linha com "lado" linhas.


In [21]:
def rr_tile( lado):
    import numpy as np
    f = np.arange(lado, dtype='uint16')
    return np.tile( f, (lado,1))

print(rr_tile(11))


[[ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]]

Utilizando resize

A solução do resize utiliza-se da propriedade da função resize do numpy que completa o raster da imagem repetindo-o até o tamanho final.


In [22]:
def rr_resize( lado):
    import numpy as np
    f = np.arange(lado, dtype='uint16')
    return np.resize(f, (lado,lado))
        
print(rr_resize(11))


[[ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]]

Utilizando repeat

O repeat to numpy repete cada pixel n vezes. Para utilizá-lo no neste problema, repetindo-se a linha rampa (arange) por lado, depois de reformatá-lo para duas dimensões há necessidade de fazer a transposição pois a repetição se dá na horizontal e o que se quer é a repetição na veritical, pois na imagem final as linhas são repetidas.


In [23]:
def rr_repeat( lado):
    import numpy as np
    f = np.arange(lado, dtype='uint16')
    return np.repeat( f, lado).reshape(lado, lado).transpose()

print(rr_repeat(11))


[[ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]]

Utilizando a operação módulo

Uma solução que não foi encontrada é a que utiliza o operador "módulo", isto é, o resto da divisão. Nesta solução, cria-se um vetor único do tamanho final da imagem, aplicando-se o operador "modulo lado". Depois basta reformatar para duas dimensões. O inconveniente desta solução é que o vetor precisa ser de 32 bits, pois o número total de pixels normalmente é maior que 65535, que é o máximo que se pode representar em 'uint16'.


In [24]:
def rr_modulo( lado):
    import numpy as np
    f = np.arange(lado * lado, dtype='int32')
    return (f % lado).reshape(lado,lado)
    
print(rr_modulo(11))


[[ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]
 [ 0  1  2  3  4  5  6  7  8  9 10]]

Testando


In [25]:
p = [rr_broadcast, rr_resize, rr_repeat, rr_tile, rr_indices, rr_modulo]
lado = 101
f    = rr_indices(lado)
for func in p:
    if not (func(lado) == f).all():
        print('func %s failed' % func.__name__)

Comparando tempo

O tempo de cada função é calculado executando-a mil vezes e calculando o percentil 2.


In [26]:
import numpy as np

p = [rr_broadcast, rr_tile, rr_resize, rr_repeat, rr_modulo, rr_indices]
lado = 20057
for func in p:
    print(func.__name__)
    %timeit f = func(lado)
    print()


rr_broadcast
1 loop, best of 3: 638 ms per loop

rr_tile
1 loop, best of 3: 621 ms per loop

rr_resize
1 loop, best of 3: 625 ms per loop

rr_repeat
1 loop, best of 3: 2.54 s per loop

rr_modulo
1 loop, best of 3: 4.59 s per loop

rr_indices
1 loop, best of 3: 1.32 s per loop

Referências

  • master:tutorial_numpy_1_8 Adessowiki: tile exemplos ilustrativos
  • http://docs.scipy.org/doc/numpy/reference/generated/numpy.tile.html NumPy: tile
  • http://docs.scipy.org/doc/numpy/reference/generated/numpy.repeat.html NumPy: repeat

In [ ]: