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
Contents
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
- nilai 0 muncul sebanyak 2
- nilai 1 muncul sebanyak 3
- nilai 2 muncul sebanyak 1
- nilai 3 muncul sebanyak 1
- nilai 4 muncul sebanyak 5
- nilai 5 muncul sebanyak 1
- 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
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); } }