2016-08-16 3 views
1

それぞれが1つのエンティティを表す10種類の色を含む600個の注釈付きセマンティックセグメンテーションマスク画像を有するとする。これらの画像は、n = 600、3 = RGBチャンネル、72 =高さ、96 =幅の形状の数字の配列(600,3,72,96)である。画像のコレクション内のピクセル(R、G、B)を別個のピクセルカラー値インデックスにマップする方法はありますか?

numpy配列の各RGBピクセルをカラーインデックス値にマップするにはどうすればよいですか?たとえば、カラーリストは[(128,128,0)、(240,128,0)、... n]であり、numpy配列内のすべての(240,128,0)ピクセルはインデックスに変換されます一意のマッピング(= 1)の値。

これを効率的かつ少ないコードで実行するにはどうすればよいですか?ここで私が思いついた解決策がありますが、それはかなり遅いです。

# Input imgs.shape = (N, 3, H, W), where (N = count, W = width, H = height) 
def unique_map_pixels(imgs): 
    original_shape = imgs.shape 

    # imgs.shape = (N, H, W, 3) 
    imgs = imgs.transpose(0, 2, 3, 1) 

    # tupleview.shape = (N, H, W, 1); contains tuples [(R, G, B), (R, G, B)] 
    tupleview = imgs.reshape(-1, 3).view(imgs.dtype.descr * imgs.shape[3]) 

    # get unique pixel values in images, [(R, G, B), ...] 
    uniques = list(np.unique(tupleview)) 

    # map uniques into hashed list ({"RXBXG": 0, "RXBXG": 1}, ...) 
    uniqmap = {} 
    idx = 0 
    for x in uniques: 
    uniqmap["%sX%sX%s" % (x[0], x[1], x[2])] = idx 
    idx = idx + 1 
    if idx >= np.iinfo(np.uint16).max: 
     raise Exception("Can handle only %s distinct colors" % np.iinfo(np.uint16).max) 

    # imgs1d.shape = (N), contains RGB tuples 
    imgs1d = tupleview.reshape(np.prod(tupleview.shape)) 

    # imgsmapped.shape = (N), contains uniques-index values 
    imgsmapped = np.empty((len(imgs1d))).astype(np.uint16) 

    # map each pixel into unique-pixel-ID 
    idx = 0 
    for x in imgs1d: 
    str = ("%sX%sX%s" % (x[0], x[1] ,x[2])) 
    imgsmapped[idx] = uniqmap[str] 
    idx = idx + 1 

    imgsmapped.shape = (original_shape[0], original_shape[2], original_shape[3]) # (N, H, W) 
    return (imgsmapped, uniques) 

テストそれ:

import numpy as np 
n = 30 
pixelvalues = (np.random.rand(10)*255).astype(np.uint8) 
images = np.random.choice(pixelvalues, (n, 3, 72, 96)) 

(mapped, pixelmap) = unique_map_pixels(images) 
assert len(pixelmap) == mapped.max()+1 
assert mapped.shape == (len(images), images.shape[2], images.shape[3]) 
assert pixelmap[mapped[int(n*0.5)][60][81]][0] == images[int(n*0.5)][0][60][81] 
print("Done: %s" % list(mapped.shape)) 
+0

うーん。なぜあなたはこれをしたいのですか?それはちょうど理由のないステップを追加しているようだ。これらのカラーインデックスで何かをしたいのであれば、dictを検索してRGBタプルに戻す必要がありますか?編集:気にしない、参照してください。たくさんの画像を格納している場合は、タプルの束の代わりにintを格納する方が効率的です。なぜなら、とにかく特定の数の色を予測しているからです(10)。 – Anonymous

+0

はい、色の数が限られています。一意のインデックスが必要なのは、ピクセルカラーではなくピクセルカテゴリを予測するアルゴリズムにピクセルを供給しているからです。グレースケール画像(例えば、輝度0〜10)も同様であるが、画像は標準ツール(=画像ビューア、エディタなど)によって容易に視覚化できない。最後に、予測の後、RGB値にマップする必要があります。 –

答えて

1

はここで、これらのエラーチェックなしのコンパクトなベクトル化されたアプローチだ -

def unique_map_pixels_vectorized(imgs): 
    N,H,W = len(imgs), imgs.shape[2], imgs.shape[3] 
    img2D = imgs.transpose(0, 2, 3, 1).reshape(-1,3) 
    ID = np.ravel_multi_index(img2D.T,img2D.max(0)+1) 
    _, firstidx, tags = np.unique(ID,return_index=True,return_inverse=True) 
    return tags.reshape(N,H,W), img2D[firstidx] 

ランタイムテストと検証 -

In [24]: # Setup inputs (3x smaller than original ones) 
    ...: N,H,W = 200,24,32 
    ...: imgs = np.random.randint(0,10,(N,3,H,W)) 
    ...: 

In [25]: %timeit unique_map_pixels(imgs) 
1 loop, best of 3: 2.21 s per loop 

In [26]: %timeit unique_map_pixels_vectorized(imgs) 
10 loops, best of 3: 37 ms per loop ## 60x speedup! 

In [27]: map1,unq1 = unique_map_pixels(imgs) 
    ...: map2,unq2 = unique_map_pixels_vectorized(imgs) 
    ...: 

In [28]: np.allclose(map1,map2) 
Out[28]: True 

In [29]: np.allclose(np.array(map(list,unq1)),unq2) 
Out[29]: True 
+0

60x実際には、1つのデータセットの前処理時間が4時間から4分に短縮されました:)ありがとうございます! ravel_multi_indexのドキュメントは非常にまばらですが、実際に何がしているのかは分かりません。開始点としての最大ピクセル値はどういう意味ですか?私は理解しているように、どういうわけかこれらの3要素配列を一意のint表現に圧縮しますが、それらの(大)整数はどのように表現されますか? –

+1

@Mikaああ、あなたは全運にいます!この記事をチェックする:http://stackoverflow.com/a/38674038/3293881 – Divakar

関連する問題