PythonでRGBイメージをグレースケールに変換するにはどうすればよいですか?


206

matplotlibRGBイメージを読み込んでグレースケールに変換するために使用しようとしています。

matlabではこれを使用します:

img = rgb2gray(imread('image.png'));

matplotlibのチュートリアル彼らはそれをカバーしていません。彼らはただ画像を読んだ

import matplotlib.image as mpimg
img = mpimg.imread('image.png')

そして、それらは配列をスライスしますが、それは私が理解しているものからRGBをグレースケールに変換することと同じではありません。

lum_img = img[:,:,0]

numpyまたはmatplotlibに、rgbからgrayに変換する組み込み関数がないとは信じがたいです。これは画像処理の一般的な操作ではありませんか?

imread5分でインポートされた画像を処理する非常にシンプルな関数を作成しました。それはひどく非効率的ですが、それが私が組み込みのプロフェッショナルな実装を望んでいた理由です。

セバスチャンは私の機能を改善しました、しかし私はまだ組み込みのものを見つけたいと思っています。

matlab(NTSC / PAL)の実装:

import numpy as np

def rgb2gray(rgb):

    r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
    gray = 0.2989 * r + 0.5870 * g + 0.1140 * b

    return gray

2
rgb2gray関数と同じものを単純に次のように書くことができることに注意してくださいgray = np.mean(rgb, -1)rgb[...,:3]それが実際にrgbaである場合は、そこにあるかもしれません。
12

うーん、gray = np.mean(rgb, -1)正常に動作します。ありがとう。これを使用しない理由はありますか?なぜ代わりに以下の回答のソリューションを使用するのですか?
ワスピーター2012

6
ページウィキペディアグレースケールは、グレースケールにRGBを変換する方法がユニークではありませんが、輝度に基づいて一般的に使用される式を与えると言います。とはかなり異なりnp.mean(rgb, -1)ます。
unutbu 2012

2
だから私はMatlabのバージョンが欲しいと思いますか?0.2989 * R + 0.5870 * G + 0.1140 * B それが標準的な方法だと思います。
ワスピーター2012

回答:


304

枕でそれをするのはどうですか:

from PIL import Image
img = Image.open('image.png').convert('LA')
img.save('greyscale.png')

matplotlibとを使用する

Y' = 0.2989 R + 0.5870 G + 0.1140 B 

あなたができる:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb2gray(rgb):
    return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])

img = mpimg.imread('image.png')     
gray = rgb2gray(img)    
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()

3
彼が使用している場合はmatplotlib他のいくつかの理由で、彼は組み込み使用することができるはずcolorsys.rgb_to_yiq()ただ、輝度チャネルを得るために変換するためのプラスのスライスを。
Silas Ray

34
なんで.convert('LA')?なんで.convert('gray')?不必要に不可解なようです。PILのドキュメントは、変換機能のための「LA」については何も言及していません。
ワスピーター2012

25
PILを使用:cannot write mode LA as JPEG、LAではなくLモードを使用する必要がありました
jsky

6
これimg = Image.open('image.png').convert('LA')img = Image.open('image.png').convert('L')
nviens 2017年

12
@BluePython:LAモードには光度(明るさ)とアルファがあります。LAモードを使用する場合greyscale.png、アルファチャンネルがimage.png保持されたRGBA画像になります。Lモードを使用greyscale.pngする場合、RGBイメージ(アルファなし)になります。
unutbu 2017年

69

scikit-imageを使用することもできます。scikit- imageはndarray、のように画像を変換するためのいくつかの関数を提供しますrgb2gray

from skimage import color
from skimage import io

img = color.rgb2gray(io.imread('image.png'))

:この変換で使用される重みは、最新のCRT蛍光体に対して較正されています:Y = 0.2125 R + 0.7154 G + 0.0721 B

または、次の方法で画像をグレースケールで読み取ることもできます。

from skimage import io
img = io.imread('image.png', as_gray=True)

0 <値<1になるのは正常ですか?実際のグレースケールを取得するには、それらを255倍する必要がありますか?
サム

私の目的がGLCM機能(greycoprops)を使用することであることを知っている
Sam

io.imreadに関する注意: "as_gray"のため、 "as_grey"は非推奨になりました。同じ使用法、アメリカ化されたスペル。:)
ハロゲン

1
これは現在の質問に対する最も有用な回答だと思います。この出力は、matplotlibおよびnumpyとも互換性があります。
MertBeşiktepe19年

私はカラーオブジェクトを使用していますが、私のイメージは現在は赤みがかっており、グレー(白黒)ではありません。pyplot.imshow()cmapとして使用する必要がありgray' then only the image is shown as gray in ますか?何かご意見は ?どこが間違っているのですか?
GadaaDhaariGeek

63

Ubuntu 16.04 LTS(Xeon E5 2670 with SSD)のPython 3.5で実行される1000 RGBA PNG画像(224 x 256ピクセル)で、推奨される3つの方法の速度がテストされました。

平均実行時間

pil : 1.037秒

scipy: 1.040秒

sk : 2.120秒

PILとSciPyは同一のnumpy配列(0から255の範囲)を提供しました。SkImageは0から1までの配列を提供します。さらに、色はわずかに異なります。CUB -200データセットの例を参照してください

SkImage: SkImage

PIL : PIL

SciPy : SciPy

Original: 元の

Diff : ここに画像の説明を入力してください

コード

  1. パフォーマンス

    run_times = dict(sk=list(), pil=list(), scipy=list())
    for t in range(100):
        start_time = time.time()
        for i in range(1000):
            z = random.choice(filenames_png)
            img = skimage.color.rgb2gray(skimage.io.imread(z))
        run_times['sk'].append(time.time() - start_time)

    start_time = time.time()
    for i in range(1000):
        z = random.choice(filenames_png)
        img = np.array(Image.open(z).convert('L'))
    run_times['pil'].append(time.time() - start_time)
    
    start_time = time.time()
    for i in range(1000):
        z = random.choice(filenames_png)
        img = scipy.ndimage.imread(z, mode='L')
    run_times['scipy'].append(time.time() - start_time)
    

    for k, v in run_times.items(): print('{:5}: {:0.3f} seconds'.format(k, sum(v) / len(v)))

  2. 出力
    z = 'Cardinal_0007_3025810472.jpg'
    img1 = skimage.color.rgb2gray(skimage.io.imread(z)) * 255
    IPython.display.display(PIL.Image.fromarray(img1).convert('RGB'))
    img2 = np.array(Image.open(z).convert('L'))
    IPython.display.display(PIL.Image.fromarray(img2))
    img3 = scipy.ndimage.imread(z, mode='L')
    IPython.display.display(PIL.Image.fromarray(img3))
  3. 比較
    img_diff = np.ndarray(shape=img1.shape, dtype='float32')
    img_diff.fill(128)
    img_diff += (img1 - img3)
    img_diff -= img_diff.min()
    img_diff *= (255/img_diff.max())
    IPython.display.display(PIL.Image.fromarray(img_diff).convert('RGB'))
  4. 輸入
    import skimage.color
    import skimage.io
    import random
    import time
    from PIL import Image
    import numpy as np
    import scipy.ndimage
    import IPython.display
  5. バージョン
    skimage.version
    0.13.0
    scipy.version
    0.19.1
    np.version
    1.13.1

6
SciPyのイメージI / Oは文字通り PIL / Pillowです。したがって、SciPyをテストすると、SciPyのラッパー関数によって発生するごくわずかなオーバーヘッドでPIL / Pillowを効果的に再テストできます。それはあったであろう多くの(ないOpenCVの置換するより有用ではない(ん)scipyのダウンロードのためPIL /枕を活用します)。それにもかかわらず、専用のベンチマークに感謝します!SciKitによって課せられた認識できる速度低下は魅力的です... そして恐ろしいです。
セシルカレー

@CecilCurry OpenCVでアイデアをありがとう!自由時間があったら追加します。
Maximilian Peters

賛成です!私が探していた答えではありませんでしたが、それでも非常に興味深いものでした:)
Cyril N.

29

imreadOpenCV を使用して、最初からいつでも画像ファイルをグレースケールとして読み取ることができます。

img = cv2.imread('messi5.jpg', 0)

さらに、画像をRGBとして読み取る場合は、何らかの処理を行ってcvtcolorから、OpenCVから使用できるグレイスケールに変換します。

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

6
Ftr:0フラグはcv2.CV_LOAD_IMAGE_GRAYSCALEです。
dtk

24

最速かつ現在の方法は、を介してインストールされたPillowを使用することpip install Pillowです。

コードは次のとおりです。

from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')

3
上記の例のようにメソッドをチェーンしていない場合convertは、画像の変換されたコピーを返します
Matt

32ビットPNGでは機能しません。値は255 に固定されます
Andrew Matuk

11

チュートリアルは、RGBでエンコードされたグレースケールイメージから始まっているため、不正行為です。したがって、チュートリアルは、単一のカラーチャネルをスライスしてグレースケールとして扱うだけです。あなたがしなければならない基本的なステップは、RGBカラースペースから、YUV / YIQやHSL / HSVなどのルミナンス/クロマモデルに近いものでエンコードするカラースペースに変換し、ルミナンスのようなチャネルをスライスして、グレースケール画像。 matplotlibYUV / YIQに変換するメカニズムは提供されていないようですが、HSVに変換できます。

matplotlib.colors.rgb_to_hsv(img)グレースケールの配列の最後の値(V)をスライスして使用してみてください。これは輝度値とまったく同じではありませんが、すべてで実行できることを意味しますmatplotlib

バックグラウンド:

または、PILまたは組み込み関数colorsys.rgb_to_yiq()を使用して、真の輝度値を持つ色空間に変換することもできます。オールインして独自の輝度専用コンバーターを導入することもできますが、それはおそらくやり過ぎです。


9

この式を使用し

Y' = 0.299 R + 0.587 G + 0.114 B 

我々はできる

import imageio
import numpy as np
import matplotlib.pyplot as plt

pic = imageio.imread('(image)')
gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114]) 
gray = gray(pic)  
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))

ただし、GIMPでカラーをグレースケール画像に変換するソフトウェアには、このタスクを実行するための3つのアルゴリズムがあります。


8

NumPy / SciPyをすでに使用している場合は、次のように使用することもできます

scipy.ndimage.imread(file_name, mode='L')


5
scipy.ndimage.imread()scipy.misc.imread()は両方ともSciPy 1.0.0で正式に非推奨になり、SciPy 1.2.0で完全に削除されます。SciPyのドキュメントimageio.imread()は適切な代替品として推奨していますが、この関数のAPIは不条理なところまであります。グレースケール変換をサポートしていないため、私たちを含む多くのアプリケーションには依然として不適切です。</sigh>
セシルカレー

5
@ CecilCurry、imageioを使用してカラー画像をグレースケールに変換するにはどうすればよいですか?
0x90

5

あなたができる:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb_to_gray(img):
        grayImage = np.zeros(img.shape)
        R = np.array(img[:, :, 0])
        G = np.array(img[:, :, 1])
        B = np.array(img[:, :, 2])

        R = (R *.299)
        G = (G *.587)
        B = (B *.114)

        Avg = (R+G+B)
        grayImage = img

        for i in range(3):
           grayImage[:,:,i] = Avg

        return grayImage       

image = mpimg.imread("your_image.png")   
grayImage = rgb_to_gray(image)  
plt.imshow(grayImage)
plt.show()

5

img.Convert()を使用し、「L」、「RGB」、「CMYK」をサポートします。モード

import numpy as np
from PIL import Image

img = Image.open("IMG/center_2018_02_03_00_34_32_784.jpg")
img.convert('L')

print np.array(img)

出力:

[[135 123 134 ...,  30   3  14]
 [137 130 137 ...,   9  20  13]
 [170 177 183 ...,  14  10 250]
 ..., 
 [112  99  91 ...,  90  88  80]
 [ 95 103 111 ..., 102  85 103]
 [112  96  86 ..., 182 148 114]]

1
5行目はimg = img.convert('L')
アラン遺跡

3

私はグーグルを介してこの質問に行き、すでにロードされている画像をグレースケールに変換する方法を探していました。

SciPyでこれを行う方法は次のとおりです。

import scipy.misc
import scipy.ndimage

# Load an example image
# Use scipy.ndimage.imread(file_name, mode='L') if you have your own
img = scipy.misc.face()

# Convert the image
R = img[:, :, 0]
G = img[:, :, 1]
B = img[:, :, 2]
img_gray = R * 299. / 1000 + G * 587. / 1000 + B * 114. / 1000

# Show the image
scipy.misc.imshow(img_gray)

1
いいね。私はちょうどだろう短いソリューションを注意したいimg_gray = numpy.average(img, weights=[0.299, 0.587, 0.114], axis=2)
Akavall

@Akavall知ってよかった、ありがとう!あなたのショートカットがより速いかどうか知っていますか?そうでない場合は、理解しやすいので、私のものを使います。
Martin Thoma 2017

私はそれを計時しませんでした、私の直感numpy.averageは少し速いですが、実際には違いはありません。あなたの解決策は明確であり、R、G、Bに関連する情報があるので、私はそれを保持します。私のコメントは、代替ではなく、追加のオプションでした。
Akavall 2017

scipy.ndimage.imread()scipy.misc.imread()は両方ともSciPy 1.0.0で正式に非推奨になり、SciPy 1.2.0で完全に削除されます。おそらく代わりに、代わりにPillowの組み込みグレースケール変換サポート(ala unutbu答え)を使用したいだけです。
セシルカレー

-3
image=myCamera.getImage().crop(xx,xx,xx,xx).scale(xx,xx).greyscale()

greyscale()変換に直接使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.