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
Contents
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
- CV_8U : rentang nilai 0 sampai 255
- CV_8S : rentang nilai -128 sampai dengan +127
- CV_16U : rentang nilai 0 sampai dengan 65,535
- CV_16S : rentang nilai -32,768 sampai +32,767
- CV_32S : rentang nilai -2,147,483,648 sampai dengan +2,147,483,647
- CV_32F : rentang floating -FLT_MAX sampai dengan FLT_MAX
- CV_64F : rentang double -DBL_MAX sampai dengan DBL_MAX
Oiya sebagai catatan diatas, kode huruf diatas itu punya arti sendiri-sendiri yaitu
- U kependekan dari unisgned / tidak bertanda sehingga disebut bilangan positif
- S kependekan dari signed / bertanda sehingga punya nilai negatif dan positif
- F kependekan dari float
Sedangkan simbol angka tersebut mempunyai arti pangkat [latextpage]
- Misalkan 8 mempunyai nilai maksimal \( 2^8-1= 255\ )
- 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
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