Bagaimana saya bisa mengubah gambar RGB menjadi skala abu-abu dengan Python?

206

Saya mencoba menggunakan matplotlib untuk membaca dalam gambar RGB dan mengubahnya menjadi skala abu-abu.

Di matlab saya menggunakan ini:

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

Dalam tutorial matplotlib mereka tidak membahasnya. Mereka baru saja membaca gambar

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

dan kemudian mereka mengiris array, tapi itu tidak sama dengan mengubah RGB menjadi grayscale dari apa yang saya mengerti.

lum_img = img[:,:,0]

Saya merasa sulit untuk percaya bahwa numpy atau matplotlib tidak memiliki fungsi bawaan untuk mengkonversi dari rgb ke grey. Bukankah ini operasi yang umum dalam pemrosesan gambar?

Saya menulis fungsi yang sangat sederhana yang berfungsi dengan gambar yang diimpor menggunakan imreaddalam 5 menit. Ini sangat tidak efisien, tapi itu sebabnya saya berharap untuk implementasi profesional built-in.

Sebastian telah meningkatkan fungsi saya, tetapi saya masih berharap untuk menemukan yang built-in.

implementasi 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
waspinator
sumber
2
Perhatikan bahwa Anda dapat menulis hal yang sama seperti fungsi rgb2gray Anda hanya sebagai: gray = np.mean(rgb, -1). Mungkin rgb[...,:3]ada jika itu sebenarnya rgba.
seberg
hmm, gray = np.mean(rgb, -1)berfungsi dengan baik. Terima kasih. Apakah ada alasan untuk tidak menggunakan ini? Mengapa saya menggunakan solusi dalam jawaban di bawah?
waspinator
6
The grayscale wikipedia Halaman mengatakan metode mengkonversi RGB ke grayscale tidak unik, tapi memberikan formula yang umum digunakan berdasarkan luminance. Sangat berbeda dari np.mean(rgb, -1).
unutbu
2
jadi saya kira saya ingin versi Matlab ? 0.2989 * R + 0.5870 * G + 0.1140 * B Saya berasumsi bahwa itu adalah cara standar untuk melakukannya.
waspinator

Jawaban:

304

Bagaimana kalau melakukannya dengan Bantal :

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

Menggunakan matplotlib dan formula

Y' = 0.2989 R + 0.5870 G + 0.1140 B 

Anda bisa melakukan:

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()
unutbu
sumber
3
Jika dia harus menggunakan matplotlibuntuk beberapa alasan lain, dia harus dapat menggunakan builtin colorsys.rgb_to_yiq()untuk mengubah dan sepotong untuk mendapatkan hanya saluran luma.
Silas Ray
34
mengapa .convert('LA')? mengapa tidak .convert('gray')? Tampak samar samar. The dokumentasi PIL tidak menyebutkan apa-apa tentang 'LA' untuk mengkonversi fungsi.
waspinator
25
menggunakan PIL cannot write mode LA as JPEG
:,
6
Ini img = Image.open('image.png').convert('LA')harusimg = Image.open('image.png').convert('L')
nviens
12
@ BluePython: LAmode memiliki luminositas (kecerahan) dan alfa. Jika Anda menggunakan LAmode, maka greyscale.pngakan menjadi gambar RGBA dengan saluran alfa image.pngdipertahankan. Jika Anda menggunakan Lmode, maka greyscale.pngakan menjadi gambar RGB (tanpa alfa).
unutbu
69

Anda juga dapat menggunakan scikit-image , yang menyediakan beberapa fungsi untuk mengkonversi gambar ndarray, seperti rgb2gray.

from skimage import color
from skimage import io

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

Catatan : Bobot yang digunakan dalam konversi ini dikalibrasi untuk fosfor CRT kontemporer: Y = 0,2125 R + 0,7154 G + 0,0721 B

Atau, Anda dapat membaca gambar dalam skala abu-abu dengan:

from skimage import io
img = io.imread('image.png', as_gray=True)
Yangjie
sumber
Apakah normal saya mendapatkan 0 <nilai <1? Apakah saya harus mengalikannya dengan 255 untuk mendapatkan skala abu-abu yang sebenarnya?
Sam
mengetahui bahwa tujuan saya adalah menggunakan fitur GLCM (greycoprops)
Sam
Catatan untuk io.imread: "as_grey" telah usang karena "as_gray". Penggunaan yang sama, hanya ejaan Amerikanisasi. :)
Halogen
1
Saya percaya ini adalah jawaban yang paling berguna untuk pertanyaan yang ada, output dari ini juga kompatibel dengan matplotlib dan numpy.
Mert Beşiktepe
Saya menggunakan objek warna tetapi gambar saya agak kemerahan sekarang dan tidak abu-abu (hitam dan putih). Saya perlu menggunakan cmapsebagai gray' then only the image is shown as gray in pyplot.imshow () `? Adakah pikiran? Dimana saya salah
GadaaDhaariGeek
63

Tiga dari metode yang disarankan diuji untuk kecepatan dengan 1000 gambar RGBA PNG (224 x 256 piksel) berjalan dengan Python 3.5 pada Ubuntu 16,04 LTS (Xeon E5 2670 dengan SSD).

Waktu lari rata-rata

pil : 1,037 detik

scipy: 1,040 detik

sk : 2,120 detik

PIL dan SciPy memberikan numpyarray yang identik (mulai dari 0 hingga 255). SkImage memberikan array dari 0 hingga 1. Selain itu, warna-warna tersebut dikonversi sedikit berbeda, lihat contoh dari dataset CUB-200.

SkImage: SkImage

PIL : PIL

SciPy : SciPy

Original: Asli

Diff : masukkan deskripsi gambar di sini

Kode

  1. Performa

    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. Keluaran
    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. Perbandingan
    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. Impor
    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. Versi
    skimage.version
    0.13.0
    scipy.version
    0.19.1
    np.version
    1.13.1
Maximilian Peters
sumber
6
Gambar SciPy I / O secara harfiah PIL / Pillow. Oleh karena itu, pengujian SciPy secara efektif menguji ulang PIL / Pillow dengan overhead yang dapat diabaikan yang diperkenalkan oleh fungsi wrapper SciPy. Akan jauh lebih bermanfaat untuk mengganti OpenCV (yang tidak memanfaatkan PIL / Pillow) untuk SciPy (yang memang). Meskipun demikian, terima kasih atas pembandingan khusus! Perlambatan yang terlihat oleh SciKit sangat menarik ... dan mengerikan.
Cecil Curry
@CecilCurry Terima kasih atas idenya dengan OpenCV! Saya akan menambahkannya ketika saya menemukan waktu luang.
Maximilian Peters
Terpilih! Bukan jawaban yang saya cari, tapi tetap sangat sangat menarik :)
Cyril N.
29

Anda selalu dapat membaca file gambar sebagai skala abu-abu sejak awal menggunakan imreaddari OpenCV:

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

Lebih jauh, jika Anda ingin membaca gambar sebagai RGB, lakukan pemrosesan dan kemudian konversikan ke Skala Abu-abu yang dapat Anda gunakan cvtcolordari OpenCV:

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
Diamantatos Paraskevas
sumber
6
Ftr: 0Bendera adalah cv2.CV_LOAD_IMAGE_GRAYSCALE.
dtk
24

Cara tercepat dan saat ini adalah menggunakan Bantal , dipasang melaluipip install Pillow .

Kodenya adalah:

from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')
YPCrumble
sumber
3
Perhatikan bahwa, jika Anda tidak merantai metode Anda seperti dalam contoh di atas, convertmengembalikan salinan gambar yang dikonversi
Matt
tidak berfungsi untuk 32 bit PNG, nilai akan dijepit ke 255
Andrew Matuk
11

Tutorial ini curang karena dimulai dengan gambar skala abu-abu yang dikodekan dalam RGB, sehingga mereka hanya memotong satu saluran warna dan memperlakukannya sebagai skala abu-abu. Langkah-langkah dasar yang perlu Anda lakukan adalah mengubah dari ruang warna RGB ke ruang warna yang mengkodekan dengan sesuatu yang mendekati model luma / chroma, seperti YUV / YIQ atau HSL / HSV, kemudian memotong saluran seperti luma dan menggunakannya sebagai gambar skala abu-abu Anda. matplotlibtampaknya tidak menyediakan mekanisme untuk mengonversi ke YUV / YIQ, tetapi ia memungkinkan Anda mengonversi ke HSV.

Coba gunakan matplotlib.colors.rgb_to_hsv(img)kemudian mengiris nilai terakhir (V) dari array untuk skala abu-abu Anda. Ini tidak sama dengan nilai luma, tetapi itu berarti Anda dapat melakukan semuanyamatplotlib .

Latar Belakang:

Atau, Anda bisa menggunakan PIL atau builtin colorsys.rgb_to_yiq()untuk mengonversi ke ruang warna dengan nilai luma yang sebenarnya. Anda juga dapat masuk dan memutar konverter hanya-luma Anda sendiri, meskipun itu mungkin berlebihan.

Silas Ray
sumber
9

Menggunakan rumus ini

Y' = 0.299 R + 0.587 G + 0.114 B 

Kita bisa

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

Namun, konversi warna GIMP ke perangkat lunak gambar grayscale memiliki tiga algoritma untuk melakukan tugas tersebut.

iNet
sumber
8

Jika Anda sudah menggunakan NumPy / SciPy, Anda sebaiknya menggunakan :

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

dtk
sumber
5
Keduanya scipy.ndimage.imread()dan scipy.misc.imread()secara resmi ditinggalkan dalam SciPy 1.0.0 dan akan dihapus secara permanen di SciPy 1.2.0. Meskipun dokumentasi SciPy merekomendasikan imageio.imread()sebagai pengganti yang sesuai, API fungsi ini adalah tulang belulang sampai titik absurditas. Ini tidak memberikan dukungan untuk konversi skala abu-abu dan dengan demikian tetap tidak cocok untuk banyak aplikasi - termasuk kami. </sigh>
Cecil Curry
5
@ CecilCurry, bagaimana Anda mengonversi gambar berwarna dalam skala abu-abu menggunakan imageio?
0x90
5

Anda bisa melakukan:

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()
am.mansour
sumber
5

Gunakan img.Convert (), mendukung "L", "RGB" dan "CMYK." mode

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)

Keluaran:

[[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]]
naren
sumber
1
seharusnya baris ke-5 img = img.convert('L')?
Allan Ruin
3

Saya sampai pada pertanyaan ini melalui Google, mencari cara untuk mengkonversi gambar yang sudah dimuat ke skala abu-abu.

Ini cara untuk melakukannya dengan 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)
Martin Thoma
sumber
1
Bagus. Saya hanya ingin mencatat solusi yang lebih singkat adalahimg_gray = numpy.average(img, weights=[0.299, 0.587, 0.114], axis=2)
Akavall
@Akavall Senang mengetahui, terima kasih! Apakah Anda tahu jika pintasan Anda lebih cepat? Jika tidak, saya akan menyimpan milik saya karena lebih mudah dimengerti.
Martin Thoma
Saya tidak mengatur waktu, firasat saya numpy.averagesedikit lebih cepat tetapi tidak berbeda. Solusi Anda jelas dan memiliki informasi yang relevan tentang R, G, B, jadi saya akan menyimpannya. Komentar saya lebih merupakan opsi tambahan, bukan pengganti.
Akavall
Keduanya scipy.ndimage.imread()dan scipy.misc.imread()secara resmi ditinggalkan dalam SciPy 1.0.0 dan akan dihapus secara permanen di SciPy 1.2.0. Anda mungkin hanya ingin menggunakan dukungan konversi builtin grayscale Bantal ini (ala unutbu 's jawaban ), sebagai gantinya.
Cecil Curry
-3
image=myCamera.getImage().crop(xx,xx,xx,xx).scale(xx,xx).greyscale()

Anda dapat menggunakan greyscale()langsung untuk transformasi.

Qian Han
sumber