Manipulasi Gambar dengan Python - Pillow
Tentang PIL (Python Imaging Library) dan Pillow
PIL adalah library open-source tambahan untuk Python yang fungsi utamanya adalah memanipulasi file gambar. PIL diciptakan oleh Fredrik Lundh pada tahun 1995, dan pengembangannya dihentikan pada tahun 2011. PIL di-fork dan diteruskan oleh library Pillow.
Pillow mendukung banyak format file populer, misalnya PNG, JPG/JPEG, TIFF, dan BMP. Jika perlu, Pillow dan Python mendukung library decoder tambahan. Tipe manipulasi antara lain masking, filtering, enhancement, menambahkan teks, manipulasi per pixel, dan lain-lain.
Persiapan Environment
Siapkan dan gunakan venv khusus yang masih bersih (saran) dengan mkvirtualenv nama_venv
. Install Pillow menggunakan pip
pip install Pillow
(Pillow tidak dapat dipasang di env yang sama dengan PIL.)
Output:
(gambar1) gp@pop-os-3770k:~/Devel/py$ pip install Pillow
Collecting Pillow
Downloading Pillow-8.1.2-cp38-cp38-manylinux1_x86_64.whl (2.2 MB)
|████████████████████████████████| 2.2 MB 1.0 MB/s
Installing collected packages: Pillow
Successfully installed Pillow-8.1.2
Untuk mengimpor Pillow:
from PIL import Image
Perhatikan bahwa keyword untuk nama modulnya adalah PIL, bukan Pillow untuk alasan backward compatibility. Kita akan menggunakan kelas Image
di latihan ini.
Note: untuk linux, install lib yang dibutuhkan di sistem:
sudo apt install libjpeg-dev zlib1g-dev
Gambar untuk Latihan
Boleh apa saja, yang penting berukuran kecil supaya tidak menyebabkan lambat dan no profanity, please... Btw, ini gambar Lena Forsén:
Semua instruksi di bawah bisa dikerjakan dalam satu file python. Run dengan cara:
python nama_file.py
Membuka dan Menyimpan Gambar
Metode open()
pada latihan ini cukup sederhana. Lihat screenshot kode di bawah.
Metode show()
digunakan untuk menampilkan file dengan program yang disediakan OS. Metode ini dapat menimbulkan error jika sistem tidak mendukung.
Pada saat menyimpan gambar menggunakan save()
, kita bisa mengubah formatnya dengan cara menyebutkan nama file lengkap dengan ekstensi atau secara eksplisit:
image_object.save(fp, format=None, **params)
dimana
image_object
: instansi dari Image, sesuaikan namanyafp
: nama file (string), pathlib.Path, obyek fileformat
: (opsional) ekstensi, misal'BMP'
**params
: kwargs opsional, tidak dijelaskan di sini
Atribut Gambar
Ada beberapa atribut dari obyek gambar yang bisa digunakan untuk mengetahui info tentang obyek gambar itu:
filename
: nama atau path file, misallena.png
format
: mengembalikan format gambar, misalPNG
mode
: format pixel, misalRGB
atauCMYK
size
: tuple dua elemen dimensi gambar, lebar x tinggi, misal(1280, 721)
width
danheight
info
: info tambahan, misal dpi
Contoh pemanggilan atribut (menggunakan Python interpreter di terminal Linux):
>>> img.filename
'cow.jpg'
>>> img.size
(1280, 720)
Mengubah Dimensi Gambar (Resize)
Untuk mengubah dimensi (lebar x tinggi) gambar, kita bisa menggunakan resize()
dengan beberapa parameter.
resized_img = image_object.resize(tuple, resample=Image.BICUBIC)
resized_img.save('newfile.gif')
dimana
image_object
: instansi Imagetuple
adalah tuple dimensi gambar lebar x tinggi, misal(300, 150)
(perhatikan tanda kurung ya...)resample
: opsional, pilihannya:Image.NEAREST
Image.BOX
Image.BILINEAR
Image.HAMMING
Image.BICUBIC
Image.LANCZOS
Membuat Thumbnail
Operasi ini mirip dengan resize, namun pembuatan thumbnail memperhatikan aspect ratio, sehingga dimensi gambar yang dihasilkan belum tentu sesuai dengan parameter yang kita masukkan. Metodenya adalah thumbnail()
.
image_object.thumbnail((lebar, tinggi))
image_object.save('thumb.gif')
Oiya, apa itu thumbnail? Thumbnail adalah versi gambar dan video yang sudah diseragamkan dimensinya, misalnya ke 256 x 256 pixel. Thumbnail biasanya disimpan bersama gambar/video asli. Tujuan thumbnail antara lain mengurangi bandwidth dan waktu download. Gambar asli hanya ditampilkan jika memang diperlukan.
Update 4 Januari 2022: Mohon maaf metode thumbnail memodifikasi citra secara in-place. Kode di atas sudah saya ubah untuk memperbaiki kesalahan sebelumnya.
Memotong (Cropping) Gambar
Seperti bisa dilihat di bawah, metodenya adalah crop()
.
crop_img = image_object.crop((340, 20, 560, 230))
crop_img.save('cropped.jpg')
Perhatikan, pada sistem koordinat kartesian untuk Pillow, titik x, y = 0, 0
berada di kiri atas gambar. Sintaksnya adalah
cropped = Image.crop( ( x, y, x + lebar , y + tinggi ) )
# atau
cropped = Image.crop( ( kiri, atas, kanan, bawah ) )
Untuk kode di atas, ilustrasinya sbb:
Ini akan menghasilkan cropped image dengan dimensi (560 - 340) x (230 - 20) = 220 x 210
Menambahkan Border pada Gambar
Border bisa ditambahkan dengan cara membuat gambar baru. Pada contoh ini, kita akan membuat border dengan tebal 10 pixel, maka gambar yang akan kita buat (dengan latar belakang red) harus 20 pixel lebih besar.
border_im = image_object.new('RGB', (img.width+20, img.height+20), 'red')
border_im.paste(img, (10, 10))
border_im.save('lena-border.jpg')
Memutar (Rotate) Gambar
Kita bisa menggunakan metode transpose()
dengan satu parameter:
from PIL import Image
img = Image.open('lena.png')
rotated = img.transpose(Image.ROTATE_90)
rotated.show()
rotated.save('rotate90.jpg')
Beberapa parameter rotasi gambar:
PIL.Image.ROTATE_90
PIL.Image.ROTATE_180
PIL.Image.ROTATE_270
Rotasi berlawanan jalan jarum jam. Kalau mau lebih bebas lagi, kita bisa menggunakan Image.rotate()
:
Image.rotate(angle, resample=0, expand=0, center=None)
dimana
angle
: sudut (berlawanan jalan jarum jam)expand
: jika True, dimensi gambar akan disesuaikan untuk memuat hasil rotasi seutuhnyacenter
: pusat rotasi dalam tuple (x, y). Default adalah titik tengah gambarresample
: lihat penjelasan di bagian Resize
Flip
Masih menggunakan metode transpose()
:
from PIL import Image
img = Image.open('lena.png')
# Flip kiri-kanan (axis vertikal)
flipped = img.transpose(Image.FLIP_LEFT_RIGHT)
flipped.show()
flipped.save('flipped.jpg')
Dan tentu saja masih ada flip atas-bawah (axis horizontal): PIL.Image.FLIP_TOP_BOTTOM
.
Brightness, Contrast, dan Sharpness
Untuk ketiga tipe manipulasi ini, ada yang disebut faktor 1 (factor of one). Nilai 1 ini adalah gambar asli sebelum manipulasi. Kelas di library Pillow yang akan kita gunakan adalah ImageEnhance
.
from PIL import Image, ImageEnhance
Brightness
Untuk faktor: brighter > 1 > darker
from PIL import Image, ImageEnhance
img = Image.open("lena.png")
# buat instansi enhancer untuk brightness
enhancer = ImageEnhance.Brightness(img)
factor = 1
# panggil metode enhance untuk memanipulasi
im_output = enhancer.enhance(factor)
#im_output.save('original-image.png')
factor = 0.5 # darkens
im_output = enhancer.enhance(factor)
im_output.save('darkened.png')
factor = 1.5 # brightens
im_output = enhancer.enhance(factor)
im_output.save('brightened.png')
Contrast
Untuk faktor: kontras > 1 > kelabu
from PIL import Image, ImageEnhance
img = Image.open("lena.png")
enhancer = ImageEnhance.Contrast(img)
factor = 1
im_output = enhancer.enhance(factor)
#im_output.save('original-image.png')
factor = 0.5 # kurangi kontras
im_output = enhancer.enhance(factor)
im_output.save('less-contrast.png')
factor = 1.5 # tambah kontras
im_output = enhancer.enhance(factor)
im_output.save('more-contrast.png')
Sharpness
Untuk faktor: tajam > 1 > buram
from PIL import Image, ImageEnhance
img = Image.open('lena.png')
enhancer = ImageEnhance.Sharpness(img)
factor = 1
im_s_1 = enhancer.enhance(factor)
#im_s_1.save('original-image.png')
factor = 0.05
im_s_1 = enhancer.enhance(factor)
im_s_1.save('blurred.png')
factor = 2
im_s_1 = enhancer.enhance(factor)
im_s_1.save('sharpened.png')
Watermark
Kode di bawah adalah untuk menambahkan watermark berupa teks. Untuk latihan, gunakan nomor pokok mahasiswa (NPM) sebagai teks watermark. Pada contoh ini, lokasi watermark adalah di kanan bawah gambar dengan margin 15 pixel agar tulisan tidak terlalu ke tepi.
Penting: font Arial bisa diunduh disini. Taruh file ttf
di direktori yang sama dengan kode program.
# Sesuaikan kelas-kelas yang diimpor dari Pillow
from PIL import Image, ImageDraw, ImageFont
# Buka gambar sumber
img = Image.open('lena.png')
width, height = img.size # lebar dan tinggi untuk kalkulasi koordinat teks
# menambahkan elemen 2d ke gambar yang sudah ada
draw = ImageDraw.Draw(img)
text = '13113770' # ganti dengan npm mu...
# mendefinisikan font baru, lengkap dengan ukurannya
font = ImageFont.truetype('arial.ttf', 18)
# hitung lebar dan tinggi font relatif terhadap gambar utama
textwidth, textheight = draw.textsize(text, font)
# hitung koordinat x, y teks
margin = 15
x = width - textwidth - margin
y = height - textheight - margin
# terapkan watermark
draw.text((x, y), text, font=font)
img.show()
# Simpan gambar
img.save('watermark.jpg')
Gambar dengan watermark: