web-dev-qa-db-ja.com

misc.imreadで画像を赤、緑、青のチャネルにスライスする方法

画像をRGBにスライスしようとしていますが、これらの画像のプロットに問題があります。この機能を使用して、特定のフォルダからすべての画像を取得します。

def get_images(path, image_type):
image_list = []
for filename in glob.glob(path + '/*'+ image_type):
    im=misc.imread(filename, mode='RGB')
    image_list.append(im)
return image_list

この関数は4d配列(30、1536、2048、3)を作成します。最初の値は画像の数を表し、2番目と3番目は次元、3番目はRGB値であることを確信しています。

すべての画像を取得した後、それらをnumpy配列として保存しました

image_list = get_images('C:\HDR\images', '.jpg')
temp = np.array(image_list)

その後、私はこれらの画像から特定の色を取得するために単純なスライスを使用しようとしました:

red_images = temp[:,:,:,0]
green_images = temp[:,:,:,1]
blue_images = temp[:,:,:,2]

値を出力すると、すべて問題ないようです。

print(temp[11,125,311,:])
print(red_images[11,125,311])
print(green_images[11,125,311])
print(blue_images[11,125,311])

そして私は以下を得ます:

[105  97  76]
105
97
76

これまでのところ、すべて問題ないようですが、画像を表示しようとすると問題が発生します。 matplotlib.pyplot.imshow表示するには、次のような画像を取得します。

Image red channel

赤を選択しているので、これは合理的です。

 plt.imshow(temp[29,:,:,0])

しかし、次のように別のカラーチャネルに変更すると、

plt.imshow(temp[29,:,:,2])

私はこのような画像を取得します:

Image bug channel

私の質問は簡単です。ここで何が起きてるの?

8
mrGreenBrown

Matplotlibは、各チャネル(つまり、強度)を「ヒートマップ」として扱っているだけだと思います。

次のようにカラーマップを関数imshowに渡して、イメージに色を付ける方法を伝えます。

plt.imshow(image_slice, cmap=plt.cm.gray)

編集する

@mrGreenBrownあなたのコメントへの応答として、私はあなたが使用したmisc.imread関数がscipyから、つまりscipy.misc.imreadであると想定しています。その関数はPILの関数と同じです。 scipy.misc.imread docs を参照してください。これを指摘してくれた@daiに感謝します。

画像の単一チャネルは、単なる強度です。色はありません。 RGB色空間で表現された画像の場合、色は、赤、緑、青の量(それぞれのチャネルの強度によって与えられる)を「混合」することによって得られます。 単一のチャネルは色を表現できません

起こったのは、デフォルトでMatplotlibが強度をヒートマップ、つまり「色」として表示することでした。

単一のチャネルをJPEGなどの形式の画像として保存する場合、この関数は単一のチャネルを3回複製するだけなので、R、G、Bチャネルにはすべて同じ強度が含まれます。これは、単一チャネルのグレースケールイメージを処理できるPGMなどの形式で保存しない限り、一般的な動作です。同じチャネルを3回複製したこの画像を視覚化しようとすると、赤、緑、青の寄与が各ピクセルで同じであるため、画像は灰色で表示されます。

plt.cm.graycmap引数に渡すと、単にimshowに強度を「色分け」しないように指示します。したがって、より明るいピクセル(白に近づくピクセル)は、それらの場所にその「色」が「多い」ことを意味します。

色が必要な場合は、3チャネルイメージのコピーを作成し、他のチャネルを0の値に設定する必要があります。

たとえば、赤のチャネルを「赤」として表示するには:

# Assuming I is numpy array with 3 channels in RGB order
I_red = image.copy()  # Duplicate image
I_red[:, :, 1] = 0    # Zero out contribution from green
I_red[:, :, 2] = 0    # Zero out contribution from blue

Stackoverflowからの関連質問 here

13
lightalchemist

したがって、画像のさまざまなRGBチャネルをさまざまな色で表示したいとします...

import matplotlib.pyplot as plt
from matplotlib.cbook import get_sample_data

image = plt.imread(get_sample_data('grace_hopper.jpg'))

titles = ['Grace Hopper', 'Red channel', 'Green channel', 'Blue channel']
cmaps = [None, plt.cm.Reds_r, plt.cm.Greens_r, plt.cm.Blues_r]

fig, axes = plt.subplots(1, 4, figsize=(13,3))
objs = Zip(axes, (image, *image.transpose(2,0,1)), titles, cmaps)

for ax, channel, title, cmap in objs:
    ax.imshow(channel, cmap=cmap)
    ax.set_title(title)
    ax.set_xticks(())
    ax.set_yticks(())

plt.savefig('RGB1.png')

enter image description here 暗いテーブルの上に赤いペンのある暗い部屋があるときに、赤いランプを点灯すると、ペンがほとんど白いものとして認識されます...

別の可能性は、他の色のピクセル値をゼロにして、色ごとに異なる画像を作成することです。去ったところから始めて、チャンネルを抽出して、それ以外は黒の画像にする関数を定義します。

...
from numpy import array, zeros_like
def channel(image, color):
    if color not in (0, 1, 2): return image
    c = image[..., color]
    z = zeros_like(c)
    return array([(c, z, z), (z, c, z), (z, z, c)][color]).transpose(1,2,0)

そして最後にそれを使います...

colors = range(-1, 3)
fig, axes = plt.subplots(1, 4, figsize=(13,3))
objs = Zip(axes, titles, colors)
for ax, title, color in objs:
    ax.imshow(channel(image, color))
    ax.set_title(title)
    ax.set_xticks(())
    ax.set_yticks(())

plt.savefig('RGB2.png')

enter image description here どちらがより良いバージョンであるかはわかりません。おそらく最初のバージョンはもっとrealisticに見えます(多分それはあまり人工的ではない)が、それはかなり主観的です...

6
gboffi