Jawaban UTS Pengolahan Citra Digital Kelompok I

Soal 1: selisih Laplacian of Gaussian (sigma 0,1 dan 0,2).
Soal 2: memecah teks menjadi karakter individual dengan regionprops.
Soal 3: menghitung jumlah koin per ukuran dengan regionprops.
This commit is contained in:
MelvynFaith
2026-10-22 23:43:56 +07:00
commit 003b2c544c
39 changed files with 1191 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 KiB

+64
View File
@@ -0,0 +1,64 @@
import os
import numpy as np
from PIL import Image
from scipy.signal import convolve2d
# Semua file dibaca dan disimpan di folder yang sama dengan program ini,
# sehingga program bisa dijalankan di komputer mana pun.
FOLDER = os.path.dirname(os.path.abspath(__file__))
def kernel_log(sigma, ukuran=9):
"""Membuat kernel Laplacian of Gaussian (LoG) berukuran ukuran x ukuran."""
r = ukuran // 2
y, x = np.mgrid[-r:r + 1, -r:r + 1].astype(np.float64)
rr = x**2 + y**2
k = -(1.0 / (np.pi * sigma**4)) * (1 - rr / (2 * sigma**2)) * np.exp(-rr / (2 * sigma**2))
k -= k.mean() # jumlah elemen kernel dibuat 0
return k
def terapkan_log(img, sigma):
return convolve2d(img, kernel_log(sigma), mode="same", boundary="symm")
def normalisasi(a):
"""Skala hasil ke rentang 0-255 agar bisa disimpan sebagai citra."""
a = a - a.min()
if a.max() > 0:
a = a / a.max() * 255
return a.astype(np.uint8)
def simpan(arr, nama):
Image.fromarray(normalisasi(arr)).save(os.path.join(FOLDER, nama))
# a. Baca citra (rom.jpeg harus berada di folder yang sama dengan program ini)
nama_file = "rom.jpeg"
path_citra = os.path.join(FOLDER, nama_file)
if not os.path.exists(path_citra):
raise FileNotFoundError(f"{nama_file} tidak ditemukan. Taruh di folder: {FOLDER}")
img = np.array(Image.open(path_citra).convert("L"), dtype=np.float64)
# b. Filter LoG sigma = 0,1 -> im1
im1 = terapkan_log(img, 0.1)
simpan(im1, "im1.png")
# c. Filter LoG sigma = 0,2 -> im2
im2 = terapkan_log(img, 0.2)
simpan(im2, "im2.png")
# d. Selisih kedua citra -> citra hasil
hasil = im1 - im2
simpan(hasil, "hasil_selisih.png")
# Bukti bahwa im1, im2, dan hasil hampir identik setelah dinormalisasi
n1, n2, nh = normalisasi(im1), normalisasi(im2), normalisasi(hasil)
print("Korelasi im1 vs im2 :", np.corrcoef(n1.ravel(), n2.ravel())[0, 1])
print("Korelasi im1 vs hasil :", np.corrcoef(n1.ravel(), nh.ravel())[0, 1])
print("Selisih rata-rata im1 vs im2 (0-255):", np.abs(n1.astype(int) - n2.astype(int)).mean())
# Sebelum dinormalisasi, ketiga citra hanya berbeda skala
for nama, arr in (("im1", im1), ("im2", im2), ("hasil", hasil)):
print(f"Rentang nilai mentah {nama:<5}: {arr.min():.1f} s.d. {arr.max():.1f}")
print("Selesai. File tersimpan di:", FOLDER)
+190
View File
@@ -0,0 +1,190 @@
# Soal 1 — Selisih Laplacian of Gaussian (LoG)
Program: `soal1.py` · Input: `rom.jpeg` · Output: `im1.png`, `im2.png`, `hasil_selisih.png`
Cara menjalankan: `python soal1.py` (library: `numpy`, `pillow`, `scipy`)
Referensi teori: Gonzalez & Woods, *Digital Image Processing*, edisi ke-4 (Pearson, 2018).
## 1. Tujuan dan Asumsi
Soal meminta program yang menjalankan algoritma berikut:
1. Baca citra.
2. Terapkan filter LoG dengan simpangan baku σ = 0,1, simpan sebagai **im1**.
3. Terapkan filter LoG dengan σ = 0,2, simpan sebagai **im2**.
4. Hitung selisih kedua citra, simpan sebagai **citra hasil**.
Kelompok memakai nilai σ persis seperti tertulis di soal (0,1 dan 0,2 piksel). Seperti dijelaskan di bagian 4, kedua nilai ini jauh lebih kecil dari jarak antar-piksel, sehingga kernel LoG tidak terbentuk utuh dan ketiga citra output menjadi hampir identik. Bagian 4 menganalisis hal ini secara matematis dan membuktikannya dengan angka hasil program.
## 2. Alur Program
| Langkah soal | Kode di `soal1.py` |
|---|---|
| a. Baca citra | `Image.open(...).convert("L")`: citra dibaca lalu diubah ke grayscale bertipe `float64` |
| b. LoG σ = 0,1 → im1 | `im1 = terapkan_log(img, 0.1)`, disimpan sebagai `im1.png` |
| c. LoG σ = 0,2 → im2 | `im2 = terapkan_log(img, 0.2)`, disimpan sebagai `im2.png` |
| d. Selisih → hasil | `hasil = im1 - im2`, disimpan sebagai `hasil_selisih.png` |
Fungsi pendukung:
- `kernel_log(sigma, ukuran=9)`: membuat kernel LoG 9 × 9, lalu membuat jumlah elemennya nol.
- `terapkan_log(img, sigma)`: mengonvolusikan citra dengan kernel LoG.
- `normalisasi(a)`: menskalakan nilai ke 0–255 agar bisa disimpan sebagai citra 8-bit.
Selisih dihitung dari nilai **mentah** im1 dan im2, sebelum normalisasi. Jika dihitung dari citra yang sudah dinormalisasi, informasi skala dan tanda hilang dan selisihnya tidak lagi bermakna.
## 3. Dasar Teori
### 3.1 Laplacian (Bab 3)
Laplacian adalah operator turunan kedua yang isotropik:
```
∇²f = ∂²f/∂x² + ∂²f/∂y²
```
Laplacian bernilai nol di daerah intensitas konstan dan memberi respons kuat di tepi dan detail halus. Kelemahannya, turunan kedua sangat peka terhadap noise.
### 3.2 Laplacian of Gaussian
Untuk mengurangi kepekaan terhadap noise, citra dihaluskan dulu dengan Gaussian, lalu diberi Laplacian. Karena konvolusi dan turunan sama-sama operasi linear:
```
∇²[G(x, y) ★ f(x, y)] = [∇²G(x, y)] ★ f(x, y)
```
Jadi cukup satu kernel, yaitu LoG = ∇²G. Kernel yang dipakai program:
```
LoG(x, y) = −(1 / πσ⁴) · [1 − (x² + y²) / 2σ²] · e^(−(x² + y²) / 2σ²)
```
Bentuk ini sama dengan bentuk ∇²G di buku, [(x² + y² − 2σ²) / σ⁴] · e^(−(x² + y²) / 2σ²), dikalikan konstanta normalisasi Gaussian 1/(2πσ²). Nilai σ menentukan skala: σ besar menghaluskan lebih kuat sehingga hanya detail besar yang terdeteksi.
Kernel LoG yang ideal berjumlah nol, sehingga respons di daerah konstan tepat nol. Kernel hasil sampling pada grid terbatas umumnya tidak tepat berjumlah nol, jadi program mengurangkan rata-rata kernel dari setiap elemen (`k -= k.mean()`).
Catatan: LoG sebagai detektor tepi (metode Marr-Hildreth) dibahas di Bab 10. Komponennya, yaitu Laplacian dan penghalusan Gaussian, sudah dibahas di Bab 3.
### 3.3 Konvolusi spasial (Bab 3)
```
g(x, y) = Σₛ Σₜ w(s, t) · f(x − s, y − t)
```
`convolve2d(..., mode="same", boundary="symm")` menghasilkan citra berukuran sama dengan input. Di tepi citra dipakai padding cermin, yaitu piksel tepi dicerminkan ke luar. Kernel LoG simetris, jadi konvolusi dan korelasi memberi hasil yang sama.
### 3.4 Penskalaan intensitas (Bab 2)
Output LoG berisi nilai negatif dan positif dengan rentang besar, jadi perlu diskalakan sebelum disimpan sebagai citra 8-bit:
```
f_m = f − min(f)
f_s = 255 · f_m / max(f_m)
```
Fungsi `normalisasi` menjalankan persis rumus ini.
## 4. Analisis: Kernel LoG dengan σ = 0,1 dan σ = 0,2
### 4.1 Kernel hanya bernilai di piksel tengah
Jarak antar-piksel adalah 1. Pada tetangga terdekat (r = 1), faktor Gaussian bernilai:
| σ | e^(−1/2σ²) di r = 1 | Nilai di pusat sebelum dikurangi rata-rata, −1/(πσ⁴) |
|---|---|---|
| 0,1 | 1,9 × 10⁻²² | −3183,10 |
| 0,2 | 3,7 × 10⁻⁶ | −198,94 |
Seluruh bobot Gaussian berada di piksel tengah. Kernel sebelum dikurangi rata-rata praktis berupa impuls: K ≈ c_σ · δ, dengan c_σ = −1/(πσ⁴).
### 4.2 Bentuk kernel ditentukan oleh langkah "jumlah = 0"
Setelah `k -= k.mean()`, setiap elemen dikurangi c_σ/81. Isi kernel 9 × 9 menjadi:
| σ | Pusat | Tetangga (r = 1) | Diagonal (r = √2) | Pojok |
|---|---|---|---|---|
| 0,1 | −3143,80 | 39,30 | 39,30 | 39,30 |
| 0,2 | −196,49 | 2,46 | 2,46 | 2,46 |
Kedua kernel hanyalah kelipatan dari matriks yang sama:
```
K_σ ≈ c_σ · (δ − J/81)
```
dengan δ = impuls di pusat dan J = matriks 9 × 9 berisi 1. Konvolusi dengan J/81 adalah filter rata-rata 9 × 9, sehingga:
```
im_σ ≈ c_σ · (f − f̄₉ₓ₉)
```
f − f̄ adalah *unsharp mask* (Bab 3): citra dikurangi versi kaburnya, yang menonjolkan detail lokal. Jadi im1 dan im2 sama-sama berupa unsharp mask 9 × 9 dengan skala berbeda, bukan LoG yang sebenarnya. Korelasi nilai mentah dengan (f − f̄₉ₓ₉) pada `rom.jpeg` membuktikannya:
| Citra | Korelasi dengan (f − f̄₉ₓ₉) |
|---|---|
| im1 | −1,0000000000 |
| im2 | −0,9999999986 |
| hasil | −0,9999999999 |
Tanda negatif berasal dari c_σ yang negatif.
### 4.3 Akibatnya pada selisih
Karena im_σ sebanding dengan 1/σ⁴:
```
im1 / im2 = (σ₂/σ₁)⁴ = (0,2/0,1)⁴ = 16
hasil = im1 − im2 = [1 − (σ₁/σ₂)⁴] · im1 = 0,9375 · im1
```
Hasil program sesuai dengan perhitungan ini. Median rasio im1/im2 = 16,002, dan median rasio hasil/im1 = 0,9375. Rentang nilai mentahnya:
| Citra | Minimum | Maksimum |
|---|---|---|
| im1 | −589.187,7 | 513.736,4 |
| im2 | −36.820,3 | 32.106,2 |
| hasil | −552.367,3 | 481.630,2 |
Normalisasi min-max menghapus faktor skala, sehingga ketiga citra yang disimpan praktis identik:
| Perbandingan (setelah normalisasi 0–255) | Korelasi | Piksel berbeda | Beda maksimum |
|---|---|---|---|
| im1 vs im2 | 0,9999973 | 2886 dari 1.440.000 | 1 tingkat abu-abu |
| im1 vs hasil | 0,99999999 | 16 dari 1.440.000 | 1 tingkat abu-abu |
Perbedaan kecil antara im1 dan im2 berasal dari sisa nilai Gaussian di r = 1 pada σ = 0,2 (sekitar 4 × 10⁻⁶) dan dari pembulatan ke 8-bit.
### 4.4 Ukuran kernel
Gonzalez & Woods menyarankan ukuran kernel LoG berupa bilangan ganjil terkecil yang ≥ 6σ. Untuk σ = 0,1 dan 0,2, aturan itu memberi kernel 1 × 1. Kernel 1 × 1 setelah dikurangi rata-ratanya bernilai 0, sehingga outputnya citra hitam seluruhnya. Karena itu program memakai ukuran tetap 9 × 9. Pada σ sekecil ini, ukuran kernel inilah yang menentukan bentuk hasil: hasil = unsharp mask dengan filter rata-rata seukuran kernel.
## 5. Hasil
Output program:
```
Korelasi im1 vs im2 : 0.9999973316611581
Korelasi im1 vs hasil : 0.9999999851773528
Selisih rata-rata im1 vs im2 (0-255): 0.0020041666666666667
Rentang nilai mentah im1 : -589187.7 s.d. 513736.4
Rentang nilai mentah im2 : -36820.3 s.d. 32106.2
Rentang nilai mentah hasil: -552367.3 s.d. 481630.2
```
| Citra input (`rom.jpeg`) | im1 (σ = 0,1) |
|---|---|
| ![rom](rom.jpeg) | ![im1](im1.png) |
| im2 (σ = 0,2) | Citra hasil (im1 − im2) |
|---|---|
| ![im2](im2.png) | ![hasil](hasil_selisih.png) |
Ketiga output berwarna abu-abu rata dengan tepi dan detail yang menonjol, ciri khas unsharp mask setelah normalisasi. Daerah halus seperti langit bernilai sekitar abu-abu tengah, karena f − f̄ ≈ 0 di daerah tersebut.
## 6. Kesimpulan
- Program menjalankan langkah a–d sesuai soal dengan rumus LoG yang benar.
- Dengan σ = 0,1 dan 0,2 piksel, Gaussian jauh lebih sempit dari satu piksel. Kernel LoG yang disampling tidak lagi berbentuk LoG, melainkan unsharp mask 9 × 9 yang dikalikan −1/(πσ⁴).
- im1, im2, dan citra hasil hanya berbeda faktor skala (16 : 1 : 15), sehingga setelah dinormalisasi ketiganya praktis identik.
- Agar selisih LoG menunjukkan perbedaan antar-skala, σ perlu jauh lebih besar dari 1 piksel, misalnya σ = 1 dan σ = 2 dengan ukuran kernel ≥ 6σ.
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB