Segmentasi citra berperan penting untuk memisahkan objek dari latar belakang atau antar objek dalam satu gambar. Namun, tantangan muncul ketika citra yang kita olah tidak “sempurna”, misalnya mengandung noise, alias gangguan visual berupa titik-titik acak atau bintik halus.
Pada eksperimen kali ini, kita akan menguji seberapa kuat tiga metode segmentasi populer (Otsu, Adaptive, dan Watershed) dalam menghadapi citra yang sudah “terkontaminasi” noise.
Metode yang Digunakan
Tiga metode segmentasi digunakan dalam percobaan ini. Pertama, metode Otsu Thresholding, yang menentukan nilai ambang secara otomatis berdasarkan distribusi intensitas piksel di histogram. Kedua, Adaptive Thresholding, yang menghitung nilai ambang secara lokal pada setiap area kecil gambar, bukan pada keseluruhan citra. Ketiga, Watershed Segmentation, yang memperlakukan gambar seperti permukaan topografi dan mencari batas antar objek.
Citra yang digunakan berasal dari dataset coins pada pustaka scikit-image. Citra ini menampilkan kumpulan koin yang saling berdekatan, sehingga cocok untuk menguji kemampuan algoritma segmentasi dalam memisahkan objek yang menempel satu sama lain.
Langkah Eksperimen
1. Menambahkan Noise ke Citra
Kita gunakan Salt and Pepper noise (titik putih dan hitam acak) untuk mensimulasikan gangguan sensor kamera.
from skimage import data, util
import cv2
import numpy as np
from matplotlib import pyplot as plt
# Ambil gambar coins dari skimage
img = data.coins()
# Tambahkan noise
noisy_img = util.random_noise(img, mode='s&p', amount=0.05)
noisy_img = (noisy_img * 255).astype(np.uint8)
plt.figure(figsize=(10,4))
plt.subplot(1,2,1)
plt.title("Original Image")
plt.imshow(img, cmap='gray')
plt.axis('off')
plt.subplot(1,2,2)
plt.title("Noisy Image (Salt & Pepper)")
plt.imshow(noisy_img, cmap='gray')
plt.axis('off')
plt.show()
2. Terapkan Metode Segmentasi
Masing-masing metode kemudian diterapkan untuk memisahkan objek dari latar belakang. Otsu digunakan untuk menentukan ambang biner secara otomatis, Adaptive menghitung ambang secara lokal, dan Watershed memerlukan pra-pemrosesan morfologi seperti penghapusan area kecil dan transformasi jarak sebelum segmentasi.
# Otsu Thresholding
_, otsu = cv2.threshold(noisy_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Adaptive Thresholding
adaptive = cv2.adaptiveThreshold(
noisy_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2
)
# Watershed
ret, thresh = cv2.threshold(noisy_img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((3,3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
sure_bg = cv2.dilate(opening, kernel, iterations=3)
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
ret, markers = cv2.connectedComponents(sure_fg)
markers = markers + 1
markers[unknown == 255] = 0
img_color = cv2.cvtColor(noisy_img, cv2.COLOR_GRAY2BGR)
markers = cv2.watershed(img_color, markers)
result = img_color.copy()
result[markers == -1] = [255, 0, 0]
3. Visualisasi Hasil
plt.figure(figsize=(15,5))
plt.subplot(1,3,1)
plt.title("Otsu Thresholding")
plt.imshow(otsu, cmap='gray')
plt.axis('off')
plt.subplot(1,3,2)
plt.title("Adaptive Thresholding")
plt.imshow(adaptive, cmap='gray')
plt.axis('off')
plt.subplot(1,3,3)
plt.title("Watershed Result")
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.show()
Hasil dan Analisis

Otsu Thresholding
Kondisi: Hasil Otsu terlihat sebagai citra biner yang objek koinnya terpisah dari latar belakang, tetapi latar belakang hitam dipenuhi dengan bintik-bintik putih (salt noise) yang signifikan, terutama di bagian atas.
Mengapa Bisa Begitu:
Otsu Global: Otsu adalah metode global thresholding. Ia mencari satu nilai ambang batas optimal untuk memisahkan foreground (koin) dan background (latar).
Noise Tinggi: Jika citra asli memiliki noise berupa piksel-piksel cerah sporadis (salt noise) pada area gelap (latar belakang), piksel-piksel noise ini memiliki nilai intensitas yang tinggi.
Segmentasi Noise: Ketika Otsu menerapkan ambang batas, piksel-piksel noise yang cerah tersebut memiliki nilai di atas ambang batas, sehingga mereka ikut terklasifikasi sebagai foreground (putih), padahal seharusnya adalah background (hitam).
Adaptive Thresholding
Kondisi: Hasil Adaptive Thresholding menampilkan kontur koin dengan jelas, tetapi seluruh citra, termasuk latar belakang dan permukaan koin, dipenuhi tekstur noise halus (pola bintik-bintik hitam-putih).
Mengapa Bisa Begitu:
Adaptasi Lokal: Adaptive thresholding menerapkan nilai ambang batas yang berbeda untuk setiap area kecil (jendela) dalam citra, bukan satu nilai global. Ambang batas dihitung berdasarkan nilai intensitas piksel di sekitar piksel tersebut.
Sensitif terhadap Variasi Lokal: Metode ini sangat sensitif terhadap perubahan intensitas lokal. Karena citra masukan ber-noise tinggi, ada variasi intensitas yang ekstrem dan cepat antar piksel yang berdekatan.
Segmentasi Noise Sebagai Tekstur: Variasi intensitas yang disebabkan oleh noise (bintik-bintik acak) diinterpretasikan oleh algoritma adaptive thresholding sebagai "detail" atau "tekstur". Akibatnya, ia membagi-bagi area yang seharusnya seragam (seperti latar belakang) menjadi bintik-bintik putih-hitam, menciptakan pola noise yang intens pada hasil akhirnya.
Watershed Result
Kondisi: Hasil Watershed menunjukkan citra asli dengan batas-batas koin yang dilingkari (segmentasi), tetapi latar belakang citra yang tersegmentasi terlihat sangat bintik-bintik/kasar, dan garis batas segmentasi (lingkaran biru) terlihat tidak mulus atau terdistorsi di beberapa tempat.
Mengapa Bisa Begitu:
Ketergantungan pada Gradien/Jarak: Algoritma watershed biasanya beroperasi pada peta gradien atau peta jarak dari citra. Puncak-puncak (lokal maxima) dalam peta ini digunakan sebagai marker atau batas lembah yang akan diisi air (segmentasi).
Noise Menciptakan "Lembah" Palsu: Noise yang tinggi pada citra masukan secara efektif menciptakan banyak puncak dan lembah lokal palsu pada peta gradien/jarak.
Over-Segmentation: Setiap puncak atau lembah palsu ini dapat menyebabkan terjadinya segmentasi berlebih (over-segmentation), di mana satu objek (misalnya, koin) terbagi menjadi beberapa wilayah yang tersegmentasi, atau di mana piksel-piksel noise kecil di latar belakang diinterpretasikan sebagai objek terpisah.
Batas Tidak Mulus: Noise menyebabkan perhitungan gradien menjadi tidak stabil. Akibatnya, batas-batas yang dihasilkan oleh watershed (garis biru) tidak mengikuti kontur koin secara mulus, melainkan berfluktuasi karena dipengaruhi oleh variasi intensitas piksel noise di sekitarnya.
Solusi: Preprocessing sebelum Segmentasi
Penerapan pra-pemrosesan sangat membantu meningkatkan kualitas segmentasi. Salah satu cara yang efektif adalah menggunakan Gaussian Blur untuk menghaluskan citra dan meredam noise. Untuk kondisi noise yang lebih parah, kombinasi median filter dengan metode Watershed dapat memberikan hasil yang lebih optimal. Sebagai contoh, gussian blur diterapkan pada gambar yang telah diberi noise. Sehingga hasil keseluruhan kode menjadi seperti berikut:
from skimage import data, util
import cv2
import numpy as np
from matplotlib import pyplot as plt
# Ambil gambar coins dari skimage
img = data.coins()
# Tambahkan noise
noisy_img = util.random_noise(img, mode='s&p', amount=0.05)
noisy_img = (noisy_img * 255).astype(np.uint8)
plt.figure(figsize=(10,4))
plt.subplot(1,2,1)
plt.title("Original Image")
plt.imshow(img, cmap='gray')
plt.axis('off')
plt.subplot(1,2,2)
plt.title("Noisy Image (Salt & Pepper)")
plt.imshow(noisy_img, cmap='gray')
plt.axis('off')
plt.show()
noisy_img = cv2.GaussianBlur(noisy_img, (5,5), 0)
# --- Otsu Thresholding ---
_, otsu = cv2.threshold(noisy_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# --- Adaptive Thresholding ---
adaptive = cv2.adaptiveThreshold(
noisy_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2
)
# --- Watershed ---
ret, thresh = cv2.threshold(noisy_img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((3,3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
sure_bg = cv2.dilate(opening, kernel, iterations=3)
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
ret, markers = cv2.connectedComponents(sure_fg)
markers = markers + 1
markers[unknown == 255] = 0
img_color = cv2.cvtColor(noisy_img, cv2.COLOR_GRAY2BGR)
markers = cv2.watershed(img_color, markers)
result = img_color.copy()
result[markers == -1] = [255, 0, 0]
plt.figure(figsize=(15,5))
plt.subplot(1,3,1)
plt.title("Otsu Thresholding")
plt.imshow(otsu, cmap='gray')
plt.axis('off')
plt.subplot(1,3,2)
plt.title("Adaptive Thresholding")
plt.imshow(adaptive, cmap='gray')
plt.axis('off')
plt.subplot(1,3,3)
plt.title("Watershed Result")
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.show()
| Metode Segmentasi | Sebelum Smoothing (Noise Tinggi) | Setelah Smoothing (Noise Berkurang) |
|---|---|---|
| Otsu Thresholding |
|
|
| Adaptive Thresholding |
|
|
| Watershed Result |
|
|
Kesimpulan
Dampak dari proses smoothing ( Filter Gaussian) pada Gambar 2 dibandingkan Gambar 1 secara keseluruhan adalah peningkatan kualitas pre-processing yang menghasilkan hasil segmentasi yang lebih robust dan akurat.
Noise berkurang: Terutama terlihat jelas pada hasil Otsu Thresholding dan latar belakang Watershed Result.
Batas Segmentasi Lebih Baik: Garis batas koin pada Watershed Result (Gambar 2) lebih halus dan mendekati bentuk koin, menunjukkan keberhasilan smoothing dalam menghilangkan gangguan yang menyebabkan segmentasi yang tidak tepat.
Secara umum, dalam pemrosesan citra, pre-processing sangat penting, dan gambar ini merupakan demonstrasi yang baik tentang bagaimana langkah tersebut dapat meningkatkan kinerja teknik segmentasi seperti Otsu dan Watershed.

Posting Komentar