Algoritma FCM (Fuzzy C-Means) Clustering


Algoritma FCM (Fuzzy C-Means) Clustering adalah salah satu algoritma yang digunakan dalam pengolahan citra. Contoh yang dibahas kali ini adalah mengenai pemotongan gambar sesuai dengan kelompok warnanya.
Algoritma ini merupakan penggabungan dari Algoritma Fuzzy Logic dan Algoritma K-Means Clustering yang sudah pernah dibahas sebelumnya. K-Means Clustering adalah salah satu algoritma klasifikasi data yang cukup banyak dipakai untuk memecahkan masalah. Hanya saja metode tersebut tidak memiliki nilai pengembalian berupa sebuah nilai pembanding untuk masing-masing cluster, sehingga digunakan algoritma Fuzzy untuk menghitung skor dari sebuah data. Dalam kasus ini Fuzzy juga digunakan untuk membatasi nilai sebuah titik warna pada masing-masing cluster agar selalu memiliki nilai total satu. Masing-masing cluster memiliki warna perwakilan yang diambil dari nilai centroid, dan semua titik yang masuk dalam sebuah cluster akan berubah warna menjadi warna centroid pada cluster tersebut.



Sebelum masuk kedalam langkah-langkah pembahasan algoritma, ada beberapa konstanta atau parameter yang harus diketahui, yaitu:
* Tentukan Jumlah Cluster
Jumlah Cluster adalah jumlah dari pengelompokan data yang ingin dilakukan
Jumlah Cluster nilainya harus diantara 2 dan jumlah data
Nilai jumlah cluster dapat diset melalui input jumlah cluster pada layar

Dim jumlahCluster As Integer = CInt(numJumlahCluster.Value)

* Tentukan Jumlah maksimal perulangan / iterasi
Nilai jumlah maksimal iterasi dapat diset melalui input maksimal iterasi pada layar

Dim maksIterasi As Integer = CInt(numMaksIterasi.Value)

* Tentukan batas minimal selisih perhitungan dalam setiap iterasi
Nilai batas minimal iterasi dapat diset melalui input batas minimal selisih pada layar

Dim batasMinimalSelisihPerhitungan As Double = CDbl(numBatasMinimalSelisih.Value)

* Tentukan faktor fuzzy
Faktor fuzzy harus bernilai diatas 1
Diasumsikan dalam kasus ini, faktor fuzzy bernilai 2

Const faktorFuzzy As Single = 2


Langkah-langkah penggunaan algoritma ini adalah

1. Masukkan data titik, yaitu masing-masing warna dalam setiap pixel gambar beserta posisinya

Dim points As New List(Of ClusterPoint)()
For i As Integer = 0 To gmbContoh.Width - 1
	For j As Integer = 0 To gmbContoh.Height - 1
		Dim warna As Color = gmbContoh.GetPixel(i, j)
		points.Add(New ClusterPoint(i, j, warna))
	Next
Next

* Agar dapat menjalankan skrip diatas, maka diperlukan sebuah Class ClusterPoint untuk menampung data posisi titik, warna pixel dan indeks cluster dimana titik tersebut berada. Deklarasi Class ClusterPoint adalah sebagai berikut:

Public Class ClusterPoint
    Private m_X As Double                       'posisi X sebuah titik
    Private m_Y As Double                       'posisi Y sebuah titik
    Private m_warnaPixel As Color               'warna perubahan sebuah pixel setelah masuk ke dalam cluster
    Private m_warnaOriginalPixel As Color       'warna asli sebuah pixel sebelum masuk ke dalam cluster
    Private m_indeksCluster As Double           'indeks cluster dimana titik ini berada

    Public Property X() As Double
        Get
            Return m_X
        End Get
        Set(value As Double)
            m_X = value
        End Set
    End Property

    Public Property Y() As Double
        Get
            Return m_Y
        End Get
        Set(value As Double)
            m_Y = value
        End Set
    End Property

    Public Property warnaPixel() As Color
        Get
            Return m_warnaPixel
        End Get
        Set(value As Color)
            m_warnaPixel = value
        End Set
    End Property

    Public Property warnaOriginalPixel() As Color
        Get
            Return m_warnaOriginalPixel
        End Get
        Set(value As Color)
            m_warnaOriginalPixel = value
        End Set
    End Property

    Public Property indeksCluster() As Double
        Get
            Return m_indeksCluster
        End Get
        Set(value As Double)
            m_indeksCluster = value
        End Set
    End Property

    Public Sub New(x As Double, y As Double, col As Color)
        Me.X = x
        Me.Y = y
        Me.warnaPixel = col
        Me.warnaOriginalPixel = col
        Me.indeksCluster = -1
    End Sub
End Class

2. Tentukan titik acak sebanyak jumlah cluster untuk dimasukkan ke dalam masing-masing cluster

Dim centroids As New List(Of ClusterCentroid)()
For i As Integer = 0 To jumlahCluster - 1
	Dim posisiXAcak As Integer = random.Next(gmbContoh.Width)
	Dim posisiYAcak As Integer = random.Next(gmbContoh.Height)
	Dim warna As Color = gmb.GetPixel(posisiXAcak, posisiYAcak)
	centroids.Add(New ClusterCentroid(posisiXAcak, posisiYAcak, warna))
Next

* Agar dapat menjalankan skrip diatas, maka diperlukan sebuah Class ClusterCentroid untuk menampung data posisi titik, jumlah masing-masing komponen warna, jumlah pixel dan warna pixel. Deklarasi Class ClusterCentroid adalah sebagai berikut:

Public Class ClusterCentroid
    Private m_X As Double                       'posisi X sebuah centroid
    Private m_Y As Double                       'posisi Y sebuah centroid
    Private m_jumlahKomponenMerah As Double     'Jumlah dari nilai komponen merah pada semua titik pada cluster, digunakan untuk menghitung rata-rata
    Private m_jumlahKomponenHijau As Double     'Jumlah dari nilai komponen hijau pada semua titik pada cluster, digunakan untuk menghitung rata-rata
    Private m_jumlahKomponenBiru As Double      'Jumlah dari nilai komponen biru  pada semua titik pada cluster, digunakan untuk menghitung rata-rata
    Private m_jumlahPixelPerCluster As Double   'Jumlah pixel dalam cluster, digunakan untuk menghitung rata-rata
    Private m_jumlahPixel As Double             'Jumlah pixel pada semua cluster
    Private m_warnaPixel As Color               'warna perubahan sebuah pixel setelah masuk ke dalam cluster
    Private m_warnaOriginalPixel As Color       'warna asli sebuah pixel sebelum masuk ke dalam cluster

    Public Property X() As Double
        Get
            Return m_X
        End Get
        Set(value As Double)
            m_X = value
        End Set
    End Property

    Public Property Y() As Double
        Get
            Return m_Y
        End Get
        Set(value As Double)
            m_Y = value
        End Set
    End Property

    Public Property jumlahKomponenMerah() As Double
        Get
            Return m_jumlahKomponenMerah
        End Get
        Set(value As Double)
            m_jumlahKomponenMerah = value
        End Set
    End Property

    Public Property jumlahKomponenHijau() As Double
        Get
            Return m_jumlahKomponenHijau
        End Get
        Set(value As Double)
            m_jumlahKomponenHijau = value
        End Set
    End Property

    Public Property jumlahKomponenBiru() As Double
        Get
            Return m_jumlahKomponenBiru
        End Get
        Set(value As Double)
            m_jumlahKomponenBiru = value
        End Set
    End Property

    Public Property jumlahPixelPerCluster() As Double
        Get
            Return m_jumlahPixelPerCluster
        End Get
        Set(value As Double)
            m_jumlahPixelPerCluster = value
        End Set
    End Property

    Public Property jumlahPixel() As Double
        Get
            Return m_jumlahPixel
        End Get
        Set(value As Double)
            m_jumlahPixel = value
        End Set
    End Property

    Public Property warnaPixel() As Color
        Get
            Return m_warnaPixel
        End Get
        Set(value As Color)
            m_warnaPixel = value
        End Set
    End Property

    Public Property warnaOriginalPixel() As Color
        Get
            Return m_warnaOriginalPixel
        End Get
        Set(value As Color)
            m_warnaOriginalPixel = value
        End Set
    End Property

    Public Sub New(x As Double, y As Double, col As Color)
        Me.X = x
        Me.Y = y
        Me.jumlahKomponenMerah = 0
        Me.jumlahKomponenHijau = 0
        Me.jumlahKomponenBiru = 0
        Me.jumlahPixelPerCluster = 0
        Me.jumlahPixel = 0
        Me.warnaPixel = col
        Me.warnaOriginalPixel = col
    End Sub
End Class

3. Lakukan perhitungan sebanyak jumlah iterasi (poin 3a – 3i)

Dim iterasi As Integer = 0
Do While iterasi < maksIterasi
. . .

3a. Hitung nilai fungsi pada gambar awal
Penjelasan lebih detail tentang fungsi ini dapat dilihat pada penjelasan skrip dibawah ini

fcm.nilaiFungsi = fcm.hitungNilaiFungsi()

* Gunakan fungsi ini untuk menghitung nilai fungsi dari sebuah gambar
Nilai masing-masing titik pada semua cluster dihitung dengan rumus
Jk = nilai jarak dipangkatkan faktor fuzzy * kuadrat dari (nilai jarak titik tersebut pada masing-masing cluster)
Nilai fungsi sebuah gambar adalah jumlah dari semua nilai Jk yang sudah dihitung sebelumnya

Public Function hitungNilaiFungsi() As Double
	Dim Jk As Double = 0.0

	For i As Integer = 0 To Me.Points.Count - 1
		For j As Integer = 0 To Me.Clusters.Count - 1
			Jk += Math.Pow(U(i, j), Me.faktorFuzzy) * Math.Pow(Me.HitungJarak(Points(i), Clusters(j)), 2)
		Next
	Next
	Return Jk
End Function

* Gunakan fungsi ini untuk menghitung jarak dari data dan centroid
metode yang digunakan adalah jarak Euclidean, dengan rumus akar dari (jumlah dari (kuadrat dari (data - centroid)))
Karena terdapat 3 komponen warna pada setiap pixel, maka masing-masing komponen warna akan dihitung selisihnya

Private Function HitungJarak(p As ClusterPoint, c As ClusterCentroid) As Double
	Return Math.Sqrt(Math.Pow(CInt(p.warnaPixel.R) - CInt(c.warnaPixel.R), 2.0) + Math.Pow(CInt(p.warnaPixel.G) - CInt(c.warnaPixel.G), 2.0) + Math.Pow(CInt(p.warnaPixel.B) - CInt(c.warnaPixel.B), 2.0))
End Function

3b. Lakukan proses perhitungan centroid baru untuk masing-masing cluster
Penjelasan lebih detail tentang fungsi ini dapat dilihat pada penjelasan skrip dibawah ini (poin 3b1 - 3b2)

fcm.UpdateCentroids()

Memasuki perhitungan pada fungsi UpdateCentroids

3b1. Lakukan perhitungan pada masing-masing titik pada masing-masing cluster (poin 3b1a - 3b1d)

For j As Integer = 0 To Me.Clusters.Count - 1
	Dim c As ClusterCentroid = Me.Clusters(j)

	Dim nilaiFuzzyJarak As Double = 0.0
	For i As Integer = 0 To Me.Points.Count - 1
		Dim p As ClusterPoint = Me.Points(i)

. . .

3b1a. Hitung nilai fuzzy masing-masing jarak dengan rumus = nilai jarak dipangkatkan faktor fuzzy

nilaiFuzzyJarak = Math.Pow(U(i, j), Me.faktorFuzzy)

3b1b. Jumlahkan masing-masing komponen warna pada masing-masing cluster
Kemudian jumlahkan semua nilai fuzzy pada masing-masing jarak diatas

c.jumlahKomponenMerah += nilaiFuzzyJarak * p.warnaPixel.R
c.jumlahKomponenHijau += nilaiFuzzyJarak * p.warnaPixel.G
c.jumlahKomponenBiru += nilaiFuzzyJarak * p.warnaPixel.B
c.jumlahPixel += nilaiFuzzyJarak

3b1c. Catat jumlah titik pada masing-masing cluster

If U(i, j) = p.indeksCluster Then
	c.jumlahPixelPerCluster += 1
End If

3b1d. Hitung warna pixel centroid yang baru

c.warnaPixel = Color.FromArgb(CByte(c.jumlahKomponenMerah / c.jumlahPixel), CByte(c.jumlahKomponenHijau / c.jumlahPixel), CByte(c.jumlahKomponenBiru / c.jumlahPixel))

3b2. Lakukan proses pengubahan gambar sesuai warna centroid pada masing-masing cluster
Semua titik yang masuk kedalam sebuah centroid, maka warna titik tersebut akan berubah menjadi warna centroid untuk titik tersebut

Dim tmp As New Bitmap(lebarGambar, panjangGambar, PixelFormat.Format32bppRgb)

For j As Integer = 0 To Me.Points.Count - 1
	For i As Integer = 0 To Me.Clusters.Count - 1
		Dim p As ClusterPoint = Me.Points(j)

		If U(j, i) = p.indeksCluster Then
			tmp.SetPixel(CInt(p.X), CInt(p.Y), Me.Clusters(i).warnaPixel)
		End If
	Next
Next

gambarHasilPerhitungan = tmp

3c. Lakukan proses pengelompokan masing-masing titik pada cluster yang baru
Penjelasan lebih detail tentang fungsi ini dapat dilihat pada penjelasan skrip dibawah ini (poin 3c1 - 3c2)

fcm.Cluster()

Memasuki perhitungan pada fungsi Cluster

3c1. Lakukan perhitungan pada semua cluster dan semua titik (poin 3c1a - 3c1c)

For c As Integer = 0 To Clusters.Count - 1
	For h As Integer = 0 To Points.Count - 1
. . .

3c1a. Hitung jarak dengan masing-masing centroid pada masing-masing cluster

Dim top As Double = HitungJarak(Points(h), Clusters(c))
If top < Epsilon Then top = Epsilon

3c1b. Hitung jumlah jarak titik dengan cluster pada semua cluster

Dim jumlahJarak As Double = 0.0
For ck As Integer = 0 To Clusters.Count - 1
	jumlahJarak += top / HitungJarak(Points(h), Clusters(ck))
Next

3c1c. Masukkan nilai jarak yang baru untuk sebuah titik pada masing-masing cluster

U(h, c) = CDbl(1.0 / Math.Pow(jumlahJarak, (2 / (Me.faktorFuzzy - 1))))

* Lakukan proses perpindahan titik ke cluster lain apabila diperlukan
Penjelasan lebih detail tentang fungsi ini dapat dilihat pada penjelasan skrip dibawah ini

Me.UpdateCluster()

Memasuki perhitungan pada fungsi UpdateCluster

3c2. Lakukan perulangan pada masing-masing titik (poin 3c2a - 3c2d)

3c2a. Cari nilai minimal dan maksimal sebuah titik pada masing-masing cluster

For j As Integer = 0 To Me.Clusters.Count - 1
	maks = If(U(i, j) > maks, U(i, j), maks)
	min = If(U(i, j) < min, U(i, j), min)
Next

3c2b. Lakukan normalisasi nilai titik pada masing-masing cluster
Normalisasi dihitung dengan rumus = (nilai awal - nilai minimal) / (nilai maksimal - nilai minimal)
Kemudian jumlahkan semua nilai yang baru

For j As Integer = 0 To Me.Clusters.Count - 1
	U(i, j) = (U(i, j) - min) / (maks - min)
	total += U(i, j)
Next

3c2c. Lakukan update nilai titik pada masing-masing fungsi, yaitu nilai baru dibagi totalnya
Kemudian cari nilai maksimal yang baru dari nilai yang baru diupdate ini

For j As Integer = 0 To Me.Clusters.Count - 1
	U(i, j) = U(i, j) / total
	If Double.IsNaN(U(i, j)) Then U(i, j) = 0.0

	maksBaru = If(U(i, j) > maksBaru, U(i, j), maksBaru)
Next

3c2d. Pindahkan titik ke cluster yang memiliki nilai tertinggi

p.indeksCluster = maksBaru

3d. Hitung nilai fungsi pada gambar yang telah mengalami pengelompokan
Fungsi untuk mencari nilai fungsi sudah dijelaskan pada penjelasan sebelumnya

Dim nilaiFungsiBaru As Double = fcm.hitungNilaiFungsi()

3e. Tampilkan selisih perhitungan sementara pada layar

bw.ReportProgress((100 * iterasi) / maksIterasi, New UpdateLabel(lblSelisihPerhitungan, "Selisih Perhitungan " & Math.Abs(fcm.nilaiFungsi - nilaiFungsiBaru).ToString("F2")))

3f. Tampilkan waktu perhitungan sementara pada layar

Dim waktu As String = [String].Format("{0:00}:{1:00}:{2:00}.{3:00}", sw.Elapsed.Hours, sw.Elapsed.Minutes, sw.Elapsed.Seconds, sw.Elapsed.Milliseconds / 10)
bw.ReportProgress((100 * iterasi) / maksIterasi, New UpdateLabel(lblLamaPerhitungan, Convert.ToString("Lama Perhitungan: ") & waktu))

3g. Tampilkan hasil perhitungan gambar sementara pada layar

picHasil.Image = DirectCast(fcm.getGambarHasilPerhitungan, Bitmap)

3h. Tampilkan jumlah perulangan yang telah dilakukan pada layar

bw.ReportProgress((100 * iterasi) / maksIterasi, New UpdateLabel(lblIterasi, "Iterasi " & iterasi))

3i. Apabila selisih nilai fungsi kurang dari batas minimal selisih perhitungan, maka hentikan perhitungan

If Math.Abs(fcm.nilaiFungsi - nilaiFungsiBaru) < batasMinimalSelisihPerhitungan Then Exit Do

4. Simpan hasil pengelompokan pixel gambar

picHasil.Image = DirectCast(fcm.getGambarHasilPerhitungan.Clone(), Bitmap)
fcm.getGambarHasilPerhitungan.Save("HasilFCM.png")

5. Buat gambar baru untuk mengetahui hasil potongan gambar awal pada masing-masing cluster

Dim jarak As Double(,) = fcm.U
Dim bmpPerCluster As Bitmap() = New Bitmap(centroids.Count - 1) {}
For i As Integer = 0 To centroids.Count - 1
	bmpPerCluster(i) = New Bitmap(gmbContoh.Width, gmbContoh.Height, PixelFormat.Format32bppRgb)
Next

6. Masukkan hasil gambar pada masing-masing cluster

For j As Integer = 0 To points.Count - 1
	For k As Integer = 0 To centroids.Count - 1
		Dim p As ClusterPoint = points(j)
		If jarak(j, k) = p.indeksCluster Then
			bmpPerCluster(k).SetPixel(CInt(p.X), CInt(p.Y), p.warnaOriginalPixel)
		End If
	Next
Next

7. Simpan hasil potongan gambar pada masing-masing cluster

For i As Integer = 0 To centroids.Count - 1
	bmpPerCluster(i).Save("HasilFCM_Cluster" & i & ".png")
Next

8. Tampilkan jumlah perulangan akhir pada layar

bw.ReportProgress(100, New UpdateLabel(lblIterasi, "Selesai dalam " & iterasi & " iterasi."))

9. Tampilkan total waktu perhitungan pada layar

Dim waktuSelesai As String = [String].Format("{0:00}:{1:00}:{2:00}.{3:00}", sw.Elapsed.Hours, sw.Elapsed.Minutes, sw.Elapsed.Seconds, sw.Elapsed.Milliseconds / 10)
bw.ReportProgress(100, New UpdateLabel(lblLamaPerhitungan, "Waktu perhitungan " & waktuSelesai & ""))


Hasil akhir adalah: (klik untuk perbesar gambar)

Hasil akhir gambar bergantung dari parameter jumlah cluster yang dihitung, semakin banyak cluster, maka hasil akhir gambar akan semakin baik, tetapi perhitungan akan semakin lama. Sesuai perhitungan pada poin 4 sampai dengan 7, setiap potongan data gambar yang mengalami pengelompokan akan disimpan sendiri-sendiri, sehingga dapat diketahui potongan gambar awal yang mana yang termasuk dalam masing-masing cluster
Berikut adalah perbandingan antara gambar awal dan hasil perhitungan gambar dengan 3 cluster

Wallpaper XP HasilFCM3Cluster dummy

Karena menggunakan 3 cluster, maka terdapat 3 potongan gambar sesuai dengan cluster masing-masing. Potongan gambar tersebut adalah sebagai berikut

HasilFCM3Cluster_Cluster0 HasilFCM3Cluster_Cluster1 HasilFCM3Cluster_Cluster2

Hanya sebagai catatan saja, dalam perhitungan tersebut digunakan 20 perulangan / iterasi, tetapi perhitungan selesai pada iterasi ke 13, karena selisih perhitungan pada iterasi ke 12 dan 13 adalah 0, sehingga tidak perlu meneruskan perhitungan sampai selesai. Waktu perhitungan adalah 1 menit lebih 5,97 detik
ssFCM



Contoh kedua adalah perbandingan antara gambar awal dan hasil perhitungan gambar dengan 10 cluster

Wallpaper XP HasilFCM10Cluster dummy

Dapat dilihat bahwa hasil perhitungan gambar akan lebih bagus, karena semakin banyak cluster yang dipakai
Karena menggunakan 10 cluster, maka terdapat 10 potongan gambar sesuai dengan cluster masing-masing. Potongan gambar tersebut adalah sebagai berikut

HasilFCM10Cluster_Cluster0 HasilFCM10Cluster_Cluster1 HasilFCM10Cluster_Cluster2
HasilFCM10Cluster_Cluster3 HasilFCM10Cluster_Cluster4 HasilFCM10Cluster_Cluster5
HasilFCM10Cluster_Cluster6 HasilFCM10Cluster_Cluster7 HasilFCM10Cluster_Cluster8
HasilFCM10Cluster_Cluster9 dummy dummy

Hanya sebagai catatan saja, dalam perhitungan tersebut digunakan 50 perulangan / iterasi, dan perhitungan selesai pada iterasi ke 49, karena selisih perhitungan pada iterasi ke 48 dan 49 adalah 0, sehingga tidak perlu meneruskan perhitungan sampai selesai. Waktu perhitungan adalah 24 menit lebih 4,61 detik. Waktu perhitungan yang cukup lama dibandingkan perhitungan sebelumnya dengan jumlah cluster yang lebih sedikit
ssFCM2


Contoh source code lengkap dalam bahasa VB (Visual Basic) dapat didownload disini:



Jika membutuhkan jasa kami dalam pembuatan program, keterangan selanjutnya dapat dilihat di Fasilitas dan Harga
Jika ada yang kurang paham dengan langkah-langkah algoritma diatas, silahkan berikan komentar Anda.
Selamat mencoba.

Tinggalkan sebuah komentar

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *