Manipulasi Gambar dengan Python - Pillow

G. Prasetyadi
1057 views

academics

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 namanya
  • fp: nama file (string), pathlib.Path, obyek file
  • format: (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, misal lena.png
  • format: mengembalikan format gambar, misal PNG
  • mode: format pixel, misal RGB atau CMYK
  • size: tuple dua elemen dimensi gambar, lebar x tinggi, misal (1280, 721)
  • width dan height
  • 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 Image
  • tuple 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().

thumb_img = image_object.thumbnail((lebar, tinggi))
thumb_img.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.

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

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 seutuhnya
  • center: pusat rotasi dalam tuple (x, y). Default adalah titik tengah gambar
  • resample: 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:

## Tugas (Detail submisi tugas yang belum ada di sini, saya lampirkan saat/setelah meeting ya) Kerjakan semua demo di atas dalam satu file Python (lebih dari satu boleh kalau mau repot) (jangan lupa sertakan file gambar yang kalian pakai ya...), unggah **dua** file tersebut ke Git, lalu email ke saya. Waktu pengerjaan satu minggu. Gambar input (yang digunakan untuk `open()`) tidak boleh sama dengan di blog ini ya.. Cari gambar lain yang ukurannya <1 MB, kalau bisa dimensinya tidak square. Hal-hal yang harus di demokan di dalam program: 1. Membuka, menyimpan file ke format lain, menampilkan gambar di OS 2. Menampilkan 7 atribut gambar (nama file, ukuran, dsb..) 3. Mengubah ukuran (resize) lalu save 4. Membuat thumbnail lalu save 5. Cropping lalu save 6. Membuat gambar baru dengan border, lalu save 7. Memutar gambar lalu save 8. Membalik gambar (flip) lalu save 9. Memodifikasi brightness, contrast, dan sharpness, lalu save 10. Menambahkan watermark, lalu save