Materi Pertemuan 6

Materi Pertemuan 6
Pengolahan Citra Digital · Pertemuan 6

Mengajari Komputer Memisahkan Objek dari Latar Belakang

Segmentasi Citra dan Thresholding dengan Python

ALIMIN, M.Kom

Citra asli
Citra asli
Hasil threshold (T = 110)
Hasil threshold (T = 110)

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
Perumpamaan: komputer seperti orang di ruangan gelap yang hanya diberi daftar angka kecerahan, lalu diminta menunjuk mana daun dan mana tanah.

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
Citra asli: objek, latar, bayangan, warna
Citra asli: objek, latar, bayangan, warna
Threshold: hitam dan putih
Threshold: hitam dan putih
Segmentasi warna: hanya hijau dipertahankan
Segmentasi warna: hanya hijau dipertahankan
  • 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.
Perumpamaan: petugas sortir paket. Ia tidak perlu tahu isi paket, cukup memisahkannya berdasarkan ukuran atau label.
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.
Perumpamaan: menyorot bagian penting dengan stabilo sebelum membaca ulang.

Persiapan

04Peta perjalanan programAlur program dan library yang dipakai
  1. Buka aplikasi: Tkinter membuat jendela dan komponen.
  2. Muat gambar: load_image().
  3. Pilih metode: thresholding, deteksi tepi, atau warna.
  4. Proses piksel: apply_segmentation().
  5. 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
Berwarna (BGR, tiga kanal)
Berwarna (BGR, tiga kanal)
Grayscale (satu kanal)
Grayscale (satu kanal)

Rumus: Y = 0,299 R + 0,587 G + 0,114 B. Nilai 0 hitam, 128 abu-abu menengah, 255 putih.

Data: piksel daun R = 40, G = 160, B = 50 menghasilkan Y = 11,96 + 93,92 + 5,70 = 111,6, abu-abu agak gelap.
Perumpamaan: foto berwarna difotokopi hitam-putih. Warna hilang, tetapi terang-gelap tetap ada.

Thresholding

06Manual Threshold: garis penentuJika f(x,y) > T maka putih, selain itu hitam
T = 50: hampir semua putih
T = 50: hampir semua putih
T = 128: daun putih, tanah hitam
T = 128: daun putih, tanah hitam
T = 200: hampir semua hitam
T = 200: hampir semua 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
Perumpamaan: pembatas tinggi badan di wahana: yang melewati garis boleh masuk. Perhatikan 128 tetap hitam karena aturannya "lebih besar dari".
07Coba langsung: geser nilai ambangSimulasi interaktif langsung di halaman ini
Threshold T = 128

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
Histogram: garis merah T otomatis = 104
Histogram: garis merah T otomatis = 104
Hasil Otsu
Hasil Otsu
  • 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.
Perumpamaan: dua kerumunan di lapangan, satu berbaju gelap dan satu terang. Otsu mencari tempat tali pemisah paling adil.
09Adaptive Gaussian: ambang yang peka lingkunganAmbang berbeda untuk tiap area
Dokumen dengan bayangan
Dokumen dengan bayangan
Hasil Adaptive Gaussian
Hasil Adaptive Gaussian

Ambang dihitung per area: T(x,y) = G(x,y) − C, dengan jendela 11 × 11 dan C = 2. Slider tidak memengaruhinya.

Perumpamaan: senter di ruangan remang-remang: tiap bagian halaman dinilai dengan cahayanya sendiri, bukan satu lampu untuk seluruh ruangan.
10Tiga metode pada satu dokumen berbayanganManual, Otsu, dan Adaptive dibandingkan
Manual T = 128: sisi bayangan hilang
Manual T = 128: sisi bayangan hilang
Otsu: satu T global, masih terpengaruh bayangan
Otsu: satu T global, masih terpengaruh bayangan
Adaptive: teks terbaca di seluruh halaman
Adaptive: teks terbaca di seluruh halaman
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
Instal: pip install opencv-python numpy pillow lalu jalankan python segmentasi_citra.py
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
  1. Muat foto daun dan foto dokumen, lalu jalankan Manual Threshold pada 50, 128, dan 200.
  2. Bandingkan Otsu dengan Adaptive Gaussian pada foto dokumen berbayangan.
  3. Geser slider saat Otsu atau Adaptive aktif. Apa yang terjadi, dan mengapa?
Jembatan UTS: grayscale dan thresholding termasuk Research Metode Low Level pada format review UTS. Saat membaca kandidat jurnal, tanyakan: metode apa yang bekerja langsung pada piksel?

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.

Klik judul kartu untuk membuka atau menutup materi.