Mengajari Komputer Memisahkan Objek dari Latar Belakang
Segmentasi Citra dan Thresholding dengan Python
ALIMIN, M.Kom
Dasar
01Komputer melihat angka
Kamu melihat daun di atas tanah dalam sepersekian detik. Komputer melihat apa?
Bagi komputer, citra hanyalah tabel angka 0 sampai 255. Ini potongan nyata dari tepi daun pada gambar berikut:
| 61 | 60 | 60 | 59 | 60 | 72 | 102 | 128 | 138 | 139 |
| 62 | 62 | 62 | 62 | 70 | 93 | 122 | 137 | 139 | 139 |
| 62 | 63 | 64 | 67 | 86 | 116 | 135 | 139 | 139 | 139 |
| 63 | 61 | 64 | 79 | 108 | 132 | 139 | 139 | 139 | 139 |
| 63 | 62 | 71 | 99 | 127 | 138 | 139 | 139 | 139 | 139 |
Angka yang melonjak dari sekitar 80 ke sekitar 140 adalah batas daun. Pertemuan ini mengajarkan cara komputer memutuskannya.
02Apa itu segmentasi citra?Membagi gambar agar objek terpisah dari latar
- Membagi gambar menjadi bagian-bagian agar objek yang dianalisis terpisah dari yang lain.
- Segmentasi memisahkan area berdasarkan intensitas, warna, atau batas. Ia belum tentu menyebut nama objeknya.
03Mengapa segmentasi dibutuhkan?Contoh nyata di pertanian, kesehatan, industri
- Pertanian: memisahkan daun dari latar untuk menganalisis kondisi tanaman.
- Kesehatan: menandai area tertentu pada citra medis.
- Industri: memeriksa bentuk dan batas produk.
- Kendaraan otonom: mengenali batas jalan dan objek sekitar.
- Aplikasi AI: menyiapkan citra sebelum klasifikasi atau deteksi objek.
Persiapan
04Peta perjalanan programAlur program dan library yang dipakai
- Buka aplikasi: Tkinter membuat jendela dan komponen.
- Muat gambar:
load_image(). - Pilih metode: thresholding, deteksi tepi, atau warna.
- Proses piksel:
apply_segmentation(). - Tampilkan hasil:
render().
| Library | Fungsi | Perumpamaan |
|---|---|---|
| tkinter | Jendela, tombol, slider | Ruang kerja |
| cv2 (OpenCV) | Thresholding dan deteksi tepi | Alat pengolah gambar |
| numpy | Data piksel sebagai matriks | Kalkulator piksel |
| PIL (Pillow) | Gambar ke antarmuka Tkinter | Penghubung ke layar |
05Grayscale: menyederhanakan duniaY = 0,299 R + 0,587 G + 0,114 B
Rumus: Y = 0,299 R + 0,587 G + 0,114 B. Nilai 0 hitam, 128 abu-abu menengah, 255 putih.
Thresholding
06Manual Threshold: garis penentuJika f(x,y) > T maka putih, selain itu hitam
Jika f(x,y) > T maka piksel menjadi 255 (putih), selain itu 0 (hitam).
| Piksel | 30 | 100 | 128 | 180 | 240 |
|---|---|---|---|---|---|
| Hasil (T = 128) | 0 | 0 | 0 | 255 | 255 |
07Coba langsung: geser nilai ambangSimulasi interaktif langsung di halaman ini
Amati: pada T sekitar 100 sampai 135 daun terpisah rapi dari tanah. Terlalu rendah, semuanya putih. Terlalu tinggi, semuanya hitam.
08Otsu: ambang yang menemukan dirinya sendiriAmbang otomatis dari histogram
- Otsu memilih T dari histogram untuk memisahkan kelompok gelap dan terang sebaik mungkin: variasi dalam kelompok sekecil mungkin, variasi antarkelompok sebesar mungkin.
- Slider tidak dipakai. Kurang baik jika intensitas objek dan latar saling tumpang tindih.
09Adaptive Gaussian: ambang yang peka lingkunganAmbang berbeda untuk tiap area
Ambang dihitung per area: T(x,y) = G(x,y) − C, dengan jendela 11 × 11 dan C = 2. Slider tidak memengaruhinya.
10Tiga metode pada satu dokumen berbayanganManual, Otsu, dan Adaptive dibandingkan
| Metode | Ambang | Slider |
|---|---|---|
| Manual | Ditentukan pengguna | Ya |
| Otsu | Otomatis, satu nilai global | Tidak |
| Adaptive | Otomatis, lokal per area | Tidak |
Tidak ada metode terbaik. Yang ada metode yang cocok dengan karakter gambar.
Praktik & Penutup
11Source code praktik: segmentasi_citra.pyKode Python lengkap, bisa disalin dan diunduh
import tkinter as tk
from tkinter import filedialog, ttk
import cv2
import numpy as np
from PIL import Image, ImageTk
class SegmentationApp:
def __init__(self, root):
self.root = root
self.root.title("Pertemuan 6 & 7: Segmentasi Citra & Deteksi Tepi")
self.root.geometry("1000x650")
self.root.configure(bg="#f8fafc")
self.cv_img = None
self.setup_ui()
def setup_ui(self):
hdr = tk.Frame(self.root, bg="#b45309", pady=10)
hdr.pack(fill=tk.X)
tk.Label(hdr, text="P06-07: SEGMENTASI AMBANG (THRESHOLDING), DETEKSI TEPI & WARNA",
font=("Segoe UI", 12, "bold"), fg="white", bg="#b45309").pack()
ctrl = tk.Frame(self.root, bg="#f8fafc", pady=10)
ctrl.pack(fill=tk.X, padx=15)
tk.Button(ctrl, text="Load Citra", command=self.load_image, bg="#d97706", fg="white", padx=10).pack(side=tk.LEFT)
# DIPERBAIKI: nilai awal harus sama persis dengan salah satu isi daftar methods
self.method_var = tk.StringVar(value="Canny Edge Detector")
methods = ["Manual Threshold", "Otsu Thresholding", "Adaptive Gaussian", "Sobel Edge Detector", "Canny Edge Detector", "Segmentasi Hijau (HSV)"]
combo = ttk.Combobox(ctrl, textvariable=self.method_var, values=methods, state="readonly", width=24)
combo.pack(side=tk.LEFT, padx=10)
combo.bind("<<ComboboxSelected>>", self.apply_segmentation)
tk.Label(ctrl, text="Ambang/Thresh Slider:", bg="#f8fafc").pack(side=tk.LEFT, padx=(10, 2))
self.slider = tk.Scale(ctrl, from_=0, to=255, orient=tk.HORIZONTAL, command=self.apply_segmentation)
self.slider.set(128)
self.slider.pack(side=tk.LEFT, padx=5)
# Dual Panel
body = tk.Frame(self.root, bg="#f8fafc")
body.pack(fill=tk.BOTH, expand=True, padx=15, pady=10)
f1 = tk.LabelFrame(body, text="Citra Asli", bg="#ffffff")
f1.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5)
self.lbl_orig = tk.Label(f1, text="Pilih citra", bg="#f1f5f9")
self.lbl_orig.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
f2 = tk.LabelFrame(body, text="Hasil Segmentasi / Kontur", bg="#ffffff")
f2.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5)
self.lbl_res = tk.Label(f2, text="Belum diproses", bg="#f1f5f9")
self.lbl_res.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
def load_image(self):
p = filedialog.askopenfilename(filetypes=[("Image Files", "*.png *.jpg *.jpeg *.bmp")])
if not p:
return
self.cv_img = cv2.imread(p)
# DIPERBAIKI: batalkan jika file gagal dibaca (imread mengembalikan None)
if self.cv_img is None:
return
self.render(self.cv_img, self.lbl_orig)
self.apply_segmentation()
def apply_segmentation(self, _=None):
if self.cv_img is None:
return
method = self.method_var.get()
th_val = self.slider.get()
gray = cv2.cvtColor(self.cv_img, cv2.COLOR_BGR2GRAY)
if method == "Manual Threshold":
_, res = cv2.threshold(gray, th_val, 255, cv2.THRESH_BINARY)
res = cv2.cvtColor(res, cv2.COLOR_GRAY2BGR)
elif method == "Otsu Thresholding":
_, res = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
res = cv2.cvtColor(res, cv2.COLOR_GRAY2BGR)
elif method == "Adaptive Gaussian":
res = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
res = cv2.cvtColor(res, cv2.COLOR_GRAY2BGR)
elif method == "Sobel Edge Detector":
sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
res = np.uint8(np.clip(np.sqrt(sobelx**2 + sobely**2), 0, 255))
res = cv2.cvtColor(res, cv2.COLOR_GRAY2BGR)
elif method == "Canny Edge Detector":
res = cv2.Canny(gray, th_val, th_val * 2)
res = cv2.cvtColor(res, cv2.COLOR_GRAY2BGR)
elif method == "Segmentasi Hijau (HSV)":
hsv = cv2.cvtColor(self.cv_img, cv2.COLOR_BGR2HSV)
lower_green = np.array([25, 40, 40])
upper_green = np.array([85, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
res = cv2.bitwise_and(self.cv_img, self.cv_img, mask=mask)
else:
res = self.cv_img
self.render(res, self.lbl_res)
def render(self, cv_img, lbl):
rgb = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
h, w, _ = rgb.shape
scale = min(440 / w, 450 / h)
disp_w = max(1, int(w * scale))
disp_h = max(1, int(h * scale))
resized = cv2.resize(rgb, (disp_w, disp_h))
img_tk = ImageTk.PhotoImage(image=Image.fromarray(resized))
lbl.config(image=img_tk, text="")
lbl.image = img_tk
if __name__ == "__main__":
r = tk.Tk()
app = SegmentationApp(r)
r.mainloop()
Dua perbaikan kecil sudah ditandai DIPERBAIKI: nilai awal dropdown dan pemeriksaan gambar gagal dibaca.
12Bereksperimen sendiri (bukan tugas) dan jembatan ke UTSLatihan mandiri dan pesan untuk UTS
- Muat foto daun dan foto dokumen, lalu jalankan Manual Threshold pada 50, 128, dan 200.
- Bandingkan Otsu dengan Adaptive Gaussian pada foto dokumen berbayangan.
- Geser slider saat Otsu atau Adaptive aktif. Apa yang terjadi, dan mengapa?
Fokus pertemuan ini: kelompok menentukan 3 jurnal dengan topik berbeda untuk UTS.
13Satu kalimat untuk dibawa pulangPesan penutup dan persiapan Pertemuan 7
Komputer tidak melihat objek, ia melihat angka. Tugas kita memberinya aturan pemisah yang tepat.
Minggu depan kita memburu tepi dan warna. Sebelum itu, buka Google Scholar atau jurnal nasional dan temukan satu paper pengolahan citra yang membuatmu penasaran. Bawa judulnya ke Pertemuan 7.