Bir RGB görüntüsünü Python'da gri tonlamaya nasıl dönüştürebilirim?


209

matplotlibBir RGB görüntüde okumak ve gri tonlamaya dönüştürmek için kullanmaya çalışıyorum .

Matlab'da bunu kullanıyorum:

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

Gelen matplotlib öğretici bunu kapsamaz. Sadece görüntüde okuyorlar

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

ve sonra diziyi dilimliyorlar, ama bu RGB'yi anladığımdan gri tonlamaya dönüştürmekle aynı şey değil.

lum_img = img[:,:,0]

Numpy veya matplotlib'in rgb'den griye dönüştürmek için yerleşik bir işlevi olmadığına inanmak zor. Bu görüntü işlemede yaygın bir işlem değil mi?

imread5 dakika içinde içe aktarılan görüntü ile çalışan çok basit bir fonksiyon yazdım . Bu korkunç derecede verimsiz, ama bu yüzden yerleşik bir profesyonel uygulama umuyordum.

Sebastian işlevimi geliştirdi, ancak hala yerleşik olanı bulmayı umuyorum.

matlab (NTSC / PAL) uygulaması:

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
Basitçe olarak rgb2gray fonksiyonu olarak aynı şeyi yazabilirsiniz Not: gray = np.mean(rgb, -1). Belki rgb[...,:3]aslında rgba ise.
seberg

hmm, iyi gray = np.mean(rgb, -1)çalışıyor. Teşekkürler. Bunu kullanmamak için bir neden var mı? Bunun yerine çözümleri aşağıdaki cevaplarda neden kullanayım?
waspinator

6
Sayfanın wikipedia gri tonlama gri tonlama RGB dönüşüm yöntemi benzersiz değil ama parlaklığın dayalı yaygın olarak kullanılan formüller verir diyor. Bundan oldukça farklı np.mean(rgb, -1).
unutbu

2
bu yüzden sanırım Matlab'ın versiyonunu istiyorum ? 0.2989 * R + 0.5870 * G + 0.1140 * B Bunu yapmanın standart yolu olduğunu varsayıyorum.
waspinator

Yanıtlar:


308

Yastık ile yapmaya ne dersin :

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

Matplotlib ve formülü kullanma

Y' = 0.2989 R + 0.5870 G + 0.1140 B 

şunları yapabilirsiniz:

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
Diye kullanmak zorunda kalırsa matplotlibbaşka bir nedenden dolayı, o yerleşiğini kullanmak gerekir colorsys.rgb_to_yiq()sadece luma kanalını almak için dönüştürmeye artı bir dilim.
Silas Ray

36
neden .convert('LA')? neden olmasın .convert('gray')? Gereksizce şifreli görünüyor. PIL dokümantasyon dönüştürme işlevi için 'LA' konusundan hiç söz etmez.
waspinator

26
PIL kullanarak cannot write mode LA as JPEG
:,

6
Bu img = Image.open('image.png').convert('LA')olması gerekiyorimg = Image.open('image.png').convert('L')
nviens

12
@BluePython: LAmodda parlaklık (parlaklık) ve alfa vardır. LAModu kullanırsanız greyscale.png, alfa kanalı image.pngkorunmuş bir RGBA görüntüsü olacaktır . LModu kullanırsanız , greyscale.pngbir RGB görüntüsü olacaktır (alfa olmadan).
unutbu

71

Ayrıca kullanabilirsiniz scikit-image bir görüntü dönüştürmek için bazı fonksiyonları sağlar, ndarraygibi rgb2gray.

from skimage import color
from skimage import io

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

Notlar : Bu dönüşümde kullanılan ağırlıklar çağdaş CRT fosforları için kalibre edilmiştir: Y = 0.2125 R + 0.7154 G + 0.0721 B

Alternatif olarak, görüntüyü gri tonlarında şu şekilde okuyabilirsiniz:

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

0 <değerleri <1 almam normal mi? Gerçek gri skalayı elde etmek için bunları 255 ile çarpmam gerekir mi?
Sam

amacımın GLCM özelliklerini (greycoprops) kullanmak olduğunu bilmek
Sam

İo.imread için not: "as_grey", "as_gray" lehine kullanımdan kaldırıldı. Aynı kullanım, sadece Amerikan yazımı. :)
Halojen

1
Bunun eldeki soruya en yararlı cevap olduğuna inanıyorum, bunun çıktısı da matplotlib ve numpy ile uyumlu.
Mert Beşiktepe

Renk nesnesini kullanıyorum ancak görüntüm şimdi kırmızımsı ve gri değil (siyah beyaz). Pyplot.imshow () ` cmapolarak kullanmam gerekiyor gray' then only the image is shown as gray in ? Düşüncesi olan var mı ? Nerede yanılıyorum?
GadaaDhaariGeek

63

Önerilen yöntemlerden üçü, Ubuntu 16.04 LTS'de (SSD'li Xeon E5 2670) Python 3.5 ile çalışan 1000 RGBA PNG görüntüleri (224 x 256 piksel) ile hız açısından test edildi.

Ortalama çalışma süreleri

pil : 1.037 saniye

scipy: 1.040 saniye

sk : 2.120 saniye

PIL ve SciPy özdeş numpydiziler verdi (0 ila 255 arasında). SkImage 0'dan 1'e kadar diziler verir. Ayrıca renkler biraz farklı dönüştürülür, CUB-200 veri kümesindeki örneğe bakın .

SkImage: skimage

PIL : PIL

SciPy : scipy

Original: orijinal

Diff : resim açıklamasını buraya girin

kod

  1. Verim

    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. Çıktı
    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. karşılaştırma
    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. ithalat
    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. Sürümler
    skimage.version
    0.13.0
    scipy.version
    0.19.1
    np.version
    1.13.1

6
SciPy'nin görüntü I / O tam anlamıyla PIL / Pillow'tur. Bu nedenle, SciPy'nin test edilmesi, SciPy'nin sarıcı işlevlerinin getirdiği ihmal edilebilir ek yük ile PIL / Yastık'u etkili bir şekilde yeniden test ediyor. Bu olurdu çok daha kullanışlı OpenCV yerine (ki yok değil kaldıraç PIL / Yastık) (yapar) SciPy için. Bununla birlikte, özel kıyaslama için teşekkürler! SciKit'in getirdiği fark edilebilir yavaşlama büyüleyici ... ve dehşet verici.
Cecil Curry

@CecilCurry OpenCV ile ilgili fikir için teşekkürler! Biraz boş zaman bulduğumda ekleyeceğim.
Maximilian Peters

Upvoted! Aradığım bir cevap değil, ama yine de çok çok ilginç :)
Cyril N.

29

Görüntü dosyasını her zaman imreadOpenCV'den başlayarak hemen gri tonlamalı olarak okuyabilirsiniz :

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

Ayrıca, görüntüyü RGB olarak okumak istiyorsanız, biraz işlem yapın ve ardından OpenCV'den kullanabileceğiniz Gri Ölçek'e dönüştürün cvtcolor:

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


24

En hızlı ve güncel yol, üzerinden takılan Yastık kullanmaktır pip install Pillow.

Kod şöyledir:

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

3
yukarıdaki örnekte olduğu gibi yöntemlerinizi zincirlemiyorsanız convert, görüntünün dönüştürülmüş bir kopyasını döndürür
Matt

32 bit PNG için çalışmaz, değerler 255'e sabitlenir
Andrew Matuk

12

Öğretici hile yapıyor çünkü RGB'de kodlanmış gri tonlamalı bir görüntü ile başlıyor, bu yüzden sadece tek bir renk kanalını dilimliyor ve gri tonlamalı olarak işlem yapıyorlar. Yapmanız gereken temel adımlar, RGB renk uzayından, YUV / YIQ veya HSL / HSV gibi luma / chroma modeline yaklaşan bir şeyle kodlanan bir renk uzayına dönüştürmek, daha sonra luma benzeri kanalı kesip kullanmaktır. gri tonlamalı görüntünüz. matplotlibYUV / YIQ'ya dönüştürmek için bir mekanizma sağlamaz, ancak HSV'ye dönüştürmenize izin verir.

matplotlib.colors.rgb_to_hsv(img)Gri tonunuz için dizideki son değeri (V) kullanmayı ve sonra dilimlemeyi deneyin . Bir luma değeri ile tam olarak aynı değildir, ancak her şeyimatplotlib .

Arka fon:

Alternatif olarak, colorsys.rgb_to_yiq()gerçek luma değeri olan bir renk aralığına dönüştürmek için PIL veya yerleşiği kullanabilirsiniz. Her şeyi girebilir ve kendi luma sadece dönüştürücünüzü yuvarlayabilirsiniz, ancak bu muhtemelen aşırıdır.


9

Bu formülü kullanma

Y' = 0.299 R + 0.587 G + 0.114 B 

Biz yapabiliriz

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'))

Ancak, rengi gri tonlamalı görüntü yazılımına dönüştüren GIMP'in görevi yapmak için üç algoritması vardır.


8

NumPy / SciPy'yi zaten kullanıyorsanız :

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


5
Hem scipy.ndimage.imread()ve scipy.misc.imread()edilir resmen kaldırılmış SciPy 1.0.0 ve edilecek kalıcı olarak kaldırılır SciPy 1.2.0 yılında. SciPy'nin belgeleri imageio.imread()uygun bir yedek olarak önerilmesine rağmen , bu işlevin API'si saçmalık noktasına kadar çıplak kemiklerdir. Sağladığı hiçbir gri tonlama dönüşüm için destek ve böylece birçok uygulama için uygun olmayan kalır - bizimki dahil. </sigh>
Cecil Curry

5
@CecilCurry, renkli bir görüntüyü imageio kullanarak gri tonda nasıl dönüştürebilirsiniz?
0x90

5

şunları yapabilirsiniz:

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

İmg.Convert () kullanın, “L”, “RGB” ve “CMYK” özelliklerini destekler. kip

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)

Çıktı:

[[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. satır img = img.convert('L')mı olmalı ?
Allan Ruin

3

Zaten yüklü bir görüntüyü gri tonlamaya dönüştürmenin bir yolunu arayarak Google aracılığıyla bu soruya geldim.

SciPy ile yapmanın bir yolu:

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
Güzel. Ben sadece daha kısa bir çözüm olacağını not etmek istiyorumimg_gray = numpy.average(img, weights=[0.299, 0.587, 0.114], axis=2)
Akavall

@Akavall Bilmek güzel, teşekkürler! Kısayolunuzun daha hızlı olup olmadığını biliyor musunuz? Değilse, benimkini tutardım çünkü anlaması daha kolay.
Martin Thoma

Zaman etmedim, bağırsak hissim numpy.averagebiraz daha hızlı ama pratik olarak farklı değil. Çözümünüz açık ve R, G, B hakkında ilgili bilgilere sahip, bu yüzden onu saklıyorum. Benim yorum daha fazla bir seçenek, bir yedek değildi.
Akavall

Hem scipy.ndimage.imread()ve scipy.misc.imread()edilir resmen kaldırılmış SciPy 1.0.0 ve edilecek kalıcı olarak kaldırılır SciPy 1.2.0 yılında. Muhtemelen sadece (ala Pillow en yerleşik gri tonlama dönüşüm desteğini kullanmak istiyorum unutbu 'ın cevabı yerine,).
Cecil Curry

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

greyscale()Dönüşüm için doğrudan kullanabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.