Praktikum Pengolahan Citra Digital: Analisis & Klasifikasi Objek
Library yang Dibutuhkan
Sebelum menjalankan skrip di atas, pastikan modul/library OpenCV dan Scikit-Image sudah terinstall:
pip install opencv-python numpy matplotlib scikit-image
Penjelasan Kode Menurut Abstraksi:
-
Low-Level Processing (Input: Gambar -> Output: Gambar)
-
cv2.GaussianBlur: Mengeliminasi derau (noise) frekuensi tinggi. -
cv2.equalizeHist: Meratakan distribusi tingkat keabuan untuk mempertajam kontras.
-
-
Mid-Level Processing (Input: Gambar -> Output: Fitur/Atribut)
-
cv2.threshold&cv2.findContours: Memisahkan objek dari background dan melacak batas area (segmentasi). -
cv2.contourArea,cv2.arcLength,graycoprops: Ekstraksi fitur geometri (luas, keliling, circularity) dan tekstur (GLCM Contrast & Homogeneity).
-
-
High-Level Processing (Input: Fitur -> Output: Keputusan/Pengenalan)
-
Logika kondisional (
if circularity > 0.8) memberikan interpretasi semantis untuk mengenali objek sebagai Persegi atau Lingkaran.
-
import cv2
import numpy as np
import matplotlib.pyplot as plt
from skimage.feature import graycomatrix, graycoprops
# ==============================================================================
# 0. PREPARATION: Synthetic Image Generation & Noise Ingestion
# ==============================================================================
# [ANALISIS DATA 1]: Pembuatan Matriks Citra Sintetik
# PERTANYAAN 1.1: Mengapa nilai piksel awal diisi dengan angka 30 dan tipe data uint8?
# PERTANYAAN 1.2: Apa yang terjadi jika matriks citra diisi dengan tipe int32 atau float64?
img_size = (300, 300)
image = np.zeros(img_size, dtype=np.uint8) + 30
# Deklarasi Objek Geometry
cv2.rectangle(image, (40, 40), (140, 140), 200, -1) # Objek A: Persegi
cv2.circle(image, (220, 200), 45, 180, -1) # Objek B: Lingkaran
# [EVALUASI SIMULASI]: Pengaruh Gaussian Noise
# TUGAS: Jika nilai deviasi standar noise (sekarang 15) dinaikkan menjadi 50,
# analisis dampaknya terhadap keberhasilan deteksi bentuk pada tahap segmentasi!
np.random.seed(42)
noise = np.random.normal(0, 15, img_size).astype(np.int16)
noisy_image = np.clip(image.astype(np.int16) + noise, 0, 255).astype(np.uint8)
# ==============================================================================
# 1. LOW-LEVEL PROCESSING: Enhancements & Noise Mitigation
# ==============================================================================
# [ANALISIS ALGORITMA 1]: Reduksi Noise
# PERTANYAAN: Mengapa kita menggunakan Gaussian Filter kernel (5,5) dan bukan Median Filter?
# Tuliskan perbedaan mendasar dampak kedua filter ini terhadap tepi (edge) objek!
filtered_image = cv2.GaussianBlur(noisy_image, (5, 5), 0)
# [ANALISIS ALGORITMA 2]: Histogram Equalization
# JELASKAN: Apa fungsi equalization di sini terhadap distribusi tingkat keabuan (grayscale),
# dan mengapa langkah ini mempermudah proses Otsu Thresholding selanjutnya?
equalized_image = cv2.equalizeHist(filtered_image)
# ==============================================================================
# 2. MID-LEVEL PROCESSING: Binarization & Contour Detection
# ==============================================================================
# [EKSPERIMEN LOGIKA]: Otsu Automatic Thresholding
# TUGAS: Catat nilai threshold otomatis yang dihasilkan oleh algoritma Otsu ini!
# Mengapa thresholding manual sering gagal jika diterapkan pada citra bernoise?
_, binary_thresh = cv2.threshold(equalized_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Extraction Boundary Kontur
contours, _ = cv2.findContours(binary_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# ==============================================================================
# 3. HIGH-LEVEL PROCESSING: Feature Extraction & Classification
# ==============================================================================
output_image = cv2.cvtColor(equalized_image, cv2.COLOR_GRAY2BGR)
print("=== HASIL EKSTRAKSI FITUR & KLASIFIKASI OBJEK ===")
for i, cnt in enumerate(contours):
area = cv2.contourArea(cnt)
perimeter = cv2.arcLength(cnt, True)
# Filter noise kontur palsu
if area < 500 or perimeter == 0:
continue
# [MATEMATIKA FITUR]: Metric Circularity (Form Factor)
# PERTANYAAN MATEMATIS: Secara teori, berapa nilai circularity ideal untuk lingkaran sempurna?
# Mengapa nilainya bisa berada di bawah angka 1.0 pada citra digital ini?
circularity = (4 * np.pi * area) / (perimeter ** 2)
# [EKSTRAKSI FITUR TEKSTUR]: GLCM Matrix
# JELASKAN: Apa arti dari nilai 'contrast' dan 'homogeneity' yang dihasilkan dari GLCM?
x, y, w, h = cv2.boundingRect(cnt)
roi = equalized_image[y:y+h, x:x+w]
glcm = graycomatrix(roi, distances=[1], angles=[0], levels=256, symmetric=True, normed=True)
contrast = graycoprops(glcm, 'contrast')[0, 0]
homogeneity = graycoprops(glcm, 'homogeneity')[0, 0]
# [LOGIKA KEPUTUSAN]: Rule-Based Classification
# PERTANYAAN: Mengapa angka boundary threshold circularity diset pada 0.8?
# Apa akibatnya jika threshold ini diturunkan menjadi 0.5?
if circularity > 0.8:
label = "Lingkaran"
color = (0, 255, 0) # BGR: Hijau
else:
label = "Persegi"
color = (255, 0, 0) # BGR: Biru
# Menghitung Momen Citra untuk Titik Tengah Label
M = cv2.moments(cnt)
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
cv2.drawContours(output_image, [cnt], -1, color, 2)
cv2.putText(output_image, label, (cx - 35, cy), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
# Output Konsol Praktikum
print(f"\n[Objek #{i+1}: {label}]")
print(f" - Luas (Area) : {area} px")
print(f" - Keliling : {perimeter:.2f} px")
print(f" - Kebulatan : {circularity:.4f}")
print(f" - Tekstur Contrast : {contrast:.4f}")
print(f" - Tekstur Homogeneity : {homogeneity:.4f}")
# ==============================================================================
# 4. VISUALISASI PROSES (Pipelining)
# ==============================================================================
# TODO (TUGAS MAHASISWA):
# Buatlah plot subplot 2x3 menggunakan Matplotlib untuk menampilkan ke-5 tahapan citra
# di atas beserta subplot ke-6 yang menampilkan histogram dari equalized_image!
# Tuliskan kode lengkap plot Anda di bawah ini:
# [LENGKAPKAN KODE PLOT MATPLOTLIB DI SINI]