Files
UTS-Pengolahan-Citra-Digita…/Problem 2/soal2_penjelasan.md
T
MelvynFaith 003b2c544c 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.
2026-10-22 23:43:56 +07:00

216 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Soal 2 — Memecah Teks Menjadi Karakter Individual dengan `regionprops`
Program: `soal2.py` · Input: `Problem 2 Image.png` · Output: folder `karakter/` (18 file PNG)
Cara menjalankan: `python soal2.py` (library: `numpy`, `scikit-image`)
Referensi teori: Gonzalez & Woods, *Digital Image Processing*, edisi ke-4 (Pearson, 2018).
## 1. Tujuan
Citra input berisi tiga kata putih di atas latar hitam: **ZEUS** (horizontal), **TWINPEAK** (miring naik), dan **ACOSTA** (miring tajam). Program harus memisahkan setiap huruf dan menyimpannya sebagai gambar tersendiri. Huruf pada hasil harus tegak, yaitu kotak potongannya mengikuti kemiringan tulisan, lalu huruf diputar balik hingga lurus.
![Citra input](Problem%202%20Image.png)
## 2. Alur Program
1. Baca citra, ubah ke grayscale.
2. Segmentasi dengan threshold Otsu menjadi citra biner.
3. Buang noise kecil.
4. Labeling komponen terhubung: satu komponen = satu karakter.
5. `regionprops`: ambil properti setiap karakter.
6. Dilasi untuk mengelompokkan karakter menjadi kata.
7. Hitung sudut kemiringan setiap huruf dari lengkung yang melalui centroid huruf-huruf dalam katanya. Huruf satu goresan (I) memakai sumbu utamanya sendiri.
8. Putar setiap karakter sebesar sudutnya, potong ulang, simpan.
## 3. Penjelasan Setiap Langkah
### 3.1 Representasi citra dan konversi grayscale (Bab 2 dan Bab 7)
Citra digital adalah fungsi dua dimensi f(x, y) yang disimpan sebagai matriks piksel. File input berformat RGBA berukuran 762 × 860 × 4. Kanal alpha dibuang (`rgba2rgb`), lalu citra RGB diubah menjadi satu kanal intensitas (`rgb2gray`) dengan kombinasi linear:
```
Y = 0.2125 R + 0.7154 G + 0.0721 B
```
Hasilnya matriks bernilai [0, 1]. Tulisan bernilai mendekati 1 (putih), latar mendekati 0 (hitam).
### 3.2 Segmentasi dengan threshold Otsu
Thresholding mengubah citra grayscale menjadi citra biner:
```
g(x, y) = 1 jika f(x, y) > T
g(x, y) = 0 jika f(x, y) ≤ T
```
Nilai T dipilih otomatis dengan metode Otsu. Otsu mencoba setiap nilai k dan memilih k yang memaksimalkan varians antar-kelas:
```
σ²_B(k) = [m_G · P₁(k) − m(k)]² / [P₁(k) · (1 − P₁(k))]
```
dengan P₁(k) = proporsi piksel ≤ k, m(k) = rata-rata kumulatif intensitas sampai k, dan m_G = rata-rata intensitas global. Histogram citra ini bimodal (tulisan dan latar), jadi Otsu memisahkan keduanya dengan baik. Pada citra ini T = 0,342 (skala 0–1).
Catatan: metode Otsu dibahas di Bab 10 (Segmentasi), setelah materi UTS. Konsep dasarnya, yaitu fungsi thresholding sebagai transformasi intensitas, sudah dibahas di Bab 3.
### 3.3 Pembuangan noise
`remove_small_objects` menghapus komponen dengan luas ≤ 20 piksel. Komponen sekecil itu bukan huruf, melainkan noise sisa kompresi citra. Pada citra ini tidak ada komponen yang terbuang, tetapi langkah ini menjaga agar noise tidak tersimpan sebagai "karakter".
### 3.4 Labeling komponen terhubung (Bab 2 dan Bab 9)
**Ketetanggaan (Bab 2).** Piksel p di (x, y) memiliki:
- 4-tetangga N₄(p): (x±1, y) dan (x, y±1).
- 8-tetangga N₈(p): N₄(p) ditambah 4 tetangga diagonal.
Dua piksel foreground termasuk satu komponen jika ada jalur piksel foreground di antara keduanya. Program memakai **8-connectivity** (`connectivity=2`), sehingga goresan diagonal huruf seperti A, K, dan W tetap tersambung sebagai satu komponen.
**Ekstraksi komponen terhubung (Bab 9).** Secara morfologi, komponen yang memuat piksel awal X₀ diperoleh dengan iterasi:
```
X_k = (X_{k−1} ⊕ B) ∩ I, k = 1, 2, 3, ...
```
dengan I = citra biner dan B = elemen penstruktur 3 × 3 berisi 1 (untuk 8-connectivity). Iterasi berhenti saat X_k = X_{k−1}. `measure.label` menjalankan proses yang setara untuk setiap komponen dan memberi label 1, 2, 3, dan seterusnya. Hasilnya **18 label**, sesuai jumlah huruf: ZEUS (4) + TWINPEAK (8) + ACOSTA (6).
Pemisahan ini berhasil karena setiap huruf tidak bersentuhan dengan huruf lain. Huruf "I" juga tidak bermasalah karena kapital dan tidak memiliki titik.
### 3.5 Cara `regionprops` digunakan
`measure.regionprops(labels, intensity_image=gray)` menghasilkan satu objek per label. Properti yang dipakai program:
| Properti | Arti | Kegunaan di program |
|---|---|---|
| `coords` | Daftar koordinat (baris, kolom) piksel region | Mencari label kata dari region (langkah 3.6) |
| `centroid` | Titik pusat region: rata-rata koordinat piksel | Menghitung lengkung kata dan sudut setiap huruf (langkah 3.7) |
| `eccentricity` | Seberapa memanjang region: 0 = lingkaran, mendekati 1 = garis | Mengenali huruf satu goresan seperti I (langkah 3.7) |
| `orientation` | Sudut sumbu utama region terhadap sumbu vertikal | Sudut putar huruf satu goresan (langkah 3.7) |
| `image_intensity` | Potongan citra grayscale seukuran bounding box; piksel di luar region bernilai 0 | Gambar karakter yang diputar dan disimpan (langkah 3.8) |
| `area` | Jumlah piksel region | Informasi pada output |
`image_intensity` dipakai alih-alih memotong citra langsung. Pada huruf yang miring, bounding box satu huruf bisa memuat sebagian huruf tetangga. Dengan `image_intensity`, hanya piksel milik huruf itu sendiri yang ikut tersimpan.
Centroid dihitung dari momen orde nol dan orde satu region R:
```
area = M₀₀ = Σ 1
r̄ = M₁₀ / M₀₀ = (1/area) Σ r
c̄ = M₀₁ / M₀₀ = (1/area) Σ c
```
Catatan: deskriptor region seperti area, centroid, momen, dan komponen utama dibahas lebih lanjut di Bab 11. Program memakainya lewat `regionprops`, sesuai petunjuk soal.
### 3.6 Pengelompokan karakter menjadi kata dengan dilasi (Bab 9)
Huruf harus diputar sesuai kemiringan **katanya**, jadi program perlu tahu setiap huruf milik kata yang mana. Dilasi A oleh elemen penstruktur B didefinisikan:
```
A ⊕ B = { z | (B̂)_z ∩ A ≠ ∅ }
```
Dilasi menebalkan setiap huruf. Dengan B berupa disk radius r, dua huruf menyatu jika celah di antaranya kurang dari sekitar 2r. Hasil pengukuran jarak terdekat antar-piksel huruf pada citra ini:
- Celah antar-huruf dalam satu kata: paling besar **87 piksel** (pada ZEUS).
- Celah antar-kata: paling kecil **104 piksel** (antara E pada TWINPEAK dan A pada ACOSTA).
Radius r = 48 (menutup celah sekitar 96 piksel) berada di antara kedua nilai itu. Dilasi menyatukan huruf dalam satu kata tetapi tidak menyatukan kata yang berbeda. Labeling ulang pada citra hasil dilasi menghasilkan **3 label**, satu per kata. Label kata sebuah huruf dibaca dari citra label kata pada salah satu koordinat (`coords`) huruf tersebut.
### 3.7 Sudut kemiringan setiap huruf
Huruf-huruf dalam satu kata tersusun di sepanjang garis dasar (baseline). Baseline tidak selalu lurus. Pada TWINPEAK, kemiringan antar-centroid naik dari sekitar 2° (T–W) menjadi sekitar 27° (A–K), jadi baseline-nya melengkung. Satu sudut rata-rata per kata akan membuat huruf di ujung kata diputar terlalu jauh atau kurang jauh. Karena itu sudut dihitung **per huruf**, dari garis singgung lengkung baseline di posisi huruf tersebut.
**Langkah 1: arah umum kata (PCA).** Arah umum sebaran centroid dicari dengan analisis komponen utama:
1. Kurangi setiap centroid dengan rata-ratanya: **p**ᵢ − **p̄**.
2. Bentuk matriks kovarians C = (1/n) Σ (**p**ᵢ − **p̄**)(**p**ᵢ − **p̄**)ᵀ.
3. Eigenvektor C dengan eigenvalue terbesar = arah umum kata **u**. Eigenvektor kedua **v** tegak lurus terhadap **u**.
Program menghitungnya dengan SVD, yang memberi vektor yang sama. Arah **u** dipilih agar komponen kolomnya positif (teks dibaca dari kiri ke kanan).
**Langkah 2: lengkung baseline.** Setiap centroid diproyeksikan ke sumbu **u** dan **v**, lalu dicocokkan lengkung kuadratik dengan metode kuadrat terkecil:
```
v = a·u² + b·u + c
```
Kemiringan lengkung di posisi huruf ke-i adalah turunannya, dv/du = 2a·uᵢ + b. Arah garis singgung dalam koordinat citra:
```
(Δr, Δc) = u + (2a·uᵢ + b) · v
```
**Langkah 3: sudut.** Sudut terhadap sumbu horizontal:
```
θ = arctan2(−Δr, Δc)
```
Tanda minus diperlukan karena indeks baris citra bertambah ke bawah. Dengan begitu, θ positif berarti tulisan naik (berlawanan arah jarum jam). Untuk kata yang lurus seperti ZEUS, a ≈ 0 dan semua huruf mendapat sudut ≈ 0°.
**Pengecualian: huruf satu goresan.** Huruf I pada TWINPEAK di citra asli condong sekitar 10,7°. Nilai ini hampir sama dengan kemiringan italic font (sekitar 9,5°, diukur dari batang huruf E pada ZEUS). Artinya, I di citra asli praktis tidak diputar mengikuti lengkung, padahal lengkung memberi sudut 6,2°. Jika diputar 6,2°, I justru menjadi semakin condong (sekitar 17°).
Untuk huruf yang berupa satu goresan, arah huruf bisa dibaca langsung dari bentuknya. `regionprops` menghitung elips yang memiliki momen pusat orde dua sama dengan region:
```
μ_pq = Σ (r − r̄)^p (c − c̄)^q
```
Dari matriks kovarians [μ₂₀ μ₁₁; μ₁₁ μ₀₂] / M₀₀ diperoleh eigenvalue λ₁ ≥ λ₂. Panjang sumbu elips sebanding dengan √λ, sehingga:
- `eccentricity` = √(1 − λ₂/λ₁). Nilainya 0 untuk lingkaran dan mendekati 1 untuk garis.
- `orientation` = sudut eigenvektor λ₁ (sumbu utama) terhadap sumbu vertikal.
Eccentricity huruf I = 0,97, sedangkan huruf lain paling tinggi 0,88. Program memakai batas 0,95: huruf dengan eccentricity di atas batas itu diputar sebesar `orientation`-nya sendiri sehingga goresannya tepat vertikal. Huruf lain memakai sudut lengkung.
### 3.8 Rotasi dan pemotongan ulang (Bab 2)
Rotasi adalah transformasi geometri affine. Dalam koordinat homogen:
```
[x'] [cos θ −sin θ 0] [x]
[y'] = [sin θ cos θ 0] [y]
[1 ] [ 0 0 1] [1]
```
Setiap huruf diputar sebesar **−θ** (searah jarum jam sebesar θ) agar baseline-nya kembali horizontal. `transform.rotate` memakai *inverse mapping*: setiap piksel output (x', y') dipetakan balik ke posisi asal (x, y) dengan matriks invers. Posisi asal umumnya bukan bilangan bulat, sehingga nilainya dihitung dengan **interpolasi bilinear** dari 4 piksel terdekat:
```
v(x, y) = ax + by + cxy + d
```
Opsi `resize=True` memperbesar kanvas agar ujung huruf tidak terpotong saat diputar. Setelah rotasi, kotak dipotong ulang ke baris dan kolom yang masih memuat piksel huruf (intensitas > T Otsu). Hasilnya kotak rapat di sekitar huruf yang sudah tegak, lalu disimpan sebagai PNG 8-bit.
## 4. Hasil
Penamaan file mengikuti urutan label dari `regionprops`, yaitu urutan scan dari atas ke bawah. Karena itu urutan file tidak sama dengan urutan baca untuk TWINPEAK dan ACOSTA.
| File | Hasil | Huruf | Kata | Sudut | Sumber sudut |
|---|---|---|---|---|---|
| karakter_01.png | ![](karakter/karakter_01.png) | Z | ZEUS | −0,3° | lengkung kata |
| karakter_02.png | ![](karakter/karakter_02.png) | E | ZEUS | −0,1° | lengkung kata |
| karakter_03.png | ![](karakter/karakter_03.png) | U | ZEUS | 0,1° | lengkung kata |
| karakter_04.png | ![](karakter/karakter_04.png) | S | ZEUS | 0,3° | lengkung kata |
| karakter_05.png | ![](karakter/karakter_05.png) | K | TWINPEAK | 26,9° | lengkung kata |
| karakter_06.png | ![](karakter/karakter_06.png) | A | TWINPEAK | 22,9° | lengkung kata |
| karakter_07.png | ![](karakter/karakter_07.png) | E | TWINPEAK | 18,6° | lengkung kata |
| karakter_08.png | ![](karakter/karakter_08.png) | P | TWINPEAK | 14,4° | lengkung kata |
| karakter_09.png | ![](karakter/karakter_09.png) | N | TWINPEAK | 10,1° | lengkung kata |
| karakter_10.png | ![](karakter/karakter_10.png) | I | TWINPEAK | −10,7° | sumbu utama huruf |
| karakter_11.png | ![](karakter/karakter_11.png) | W | TWINPEAK | 2,1° | lengkung kata |
| karakter_12.png | ![](karakter/karakter_12.png) | T | TWINPEAK | −2,1° | lengkung kata |
| karakter_13.png | ![](karakter/karakter_13.png) | A | ACOSTA | 55,5° | lengkung kata |
| karakter_14.png | ![](karakter/karakter_14.png) | T | ACOSTA | 56,1° | lengkung kata |
| karakter_15.png | ![](karakter/karakter_15.png) | S | ACOSTA | 56,8° | lengkung kata |
| karakter_16.png | ![](karakter/karakter_16.png) | O | ACOSTA | 57,4° | lengkung kata |
| karakter_17.png | ![](karakter/karakter_17.png) | C | ACOSTA | 58,0° | lengkung kata |
| karakter_18.png | ![](karakter/karakter_18.png) | A | ACOSTA | 58,6° | lengkung kata |
## 5. Batasan
- **Font italic.** Setelah diluruskan, huruf masih tampak sedikit condong (sekitar 8–10°) karena fontnya italic. Ini bentuk huruf, bukan rotasi: ZEUS (sudut 0°) juga italic pada citra asli. Pengecualiannya huruf I: karena diluruskan dengan sumbu utamanya sendiri, I menjadi tepat vertikal.
- **Parameter disesuaikan dengan citra ini.** Radius dilasi 48 dan batas eccentricity 0,95 dipilih dari nilai yang diukur pada citra ini. Citra lain bisa membutuhkan nilai lain.
- **Kata minimal tiga huruf.** Lengkung kuadratik membutuhkan minimal tiga centroid.
- **Huruf tidak boleh bersentuhan.** Jika dua huruf bersentuhan, keduanya menjadi satu komponen dan tersimpan sebagai satu gambar.