2013-01-21 15 views
17

Ho un'immagine letta in numpy con parecchi pixel nella mia matrice risultante.C'è un modo conveniente per applicare una tabella di ricerca a un grande array in numpy?

Ho calcolato una tabella di ricerca con 256 valori. Ora voglio fare quanto segue:

for i in image.rows: 
    for j in image.cols: 
     mapped_image[i,j] = lut[image[i,j]] 

Yep, che è fondamentalmente ciò che fa una LUT.
L'unico problema è: voglio farlo in modo efficiente e chiamare quel ciclo in python mi farà aspettare alcuni secondi perché finisca.

Conosco numpy.vectorize(), è semplicemente una funzione di comodità che chiama lo stesso codice Python.

risposta

25

Si può semplicemente utilizzare image per indicizzare lut se lut è 1D.
Ecco un antipasto su indicizzazione in NumPy:
http://www.scipy.org/Tentative_NumPy_Tutorial#head-864862d3f2bb4c32f04260fac61eb4ef34788c4c

In [54]: lut = np.arange(10) * 10 

In [55]: img = np.random.randint(0,9,size=(3,3)) 

In [56]: lut 
Out[56]: array([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90]) 

In [57]: img 
Out[57]: 
array([[2, 2, 4], 
     [1, 3, 0], 
     [4, 3, 1]]) 

In [58]: lut[img] 
Out[58]: 
array([[20, 20, 40], 
     [10, 30, 0], 
     [40, 30, 10]]) 

mente anche l'indicizzazione inizia alle 0

+3

* face-desk * Questo è così semplice, potrei urlare. Ho pensato nell'altra direzione tutto il tempo e che non funzionerà. Ma naturalmente, numpy fa le cose in modo elementare, quindi questa è la soluzione più ovvia. Forse ero stanco ieri. ;) – Profpatsch

+0

In realtà, sembra funzionare anche per LUTS multidimensionali, almeno con numpy 1.9.2 – Claude

+0

Soluzione molto elegante, grazie! – gcucurull

13

risposta di TheodrosZelleke nel corretto, ma volevo solo aggiungere un po 'di saggezza non documentato ad esso. Numpy fornisce una funzione, np.take, che secondo la documentazione "fa la stessa cosa dell'indice di fantasia".

Beh, quasi, ma non proprio la stessa cosa:

>>> import numpy as np 
>>> lut = np.arange(256) 
>>> image = np.random.randint(256, size=(5000, 5000)) 
>>> np.all(lut[image] == np.take(lut, image)) 
True 
>>> import timeit 
>>> timeit.timeit('lut[image]', 
...    'from __main__ import lut, image', number=10) 
4.369504285407089 
>>> timeit.timeit('np.take(lut, image)', 
...    'from __main__ import np, lut, image', number=10) 
1.3678052776554637 

np.take è circa 3 volte più veloce! Nella mia esperienza, quando uso le lute 3D per convertire immagini da RGB in altri spazi colore, l'aggiunta di logica per convertire la visualizzazione 3D in una ricerca appiattita 1D consente una velocità di x10.

+1

Oh, wow, ho cercato più a fondo in 'np.put' per un po 'perché pensavo che potesse funzionare. Quando non l'ho fatto, non ho controllato le altre funzioni. -.- – Profpatsch

+6

Questi tempi sono vecchi di due anni: le versioni più recenti di NumPy, a partire da 1.9, hanno un macchinario di indicizzazione di fantasia molto migliorato, che ora è comparabilmente veloce quanto l'uso di 'take'. – Jaime