Cara mengonversi larik NumPy ke gambar PIL menggunakan matplotlib colormap

134

Saya memiliki masalah sederhana, tetapi saya tidak dapat menemukan solusi yang baik untuk itu.

Saya ingin mengambil array NumPy 2D yang mewakili gambar grayscale, dan mengubahnya menjadi gambar RGB PIL sambil menerapkan beberapa colormaps matplotlib.

Saya bisa mendapatkan output PNG yang masuk akal dengan menggunakan pyplot.figure.figimageperintah:

dpi = 100.0
w, h = myarray.shape[1]/dpi, myarray.shape[0]/dpi
fig = plt.figure(figsize=(w,h), dpi=dpi)
fig.figimage(sub, cmap=cm.gist_earth)
plt.savefig('out.png')

Meskipun saya dapat menyesuaikan ini untuk mendapatkan apa yang saya inginkan (mungkin menggunakan StringIO mendapatkan gambar PIL), saya bertanya-tanya apakah tidak ada cara yang lebih sederhana untuk melakukan itu, karena tampaknya merupakan masalah visualisasi gambar yang sangat alami. Katakanlah, sesuatu seperti ini:

colored_PIL_image = magic_function(array, cmap)
heltonbiker
sumber

Jawaban:

222

Satu baris yang cukup sibuk, tetapi ini dia:

  1. Pertama, pastikan array NumPy Anda myarray,, dinormalisasi dengan nilai maksimal pada 1.0.
  2. Terapkan peta warna langsung ke myarray.
  3. Ubah skala ke 0-255kisaran.
  4. Konversikan ke bilangan bulat, menggunakan np.uint8().
  5. Gunakan Image.fromarray().

Dan Anda sudah selesai:

from PIL import Image
from matplotlib import cm
im = Image.fromarray(np.uint8(cm.gist_earth(myarray)*255))

dengan plt.savefig():

Masukkan deskripsi gambar di sini

dengan im.save():

Masukkan deskripsi gambar di sini

fraxel
sumber
7
Bagian "Terapkan colormap langsung ke myarray" yang dipotong langsung ke jantung! Saya tidak tahu itu mungkin, terima kasih!
heltonbiker
34
Mempelajari dokumen tentang LinearSegmentedColormap (dari mana cm.gist_earth adalah contoh), saya menemukan bahwa mungkin untuk memanggilnya dengan argumen "byte" yang sudah mengubahnya menjadi uint8. Kemudian, jalur satu menjadi jauh lebih tenang:im = Image.fromarray(cm.gist_earth(myarray, bytes=True))
heltonbiker
1
@CiprianTomoiaga, bentuk larik harus berupa dimensi gambar yang Anda inginkan. Misalnya, gambar VGA akan dihasilkan dari larik berbentuk (1024,768). Anda harus memperhatikan bahwa ini berlaku untuk gambar monokrom. Ini penting karena biasanya saat Anda mengonversi gambar RGB menjadi larik, bentuknya adalah, misalnya, (1024.768,3), karena memiliki tiga saluran.
heltonbiker
5
Saya mendapatkan kesalahanNameError: name 'cm' is not defined
rnso
10
@msofrom matplotlib import cm
Quantum7
10
  • input = numpy_image
  • np.unit8 -> mengkonversi ke integer
  • convert ('RGB') -> convert ke RGB
  • Image.fromarray -> mengembalikan objek gambar

    from PIL import Image
    import numpy as np
    
    PIL_image = Image.fromarray(np.uint8(numpy_image)).convert('RGB')
    
    PIL_image = Image.fromarray(numpy_image.astype('uint8'), 'RGB')
    
Aravinda_gn
sumber
5
Semoga Ini akan menyelesaikan masalah tetapi tolong tambahkan penjelasan kode Anda dengannya sehingga pengguna akan mendapatkan pemahaman yang sempurna yang dia benar-benar inginkan.
Jaimil Patel
1
Jawaban yang bagus dan diperbarui. Yang sebelumnya berasal dari beberapa tahun lalu.
Catalina Chircu
7

Metode yang dijelaskan dalam jawaban yang diterima tidak berhasil untuk saya bahkan setelah menerapkan perubahan yang disebutkan dalam komentarnya. Tetapi kode sederhana di bawah ini berfungsi:

import matplotlib.pyplot as plt
plt.imsave(filename, np_array, cmap='Greys')

np_array bisa berupa array 2D dengan nilai dari 0..1 floats o2 0..255 uint8, dan dalam hal ini diperlukan cmap. Untuk larik 3D, cmap akan diabaikan.

Shital Shah
sumber