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.
216 lines
13 KiB
Markdown
216 lines
13 KiB
Markdown
# 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.
|
||
|
||

|
||
|
||
## 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 |  | Z | ZEUS | −0,3° | lengkung kata |
|
||
| karakter_02.png |  | E | ZEUS | −0,1° | lengkung kata |
|
||
| karakter_03.png |  | U | ZEUS | 0,1° | lengkung kata |
|
||
| karakter_04.png |  | S | ZEUS | 0,3° | lengkung kata |
|
||
| karakter_05.png |  | K | TWINPEAK | 26,9° | lengkung kata |
|
||
| karakter_06.png |  | A | TWINPEAK | 22,9° | lengkung kata |
|
||
| karakter_07.png |  | E | TWINPEAK | 18,6° | lengkung kata |
|
||
| karakter_08.png |  | P | TWINPEAK | 14,4° | lengkung kata |
|
||
| karakter_09.png |  | N | TWINPEAK | 10,1° | lengkung kata |
|
||
| karakter_10.png |  | I | TWINPEAK | −10,7° | sumbu utama huruf |
|
||
| karakter_11.png |  | W | TWINPEAK | 2,1° | lengkung kata |
|
||
| karakter_12.png |  | T | TWINPEAK | −2,1° | lengkung kata |
|
||
| karakter_13.png |  | A | ACOSTA | 55,5° | lengkung kata |
|
||
| karakter_14.png |  | T | ACOSTA | 56,1° | lengkung kata |
|
||
| karakter_15.png |  | S | ACOSTA | 56,8° | lengkung kata |
|
||
| karakter_16.png |  | O | ACOSTA | 57,4° | lengkung kata |
|
||
| karakter_17.png |  | C | ACOSTA | 58,0° | lengkung kata |
|
||
| 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.
|