J'ai une image qui est lue comme un tableau uint8 avec la forme (512,512,3)
.
Maintenant, je voudrais convertir ce tableau en un tableau uint8 de forme (512,512,1)
, où chaque valeur de pixel dans le troisième axe est convertie à partir d'une valeur de couleur [255,0,0 ]
à une valeur d'étiquette de classe unique [3]
, basée sur l'encodage de couleur / classe suivant:
1 : [0, 0, 0], 2 : [0, 0, 255], 3 : [255, 0, 0], 4 : [150, 30, 150], 5 : [255, 65, 255], 6 : [150, 80, 0], 7 : [170, 120, 65], 8 : [125, 125, 125], 9 : [255, 255, 0], 10 : [0, 255, 255], 11 : [255, 150, 0], 12 : [255, 225, 120], 13 : [255, 125, 125], 14 : [200, 100, 100], 15 : [0, 255, 0], 16 : [0, 150, 80], 17 : [215, 175, 125], 18 : [220, 180, 210], 19 : [125, 125, 255]
Quelle est la manière la plus efficace de faire ce? J'ai pensé à parcourir toutes les classes et à utiliser numpy.where
, mais cela prend évidemment beaucoup de temps.
3 Réponses :
Vous pouvez utiliser une table de recherche géante. Soit cls [[0,0,0], [0,0,255], ...]
de dtype = np.uint8
.
def scalarize(x): # compute x[...,2]*65536+x[...,1]*256+x[...,0] in efficient way y = x[...,2].astype('u4') y <<= 8 y +=x[...,1] y <<= 8 y += x[...,0] return y LUT = np.zeros(2**24, dtype='u1') LUT[scalarize(cls)] = 1 + np.arange(cls.shape[0]) simg = scalarize(img) img_to_cls = LUT[simg]
Cette scalarize
ressemble à un ajout intelligent.
En voici une basée sur des vues
-
In [100]: # Mapping array ...: maps = np.array([[0, 0, 0],[0, 0, 255],\ ...: [255, 0, 0],[150, 30, 150]],dtype=np.uint8) ...: ...: # Setup random image array ...: idx = np.array([[0,2,1,3],[1,3,2,0]]) ...: img = maps[idx] In [101]: img2label(img, maps) # should retrieve back idx Out[101]: array([[0, 2, 1, 3], [1, 3, 2, 0]])
Étant donné que vos libellés commencent à 1
, vous voudrez peut-être ajouter 1
à la sortie.
Exemple d'exécution -
# https://stackoverflow.com/a/45313353/ @Divakar def view1D(a, b): # a, b are arrays # This function gets 1D view into 2D input arrays a = np.ascontiguousarray(a) b = np.ascontiguousarray(b) void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[-1])) return a.view(void_dt).ravel(), b.view(void_dt).ravel() def img2label(a, maps): # Get one-dimension reduced view into input image and map arrays. # We need to reshape image to 2D, then feed it to view1D to get 1D # outputs and then reshape 1D image to 2D A,B = view1D(a.reshape(-1,a.shape[-1]),maps) A = A.reshape(a.shape[:2]) # Trace back positions of A in B using searchsorted. This gives us # original order, which is the final output. sidx = B.argsort() return sidx[np.searchsorted(B,A,sorter=sidx)]
Pourriez-vous ajouter quelques commentaires supplémentaires sur la façon dont cela fonctionne?
@KarlKnechtel Ajout d'une explication.
Une manière: créez séparément les tableaux booléens avec des valeurs True
où la valeur de pixel de l'entrée correspond à l'une des valeurs de la palette, puis utilisez l'arithmétique pour les combiner. Ainsi:
palette = [ [0, 0, 0], [0, 0, 255], [255, 0, 0], # etc. ] def palettized(data, palette): # Initialize result array shape = list(data.shape) shape[-1] = 1 result = np.zeros(shape) # Loop and add each palette index component. for value, colour in enumerate(palette, 1): result += (data == colour).all(axis=2) * value return result
que faire si la valeur de couleur dans une grande image n'est pas présente dans le tableau de classe?
Vous essayez effectivement de palettiser une image - regardez ici stackoverflow.com/a/57204807/2836621