Belajar OpenCV di Java KMean Bagian 3

By | July 30, 2024
1,690 Views

Yuk kita bahas mengenai cara penggunaan KMeans Clustering di OpenCV-Java yang sangat mudah digunakan untuk membantu kalian daripada harus membuat kode sendiri. Adapun pembahasan mengenai KMeans Clustering dapat kalian pelajari disini. Saya asumsikan kalian sudah melakukan setup library OpenCV yang telah dibahas sebelumnya. Saya akan jelaskan tahapan dalam menggunakan KMeans Clustering OpenCV-Java yaitu

Mengenal Prosedur

Beberapa function OpenCV-Java menggunakan teknik Pass by Value untuk mendapatkan return nilai, contohnya adalah ketika akan menggunakan function untuk mengubah color RGB ke Grayscale, maka perlu dibuatkan dulu variabel destination nya

String input = "E:/cat.png";             
// To Read the image 
Mat source = Imgcodecs.imread(input); 
// Creating the empty destination matrix 
Mat destination = new Mat();       
// Converting the image to gray scale and  
// saving it in the dst matrix 
Imgproc.cvtColor(source, destination, Imgproc.COLOR_RGB2GRAY);

Hampir semua function wrapper OpenCV-Java menggunakan teknik tersebut, maka begitu juga untuk menghitung KMeans Clustering OpenCV-Java

Core.kmeans(dataset32f, jumlah_kelas, result_label, criteria, 2, Core.KMEANS_PP_CENTERS, result_center);

Hal ini dinamakan dengan procedure (yaitu function yang tidak mengembalikan nilai /  biasa dikenal di bahasa C)

Mengubah Array ke Mat

Semua masukan yang dibutuhkan OpenCV-Java membutuhkan object bernama Mat yang berupa Native Object, sehingga semua array dalam Java harus diubah dulu kedalam object Mat yang mempunyai nilai rentang sebagai berikut

  1. CV_8U : rentang nilai 0 sampai 255
  2. CV_8S : rentang nilai -128 sampai dengan +127
  3. CV_16U : rentang nilai 0 sampai dengan 65,535
  4. CV_16S : rentang nilai -32,768 sampai +32,767
  5. CV_32S : rentang nilai -2,147,483,648 sampai dengan +2,147,483,647
  6. CV_32F : rentang floating -FLT_MAX sampai dengan FLT_MAX
  7. CV_64F : rentang double -DBL_MAX sampai dengan DBL_MAX
See also  Belajar OpenCV bagian 1 - Setting OpenCV di Java

Oiya sebagai catatan diatas, kode huruf diatas itu punya arti sendiri-sendiri yaitu

  1. U kependekan dari unisgned / tidak bertanda sehingga disebut bilangan positif
  2. S kependekan dari signed / bertanda sehingga punya nilai negatif dan positif
  3. F kependekan dari float

Sedangkan simbol angka tersebut mempunyai arti pangkat [latextpage]

  1. Misalkan 8 mempunyai nilai maksimal \( 2^8-1= 255\ )
  2. Misalkan 32 mempunyai nilai maksimal \( 2^16-1= 65535\ )

Tapi biasanya sih,

secara umum rentang nilai warna hanya punya kedalaman 8 bit alias 0 sampai dengan 255 saja, kecuali untuk pengolahan citra satelit yang mempunyai rentang nilai yang panjang yaitu 16 bit

Misalkan kita akan mengubah array menjadi mat, saya berikan nama method nya yaitu array2mat

public static Mat array2mat(int [][] a) {
   Mat matObject = new Mat(a.length,a[0].length,CvType.CV_16S);
   for (int i=0;i<a.length;i++)
   {
      for(int j=0;j<a[0].length;j++)
      {
         matObject.put(i, j, a[i][j]);
      }
   }
   return matObject;
}

Maka rentang nilai yang bisa dimasukan yaitu CV_16S punya rentang nilai -32,768 sampai +32,767

Mengubah Mat ke Array

Adapun untuk mengubah Mat ke Array, bisa kalian pelajari dibawah ini

public static double [][] mat2array(Mat mat)
{
   int baris = mat.rows();
   int kolom = mat.cols();
   double [][] result = new double[baris][kolom];
   double [] buffer = new double [1]; //anggap saja 1 channel
   for (int i=0;i<baris;i++){
      for(int j=0;j<kolom;j++)
      {
         buffer = mat.get(i,j);
         result[i][j] = buffer[0];
      }
   }
   return result;
}

Class MatUtil

Kedua method diatas, saya gabungkan dalam sebuah class bernama MatUtil.java untuk memudahkan penggunaaan

import org.opencv.core.CvType;
import org.opencv.core.Mat;

/**
 *
 * @author mulkan.ms@gmail.com
 */
public class MatUtil {
    
    public static double [][] mat2array(Mat mat)
    {
        int baris = mat.rows();
        int kolom = mat.cols();
        double [][] result = new double[baris][kolom];
        double [] buffer = new double [1]; //anggap saja 1 channel
        for (int i=0;i<baris;i++){
            for(int j=0;j<kolom;j++)
            {
                buffer = mat.get(i,j);
                result[i][j] = buffer[0];
            }
        }
        return result;
    }
    public static Mat array2mat(double [][] a) {
        Mat matObject = new Mat(a.length,a[0].length,CvType.CV_32F);
        for (int i=0;i<a.length;i++)
        {
            for(int j=0;j<a[0].length;j++)
            {
                    matObject.put(i, j, a[i][j]);
            }
        }
        return matObject;
    }
    
}

Cara mudah untuk penggunaan class diatas yaitu

double [][] a = new double [][]{{2,3,4},{5,6,7},{8,9,10}};
System.out.println(Arrays.deepToString(a));
Mat mat = MatUtil.array2mat(a);
System.out.println("mat = " + mat.dump()); 
double [][] c = MatUtil.mat2array(mat);
System.out.println(Arrays.deepToString(c));

hasilnya

[[2.0, 3.0, 4.0], [5.0, 6.0, 7.0], [8.0, 9.0, 10.0]]
mat = [2, 3, 4;
 5, 6, 7;
 8, 9, 10]
[[2.0, 3.0, 4.0], [5.0, 6.0, 7.0], [8.0, 9.0, 10.0]

Mempersiapkan dataset

Kita akan mencoba untuk melakukan clustering terhadap sebuah array berikut

double [][] data = new double[][]{
        {25,79},
        {34,51},
        {22,53},
        {27,78},
        {33,59},
        {33,74},
        {31,73},
        {22,57},
        {35,69},
        {34,75},
        {67,51},
        {54,32},
        {57,40},
        {43,47},
        {50,53},
        {57,36},
        {59,35},
        {52,58},
        {65,59},
        {47,50},
        {49,25},
        {48,20},
        {35,14},
        {33,12},
        {44,20},
        {45,5},
        {38,29},
        {43,27},
        {51,8},
        {46,7}};

menjadi clustering 3 kelas

See also  Mendapatkan Nilai Pixel berdasarkan Event Click Mouse

int jumlah_kelas = 3;

bila kita plotkan sebagai berikut (menggunakan library jfreechart)

Kita akan mengubah terlebih dahulu Array diatas menjadi Mat dengan nama datasetxy

Mat datasetxy = MatUtil.array2mat(data);

Langkah selanjutnya membuat variabel mat untuk menampung hasil KMeans Clustering OpenCV-Java yaitu

Mat result_label = new Mat();
Mat result_center = new Mat();

Membuat kriteria berhenti / break

TermCriteria criteria = new TermCriteria(TermCriteria.COUNT, 100, 1);

Selanjutnya melakukan clustering menggunakan fungsi berikut

Core.kmeans(datasetxy, jumlah_kelas, result_label, criteria, 2, Core.KMEANS_PP_CENTERS, result_center);

Kita tampilkan hasil dari KMeans Clustering OpenCV-Java

System.out.println("label: "+result_label.dump());
System.out.println("center: "+result_center.dump());

hasil output diatas yaitu

run:
label: [1;
 1;
 1;
 1;
 1;
 1;
 1;
 1;
 1;
 1;
 2;
 2;
 2;
 2;
 2;
 2;
 2;
 2;
 2;
 2;
 0;
 0;
 0;
 0;
 0;
 0;
 0;
 0;
 0;
 0]
center: [43.200001, 16.700001;
 29.6, 66.800003;
 55.100002, 46.100002]
BUILD SUCCESSFUL (total time: 0 seconds)

Kita bisa mengubah result_center menjadi sebuah array

double [][] result = MatUtil.mat2array(result_center);

Bila kita plotkan akan nampak hasilnya

Sangat mudah bukan? menggunakan KMeans Clustering OpenCV-Java. Berikut kode lengkap untuk mencobanya DemoKMeans.java

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.TermCriteria;

public class DemoKMeans {
    public static void main(String[] args){
        
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);      
        double [][] data = new double[][]{
                {25,79},
                {34,51},
                {22,53},
                {27,78},
                {33,59},
                {33,74},
                {31,73},
                {22,57},
                {35,69},
                {34,75},
                {67,51},
                {54,32},
                {57,40},
                {43,47},
                {50,53},
                {57,36},
                {59,35},
                {52,58},
                {65,59},
                {47,50},
                {49,25},
                {48,20},
                {35,14},
                {33,12},
                {44,20},
                {45,5},
                {38,29},
                {43,27},
                {51,8},
                {46,7}};

        int jumlah_kelas = 3;
        Mat datasetxy = MatUtil.array2mat(data);
        Mat result_label = new Mat();
        Mat result_center = new Mat();

        TermCriteria criteria = new TermCriteria(TermCriteria.COUNT, 100, 1);            
        Core.kmeans(datasetxy, jumlah_kelas, result_label, criteria, 2, Core.KMEANS_PP_CENTERS, result_center);	

        System.out.println("label: "+result_label.dump());
        System.out.println("center: "+result_center.dump());

        double [][] result = MatUtil.mat2array(result_center);

        ScatterPlot scatterPlotDemo1 = new ScatterPlot("Sebaran data");
        scatterPlotDemo1.addXY(data,"data X-Y");
        scatterPlotDemo1.addXY(result,"center");
        scatterPlotDemo1.show("K-Means Clustering");
        
    }
}

Library Java untuk menampilkan dataset

Tentu yang sudah pernah menggunakan Python sangatlah mudah mengolah data dengan bentuk tabular tidak perlu ribet nulis kode panjang-panjang. Tapi ketika membuat aplikasi berbentuk GUI terkadang di Python agak sulit karena tidak punya aplikasi yang bagus untuk drag and drop, walaupun ada PyQT5. Ngomong-ngomong di Java untuk mengolah data tabular ada koq yaitu

  1. https://github.com/jtablesaw/tablesaw
  2. https://github.com/cardillo/joinery
  3. https://github.com/zavtech/morpheus-core
See also  Color Spaces - RGB - HSV - Lab/Cielab