OpenCV di Java untuk menghitung Histogram Bagian 5

By | January 28, 2021
Print Friendly, PDF & Email
1,492 Views

Kita lanjutkan saja artikel sebelumnya, sekarang bahas mengenai perhitungan histogram citra/image menggunakan OpenCV-Java. Perhitungan histogram memang agak sedikit unik karena object Mat harus dipack ulang kedalam sebuah class Arraylist Map. Oiya selain itu kita akan membahas cara mengukur waktu yang dibutuhkan dalam sebuah proses, seperti kalau menggunakan Matlab/Octave berupa tic-toc. Yuk langsung saja agar kalian lebih paham cara kerjanya, saya akan berikan contoh sebuah data vector sebagai berikut

Data vector

Kalian bisa melihat variabel vector berikut yang sengaja saya acak urutannya

float[] data = new float[]{0,0,1,1,1,2,3,4,5,6,4,4,4,4};

terdiri dari rentang nilai 0 sampai 6, maka frekuensi untuk masing-masing nilai diatas yaitu

  1. nilai 0 muncul sebanyak 2
  2. nilai 1 muncul sebanyak 3
  3. nilai 2 muncul sebanyak 1
  4. nilai 3 muncul sebanyak 1
  5. nilai 4 muncul sebanyak 5
  6. nilai 5 muncul sebanyak  1
  7. nilai 6 muncul sebanyak 1

Kalian bisa melihat melalui jfreechart berikut

Melalui plot histogram diatas, kita bisa mengetahui sebaran nilai pixel pada citra. Oke kita lanjut saja penerapannya

Kode untuk menghitung histogram

Terebih dahulu sesuai dengan variabel diatas, akan kita ubah kedalam sebuah object Mat

Mat matdata = new Mat(data.length,1, CvType.CV_32F);
matdata.put(0, 0, data);

selanjutnya kita akan pack kedalam class List-ArrayList

List<Mat> plane = new ArrayList<>();
plane.add(matdata);

Aturan yang ditentukan yaitu nilai maksimal serta membuat object Mat untuk menampung hasil frekuensi

int maksimal = 7; //dimulai dari angka 0 sampai 6
boolean accumulate = false;
Mat matfrekuensi = new Mat(); //untuk menampung hasil frekuensi

Langsung saja panggil function Imgproc.calcHist

Imgproc.calcHist(plane,
      new MatOfInt(0), //karena 1 channel
      new Mat(), 
      matfrekuensi, 
      new MatOfInt(maksimal), 
      new MatOfFloat(new float[]{0,maksimal}), 
      accumulate);
System.out.println(matfrekuensi.dump());

Hasilnya bisa kalian lihat seperti berikut

[2;
 3;
 1;
 1;
 5;
 1;
 1]

Bila kebutuhan lain seperti mengubah Mat ke vector yaitu

float[] result = new float[(int) (matfrekuensi.total() * matfrekuensi.channels())];
matfrekuensi.get(0, 0, result);

Oiya, saya menggunakan jfreechart, sehingga memudahkan dalam menampilkan grafik

LinePlot scatterPlotDemo1 = new LinePlot("Histogram");
scatterPlotDemo1.addXY(result,"data 1");
scatterPlotDemo1.setXLabel("nilai");
scatterPlotDemo1.setYLabel("frekuensi");
scatterPlotDemo1.show2("Line Plot");

Untuk pembahasan jfreechart ada di buku kami. Kode lengkap untuk perhitungan diatas yaitu

import java.util.ArrayList;
import java.util.List;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.imgproc.Imgproc;


/**
 *
 * @author mulkan.ms@gmail.com
 */
public class DemoHistSimple {
    public static void main(String [] args)
    {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        float [] data = new float []{0,0,1,1,1,2,3,4,5,6,4,4,4,4};
        Mat matdata = new Mat(data.length,1, CvType.CV_32F);
        matdata.put(0, 0, data);
        
        List<Mat> plane = new ArrayList<>();
        plane.add(matdata);
        
        System.out.println(matdata.dump());
        
        int maksimal = 7; //dimulai dari angka 0 sampai 6
        boolean accumulate = false;
        Mat matfrekuensi = new Mat(); //untuk menampung hasil frekuensi
        Imgproc.calcHist(plane,
                new MatOfInt(0), //karena 1 channel
                new Mat(), 
                matfrekuensi, 
                new MatOfInt(maksimal), 
                new MatOfFloat(new float[]{0,maksimal}), 
                accumulate);
        System.out.println(matfrekuensi.dump());
        
        //bila ingin mengubah mat ke vector
        float[] result = new float[(int) (matfrekuensi.total() * matfrekuensi.channels())];
        matfrekuensi.get(0, 0, result);
        
        
    }
    
}

Bagaimana menggunakan Histogram pada sebuah Citra

Untuk menghitung histogram pada sebuah citra caranya samaa koq, sebagai contoh disini berupa citra true color. Perlu diketahui mengenai format true color terdiri dari 3 layer / channel yaitu BGR – blue; green; dan red sehingga perlu di split.

//buat object Map Array List
ArrayList BGRPlane = new ArrayList();
//lakukan split BGR
Core.split(matimage, BGRPlane);

serta mengubah nilai maksimal menjadi 256

int maksimal = 256;

Berikut plot grafik menggunakan library jfreechart untuk menampilkan ketiga data BGR

See also  Belajar OpenCV di Java KMean Bagian 3

 

dapat disimpulkan bahwa gambar tersebut mempunya warna blue yang rendah. Bagaimana menurut kalian? sangat mudah bukan? Oiya sebagai gambaran bahwa pada gambar yang saya gunakan punya ukuran yang sangat besar yaitu

dimensi gambar tinggi: 600
dimensi gambar lebar: 1200
dimensi gambar channel: 3

Sangat cepat sekali prosesnya tidak lebih dari 0.05 detik yaitu

waktu yang dibutuhkan : 0.0485328

Sangat cepat sekali bukan?

Menghitung waktu proses di OpenCV-Java

Untuk menghitung waktu proses yang akurat, di OpenCV juga disediakan koq seperti tic-toc nya Matlab. Berikut contoh kode yang digunakan

double start = Core.getTickCount();
//proses letakan disini seperti looping atau apapun
//

double end = Core.getTickCount();
System.out.println("waktu yang dibutuhkan : "+((end-start)/Core.getTickFrequency()));

Berikut kode lengkap untuk melakukan perhitungan histogram pada sebuah citra truecolor

/**
 *
 * @author mulkan.ms@gmail.com
 */
import java.awt.List;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.File;
import java.util.ArrayList;
import org.opencv.core.CvType;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;

public class DemoHistImage {    

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        float start = Core.getTickCount();
        Imgcodecs imageCodecs = new Imgcodecs();
        Mat matimage = Imgcodecs.imread("E://cat.png",Imgcodecs.IMREAD_COLOR);
    
        System.out.println("dimensi gambar tinggi: "+matimage.rows());
        System.out.println("dimensi gambar lebar: "+matimage.cols());
        System.out.println("dimensi gambar channel: "+matimage.channels());
        //bila ingin menampilkan gambar
        //HighGui.imshow( "Tampil Gambar", matimage );        
        //HighGui.waitKey(0);
        
        //buat object Map Array List
        ArrayList BGRPlane = new ArrayList();
        //lakukan split BGR
        Core.split(matimage, BGRPlane);
        
        int maksimal = 256;
        boolean accumulate = false;
        Mat bluefrek = new Mat(), greenfrek = new Mat(), redfrek = new Mat();
        Imgproc.calcHist(BGRPlane, new MatOfInt(0), new Mat(), bluefrek, new MatOfInt(maksimal), new MatOfFloat(new float[]{0,maksimal}), accumulate);
        Imgproc.calcHist(BGRPlane, new MatOfInt(1), new Mat(), greenfrek, new MatOfInt(maksimal), new MatOfFloat(new float[]{0,maksimal}), accumulate);
        Imgproc.calcHist(BGRPlane, new MatOfInt(2), new Mat(), redfrek, new MatOfInt(maksimal), new MatOfFloat(new float[]{0,maksimal}), accumulate);
        
        double end = Core.getTickCount();
        System.out.println("waktu yang dibutuhkan : "+((end-start)/Core.getTickFrequency()));
        
        //menampilkan blue frekuensi
        System.out.println(bluefrek.dump());
        
   //bila ingin mengubah mat ke vector
        float[] blueresult = new float[(int) (bluefrek.total() * bluefrek.channels())];
        bluefrek.get(0, 0, blueresult);
        float[] greenresult = new float[(int) (greenfrek.total() * greenfrek.channels())];
        greenfrek.get(0, 0, greenresult);
        float[] redresult = new float[(int) (redfrek.total() * redfrek.channels())];
        redfrek.get(0, 0, redresult);
        
        

        
    }
    
}

 

See also  Mendapatkan Nilai Pixel berdasarkan Event Click Mouse

Leave a Reply