loading...

Kamis, 25 Oktober 2018

BAB 5 - Analisis Tekstur-Gray level cooccurance matrix-GLCM

Manusia mengenal tekstur seperti lembut dan kasar walaupun tangan tidak menyentuh benda tersebut, tapi otak mampu membedakan  hal tersebut melalui visualisasi yang ditangkap oleh mata. Tekstur dapat dicirikan sebagai berikut
  1. Pengulangan pola dari variasi lokal sehingga membentuk kesatuan yang utuh
  2. Menyediakan informasi susunan spasial dari warna dan intensitas citra
  3. Dicirikan dengan distribusi spasial dari level intensitas dari nilai pixel ketetanggaan
  4. Tidak bisa didefinisikan sebagai suatu satu point / nilai tertentu karena merupakan sebuah pola / kesatuan
Lihatlah ilustrasi berikut tentang tekstur sebuah citra yaitu terdiri dari 50% hitam dan 50% putih



Tentunya uji statistik standar seperti mean, standar deviasi tidak akan mampu membedakan ketiga citra tersebut karena akan menghasilkan nilai yang sama. Seperti yang sudah dijelaskan bahwa tekstur merupakan suatu pengulangan pola dan distribusi spasial artinya ketiga citra tersebut mempunyai tingkat intensitas nilai pixel yang sama tapi mempunyai distribusi spasial yang berbeda.

Analisis tekstur merupakan salah satu metode untuk melakukan identifikasi atau klasifikasi suatu citra, analisis tersebut telah banyak digunakan dalam berbagai bidang yaitu uji tekstur wajah, mutu keramik, membedakan jenis daun dan dalam interpretasi suatu peta sehingga dapat diketahui jenis lahan.

GLCM sebagai salah satu metode analisis tekstur

Gray-Level Co-occurrence matrix merupakan metode paling banyak digunakan untuk analisis tekstur. Metode ini diperkenalkan oleh Haralick di tahun 1973 yang merupakan bagian dari project yang didukung olah NASA yaitu tepatnya NASA Goddard Space Flight Center. Haralick menggunakan citra dari NASA ERTS untuk melakukan klasifikasi dengan tingkat akurasi diatas 80%.

Matrix GLCM dihitung dari nilai pixel yang berpasangan dan memiliki nilai intensitas tertentu. Misalkan d adalah jarak antara dua pixel yaitu (x1,y1) dan (x2,y2) dan Ѳ tetha didefinisikan sebagai sudut antara keduanya, maka matrix GLCM merupakan distribusi spasial dari Pd Ѳ (i,j). Banyak paper menuliskan berbagai versi tentang perhitungan GLCM terutama mengenai masalah sudut yang digunakan.  Berikut adalah ilustrasi yang menggambarkan arah sudut dengan jarak 1 pixel dan ada 4 jenis sudut yang digunakan:
a.    0o = 180o  
b.    45= 225o
c.    90= 270o , dan
d.    135o = 315o

tapi terkadang ada yang menyatakan terdiri dari 8 arah, hal ini terjadi karena antara sudut 0o dan 180o dianggap berbeda begitu juga dengan arah sudut yang lainnya

Perhitungan GLCM

Misalkan kita mempunyai gray matrix dengan skala intensitas dari 0 sampai 2
 Maka tentukan P1,0(M) yaitu matrix GLCM dari jarak 1 untuk sudut 0o
1.    Buatlah matrix pasangan yaitu
 2.    Misalkan hitung matrix pasangan (0,0) untuk sudut 0 dan 180

 Sehingga matrix GLCM nya adalah
 Langkah selanjutnya adalah melakukan normalisasi yaitu matrixGLCMNorm. Jumlah total nilai = 24


Bila dijumlahkan akan menghasilkan nilai 1. Matrix diatas merupakan input untuk perhitungan fitur tekstur.  Berikut adalah beberapa fitur yang bisa dihitung menggunakan GLCM yaitu terdiri dari 7 fitur utama dan 7 fitur tambahan yang diturunkan dari 7 fitur utama.
  1. Angular second moment/uniformity/energy
  2. Entropy
  3. Dissimilarity
  4. Contrast/inertia
  5. Correlation
  6. Homogeneity/inverse difference moment
  7. Autocorrelation
  8. Sum of squares (variance)
  9. Sum average
  10. Sum variance
  11. Sum entropy
  12. Difference variance
  13. Difference entropy
  14. Information measures of correlation

Perhitungan 7 fitur utama

1. Angular second moment/uniformity/energy



Mengukur tentang keseragaman atau sering disebut angular second moment. Energy akan bernilai tinggi ketika nilai pixel mirip satu sama lain sebaliknya akan bernilai kecil menandakan nilai dari GLCM normalisasi adalah heterogen. Nilai maksimum dari energy adalah 1 yang artinya distribusi pixel dalam kondisi konstan atau bentuk nya yang berperiodik (tidak acak). Hasil perhitungan  diatas adalah
f1 = 0.1042

2. Entropy


Mengukur kompleksitas(keacakan) citra. Entropy akan bernilai tinggi ketika citra tidak seragam. Hasil perhitungan diatas adalah
f2 = 2.325

3. Dissimilarity


Mengukur ketidakmiripan suatu tekstur, yang akan bernilai besar bila acak dan sebaliknya akan bernilai kecil bila seragam. Hasil perhitungan diatas adalah
f3 = 1.5833

4. Contrast/inertia


Mengukur frekuensi spasial dari citra dan perbedaan moment GLCM. Perbedaan yang dimaksudkan adalah perbedaan tinggi dan rendah nya pixel.  Contrast akan bernilai 0 jika pixel ketetanggaan mempunyai nilai yang sama. Hasil perhitungan diatas adalah
f4 = 3.416

5. Correlation



Dengan
Mengukur linearitas (the  joint  probability) dari sejumlah pasangan pixel (pairs).
 

Hasil perhitungan diatas adalah
f5 = 0.1042

6. Homogeneity/inverse difference moment



Mengukur homogenitas. Nilai ini sangat sensitif terhadap nilai disekitar diagonal utama. Bernilai tinggi ketika semua pixel mempunyai nilai yang sama / seragam.  Kebalikan dari contrast yaitu akan bernilai besar jika mempunyai nilai pixel yang sama pada saat energy bernilai tetap. Hasil perhitungan diatas adalah
f6 = 0.392

7. Autocorrelation


Mengukur correlation diantara garis diagonal utama. Hasil nya contoh diatas adalah
f7 = 5.5

Catatan:
i dan j menggunakan nilai initial 1 bukan 0


Agar lebih mudah, saya buat 2 class yaitu class GLCM dan class Feature
Daftar penggunaan library

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Accord.Math;
using Accord.Math.Decompositions;
using System;




class GLCM


    ///<summary>
    /// class GLCM untuk melakukan perhitungan matrix gray level co-occurance
    /// input berupa matrix gray level 
    /// *note: untuk nilai matrix yang negatif tidak akan dihitung 
    /// sudut ada 5 arah yaitu 
    /// SUDUT_0=0
    /// SUDUT_45=45
    /// SUDUT_90=90
    /// SUDUT_135=135
    /// SUDUT_ALL={0,45,90,135}
    /// H adalah matrix GLCM 
    /// T adalah matrix GLCM yang dinormalisasi
    /// </summary>
    public class GLCM
    {
        /// <summary>
        /// Set variasi sudut  
        /// 
        /// </summary>
        public static readonly int SUDUT_0 = 0;
        public static readonly int SUDUT_45 = 45;
        public static readonly int SUDUT_90 = 90;
        public static readonly int SUDUT_135 = 135;
        public static readonly int SUDUT_ALL = 360;

        private double[,] h;
        private double[,] t;

        /// <summary>
        /// matrix GLCM
        /// </summary>
        public double[,] H
        {
            get
            {
                return this.h;
            }

        }
        /// <summary>
        /// matrix GLCM ternormalisasi
        /// </summary>
        public double[,] T
        {
            get
            {
                return this.t;
            }
        }
        #region Start Core Process
        /// <summary>
        /// Perhitungan GLCM 
        /// </summary>
        /// <param name="data">matrix 2 dimensi</param>
        /// <param name="sudut">4 jenis sudut yaitu 0;45;90;135</param>
        /// <param name="maks">maksimal nilai matrix</param>
        public void Process(double[,] data, int sudut, int maks)
        {

            if (sudut != SUDUT_ALL)
            {
                //update - perhitungan glcm 
                this.h = this.DoCal(data, sudut, maks);
                double total = Matrix.Sum(this.h);
                //update - perhitungan glcm normalisasi
                this.t = this.h.Divide(total);
                /*Console.WriteLine("\n hasil nya");
                Prt.Print(this.h);
                Console.WriteLine("\n normalisasi \n");
                Prt.Print(this.t);*/
            }
            else
            { //jika dipilih untuk semua sudut
                //untuk sudut 0
                double[,] h0 = this.DoCal(data, 0, maks);
                //untuk sudut 45
                double[,] h45 = this.DoCal(data, 45, maks);
                //untuk sudut 90
                double[,] h90 = this.DoCal(data, 90, maks);
                //untuk sudut 135
                double[,] h135 = this.DoCal(data, 135, maks);
                h = new double[h0.GetLength(0), h0.GetLength(1)];

                for (int i = 0; i < h0.GetLength(0); i++)
                {
                    for (int j = 0; j < h0.GetLength(1); j++)
                    {
                        this.h[i, j] = h0[i, j] + h45[i, j] + h90[i, j] + h135[i, j]; //SUM --> jumlah semua nya
                    }
                }
                double total = Matrix.Sum(this.h);
                this.t = this.h.Divide(total);

            }

        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="sudut"></param>
        /// <param name="maks"></param>
        /// <returns></returns>
        private double[,] DoCal(double[,] data, int sudut, int maks)
        {
            maks = maks + 1;
            //untuk menyimpan hasil matrix glcm
            double[,] mat = new double[maks, maks];
            int baris = data.GetLength(0);
            // origin adalah titik acuan 
            // neigh adalah titik tetangga
            int kolom = data.GetLength(1);
            int origin, neight;


            //untuk sudut 0 dan 180    
            if (sudut == 0)
            {
                for (int i = 0; i < data.GetLength(0); i++)
                {
                    for (int j = 0; j < data.GetLength(1); j++)
                    {
                        //untuk arrah 0 
                        //check outofbox
                        // maka j+1
                        if ((j + 1) < kolom)
                        {
                            origin = (int)data[i, j];
                            neight = (int) data[i, j + 1];
                            //Console.Write(" ["+origin+"-"+neigh+"] ");
                            if (origin >= 0 && neight >= 0)
                            {
                                mat[origin, neight] = mat[origin, neight] + 1;
                            }
                        }
                        //untuk arrah 180
                        //check outofbox
                        //maka j-1
                        if ((j - 1) >= 0)
                        {
                            origin = (int)data[i, j];
                            neight = (int)data[i, j - 1];
                            //Console.Write(" ["+origin+"-"+neigh+"] ");
                            if (origin >= 0 && neight >= 0)
                            {
                                mat[origin, neight] = mat[origin, neight] + 1;
                            }
                        }

                    }
                    //Console.WriteLine();
                }
            }

            //untuk sudut 45 dan 225
            if (sudut == 45)
            {
                for (int i = 0; i < data.GetLength(0); i++)
                {
                    for (int j = 0; j < data.GetLength(1); j++)
                    {
                        //untuk arrah 45 
                        //check outofbox
                        // maka i-1 dan j+1
                        if ((j + 1) < kolom && (i - 1) >= 0)
                        {
                            origin = (int)data[i, j];
                            neight = (int)data[i - 1, j + 1];
                            //Console.Write(" ["+origin+"-"+neigh+"] ");
                            if (origin >= 0 && neight >= 0)
                            {
                                mat[origin, neight] = mat[origin, neight] + 1;
                            }
                        }
                        //untuk arrah 225 
                        //check outofbox
                        // maka  i+1,j-1
                        if ((j - 1) >= 0 && (i + 1) < baris)
                        {
                            origin = (int)data[i, j];
                            neight = (int)data[i + 1, j - 1];
                            //Console.Write(" ["+origin+"-"+neigh+"] ");
                            if (origin >= 0 && neight >= 0)
                            {
                                mat[origin, neight] = mat[origin, neight] + 1;
                            }
                        }


                    }
                    //Console.WriteLine();
                }
            }
            //untuk sudut 90 dan 180
            if (sudut == 90)
            {
                for (int i = 0; i < data.GetLength(0); i++)
                {
                    for (int j = 0; j < data.GetLength(1); j++)
                    {

                        //untuk arrah 90
                        //check outofbox
                        // maka i-1 
                        if ((i - 1) >= 0)
                        {
                            origin = (int)data[i, j];
                            neight = (int)data[i - 1, j];
                            //Console.Write(" ["+origin+"-"+neigh+"] ");
                            if (origin >= 0 && neight >= 0)
                            {
                                mat[origin, neight] = mat[origin, neight] + 1;
                            }
                        }
                        //untuk arrah 180
                        //check outofbox
                        // maka i+1 
                        if ((i + 1) < baris)
                        {
                            origin = (int)data[i, j];
                            neight = (int)data[i + 1, j];
                            //Console.Write(" ["+origin+"-"+neigh+"] ");
                            if (origin >= 0 && neight >= 0)
                            {
                                mat[origin, neight] = mat[origin, neight] + 1;
                            }
                        }


                    }
                    //Console.WriteLine();
                }
            }
            //untuk sudut 135 dan 225

            if (sudut == 135)
            {
                for (int i = 0; i < data.GetLength(0); i++)
                {
                    for (int j = 0; j < data.GetLength(1); j++)
                    {
                        //untuk arrah 135 
                        //check outofbox
                        // maka i-1 dan j-1
                        if ((j - 1) >= 0 && (i - 1) >= 0)
                        {
                            origin = (int)data[i, j];
                            neight = (int)data[i - 1, j - 1];
                            //Console.Write(" ["+origin+"-"+neigh+"] ");
                            if (origin >= 0 && neight >= 0)
                            {
                                mat[origin, neight] = mat[origin, neight] + 1;
                            }
                        }
                        //untuk arrah 270
                        //check outofbox
                        // maka i+1 dan j+1
                        if ((j + 1) < kolom && (i + 1) < baris)
                        {
                            origin = (int)data[i, j];
                            neight = (int)data[i + 1, j + 1];
                            //Console.Write(" ["+origin+"-"+neigh+"] ");
                            if (origin >= 0 && neight >= 0)
                            {
                                mat[origin, neight] = mat[origin, neight] + 1;
                            }
                        }


                    }
                    //Console.WriteLine();
                }
            }


            return mat;
        }

    } 

class Feature

    ///<summary>
    /// class Feature untuk melakukan perhitungan feature
    /// energy
    /// entropy
    /// contrast
    /// variance
    /// homogen
    /// correlation
    /// *note: untuk input matrix harus sudah ternormalisasi yaitu jika sum cummulativ ==0
    /// </summary>
    public class Feature
    {
        private double energy;
        private double entropy;
        private double contrast;
        private double variance;
        private double homogen;
        private double correlation;
        private double dissimilarity;
        private double autocorrelation;
        private double[,] data; //matrix[,]data adalah input nya  
        private double mx; //meanX
        private double my; //meanY
        private double sx; //standard deviasi stdX
        private double sy; //standard deviasi stdY

        /// <summary>
        /// constructor
        /// </summary>
        public Feature()
        {
            //init
            this.data = data;
            this.energy = 0;
            this.entropy = 0;
            this.contrast = 0;
            this.variance = 0;
            this.homogen = 0;
            this.dissimilarity = 0;
            this.autocorrelation = 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data">matrix GLCM yang ternormalisasi</param>
        public void Process(double[,] data)
        {
            //update
            this.data = data;
            this.energy = 0;
            this.entropy = 0;
            this.contrast = 0;
            this.variance = 0;
            this.homogen = 0;
            this.dissimilarity = 0;
            this.autocorrelation = 0;
            //hitung mean
            double total = Matrix.Sum(data);

            //Console.WriteLine("sum perkolom");
            //Prt.Print();
            double totalMean = total / (data.GetLength(0) * data.GetLength(1));
            //Console.WriteLine(totalMean);

            //hitung mx dan my
            this.mx = 0;
            this.my = 0;
            this.correlation = 0;

            for (int i = 0; i < data.GetLength(0); i++)
            {
                for (int j = 0; j < data.GetLength(1); j++)
                {
                    //hitung energy
                    energy = energy + Math.Pow(data[i, j], 2);
                    //hitung entropy
                    entropy = entropy - (data[i, j] * Math.Log(data[i, j] + 2.2204e-016));

                    //hitung contrast
                    contrast = contrast + (Math.Pow((i + 1) - (j + 1), 2) * data[i, j]);
                    //hitung variance
                    variance = variance + (Math.Pow(((double)i + 1) - totalMean, 2) * data[i, j]);
                    //hitung homogeneity
                    homogen = homogen + (data[i, j] / (1 + Math.Pow(((i + 1) - (j + 1)), 2)));
                    //hitung dissimiliarity
                    dissimilarity = dissimilarity + (Math.Abs((i + 1) - (j + 1)) * data[i, j]);
                    //hitung autocorrelation
                    autocorrelation = autocorrelation + ((i + 1) * (j + 1) * data[i, j]);
                    //hitung mx 
                    mx = mx + ((i + 1) * data[i, j]);
                    //hitung my
                    my = my + ((j + 1) * data[i, j]);
                }
            }
            //hitung sx dan sy
            this.sx = 0;
            this.sy = 0;
            for (int i = 0; i < data.GetLength(0); i++)
            {
                for (int j = 0; j < data.GetLength(1); j++)
                {
                    sx = sx + (Math.Pow((i + 1) - mx, 2) * data[i, j]);
                    sy = sy + (Math.Pow((j + 1) - my, 2) * data[i, j]);

                }
            }
            //hitung correlation
            for (int i = 0; i < data.GetLength(0); i++)
            {
                for (int j = 0; j < data.GetLength(1); j++)
                {
                    correlation = correlation + (((i + 1) - mx) * ((j + 1) - my) * data[i, j]);

                }
            }

            this.correlation = correlation / Math.Sqrt(sx * sy);

        }

        /// <summary>
        /// perhitungan energy
        /// </summary>
        public double Energy
        {
            get { return this.energy; }
        }
        /// <summary>
        /// perhitungan entropy
        /// </summary>
        public double Entropy
        {
            get { return this.entropy; }
        }
        /// <summary>
        /// perhitungan contrast
        /// </summary>
        public double Contrast
        {
            get { return this.contrast; }
        }
        /// <summary>
        /// perhitungan variance
        /// </summary>
        public double Variance
        {
            get { return this.variance; }
        }
        /// <summary>
        /// perhitungan homogen
        /// </summary>
        public double Homogen
        {

            get { return this.homogen; }
        }
        /// <summary>
        /// perhitungan correlation
        /// </summary>
        public double Correlation
        {
            get { return this.correlation; }
        }
        /// <summary>
        /// perhitungan dissimilarity
        /// </summary>
        public double Dissimilarity
        {
            get { return this.dissimilarity; }
        }
        /// <summary>
        /// perhitungan autocorrelation
        /// </summary>
        public double Autocorrelation
        {
            get { return this.autocorrelation; }
        }
        /// <summary>
        /// mean X
        /// </summary>
        public double Mx
        {
            get { return this.mx; }
        }
        /// <summary>
        /// mean Y
        /// </summary>
        public double My
        {
            get
            {
                return this.my;
            }
        }
        /// <summary>
        /// standar deviasi X
        /// </summary>
        public double Sx
        {
            get { return this.sx; }
        }
        /// <summary>
        /// standard deviasi Y
        /// </summary>
        public double Sy
        {
            get { return this.sy; }
        }

    }

Cara penggunaannya untuk array

double[,] data = new double[,] {
  { 0,   0,   1,   2 },
  {2,   0,   2,   0 },
  {1,   0,   0,   2 },
  {2,   0,   1,   1 }
};

GLCM glcm = new GLCM();
int sudut = 0;
int maksimal = 2;
glcm.Process(data,sudut,maksimal);
double[,] T = glcm.T; //matrix GLCM
double[,] H = glcm.H; //matrix GLCM setelah dinormalisasi!

Feature fitur = new Feature();
fitur.Process(T); //hasil matrix ternormalisasi
Console.WriteLine("Fitur");
Console.WriteLine("Autocorrelation : " + fitur.Autocorrelation);
Console.WriteLine("Contrast : " + fitur.Contrast);
Console.WriteLine("Correlation : " + fitur.Correlation);
Console.WriteLine("Dissimilarity : " + fitur.Dissimilarity);
Console.WriteLine("Energy : " + fitur.Energy);
Console.WriteLine("Entropy : " + fitur.Entropy);
Console.WriteLine("Homogen : " + fitur.Homogen);

Lumayan panjang sekali kodenya
Bagaimana aplikasi mudahnya diterapkan pada gambar?
Coba kamu baca link ini dulu
http://www.softscients.web.id/2018/10/bab-4-operasi-dasar-olah-citra-digital.html
tentu kamu harus ubah gambar truecolor menjadi grayscale, kemudian diubah image to matrix
Bila ingin agak bagus, coba pakai winform
http://www.softscients.web.id/2018/11/bab-4-winform.html

Bila kamu kurang jelas, tanyakan saja via email
Kalau kamu membuat aplikasi diatas menggunakan Python, pasti jauh lebih singkat kode nya
karena di Python ada OpenCv dan Numpy untuk computer visionnya
Makanya kamu belajar dulu basic Python

http://www.softscients.web.id/2018/11/buku-belajar-mudah-python-dengan.html

lebih jelasnya, untuk catatan add reference yaitu
gunakan Accord dengan release untuk net46
yaitu Accord.dll; Accord.Math.Core.dll; Accord.Math.dll

Tidak ada komentar: