Membuat Scanner Document Corner Detection OpenCV Java
Membuat Scanner Document Corner Detection OpenCV Java – Corner Detection merupakan fitur yang selalu ada bila kita membuat aplikasi Scanner untuk mengetahui lokasi sebuah 4 titik sebuah objek seperti dokumen. Algoritma Corner Detection yang paling sering digunakan yaitu shi tomashi. Pernah kita bahas pada sesi sebelumnya Corner Detection yang menggunakan bahasa Python. Tentu dalam membuat aplikasi berbasis mobile untuk bahasa Python bukanlah sebuah pilihan yang tepat. Untuk Corner Detection yang nanti kita buat harus bisa diterapkan pada aplikasi berbasis android, oleh sebab itu bahasa Java yang kita pilih.
Algoritma ini akan saya gunakan untuk membuat aplikasi berbasis android untuk Scanner Document. Pembahasan mengenai Corner detection OpenCV Java sama seperti di Python hanya saja kode yang digunakan cukup panjang serta beberapa penyesuaian agar bisa kita terapkan secara nyata. Secara umum corner detection OpenCV Java yang nanti kita buat menggunakan algoritma seperti berikut (kalian bisa menyesuaikan dengan kondisi, misalkan ditambahkan dengan operasi ekualisasi histogram bila cahaya tidak seragam!)
- Mengubah RGB ke GrayScale
- Mengubah grayscale ke black white menggunakan algoritma otsu
- Mencari objek terbesar menggunakan contour
- Menerapakan convex hull agar didapatkan titik terluar
- Corner detection menggunakan shi tomashi
Saya sudah merancang algoritma diatas untuk 2 kasus yang berbeda, berikut hasil tersebut
Untuk hasil no 2 kurang sempurna karena proses otsu nya kurang begitu baik.
Mengubah RGB/BGR ke gray
Contents
Sebelum memulai project ini, kalian install dan setting terlebih dahulu OpenCV di netbeans. Seperti biasa kita load dulu OpenCV
// setting library System.loadLibrary(Core.NATIVE_LIBRARY_NAME); Imgcodecs imageCodecs = new Imgcodecs();
Untuk contoh gambar corner detection, saya menggunakan gambar dibawah ini. Berikut kode buat pengaturan file dan folder simpan
// setting lokasi file dan folder String folder = "D:\\project android\\"; String filename = folder+"corner_gambar.png";
Kita baca dan lakukan convert ke grayscale terlebih dahulu
Mat src = Imgcodecs.imread(filename); //1. ubah ke gray Mat srcGray = new Mat(); Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY);
Mengubah Gray ke BW
OpenCV mengharuskan input operasi BW dalam mode grayscale tidak seperti di Matlab rgb2bw bisa secara otomatis melakukan konversi, untuk hal tersebut kita buat perintah gray ke bw. Operasi BW disini menggunakan algortima Otsu agar nilai thresholding berjalan otomatis (oiya saya anggap gambar tersebut tidak perlu dilakukan histogram ekualisasi alias pencahayaan nya sama rata)
Mat bw = new Mat(); Imgproc.threshold(srcGray,bw, 0, 255, Imgproc.THRESH_OTSU); imageCodecs.imwrite(folder+"1. bw corner detection.jpg",bw);
Sekaligus kita akan simpan hasilnya biar nampak dalam bentuk file gambar. Tujuan operasi ini adalah untuk membuang objek2 yang tidak perlu. Nanti akan dipilih objek terbesar
Mencari objek terbesar menggunakan contour
untuk mencari objek terbesar menggunakan contour yaitu dengan cara mencari area terbesarnya! Biasanya operasi ini dikenal dengan operasi BLOB di Matlab. Perhatikan kode berikut untuk mencari contours.
Mat hierarchy = new Mat(); List<MatOfPoint> contours = new ArrayList<>(); Imgproc.findContours(bw, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_NONE);
Variable contour itu adalah MatOfPoint berisi lokasi X dan Y sebuah objek. Untuk mencari nilai objek/area terbesar gunakan perintah berikut
double maxVal = 0; int maxValIdx = 0; for (int contourIdx = 0; contourIdx < contours.size(); contourIdx++) { double contourArea = Imgproc.contourArea(contours.get(contourIdx)); //nilai areanya! if (maxVal < contourArea) { maxVal = contourArea; maxValIdx = contourIdx; } }
Informasi disimpan pada sebuah index yaitu maxValIdx. Nah untuk melihat hasilnya kita buat sebuah Mat objek terbaru sebagai penampung serta simpan hasilnya dalam bentuk gambar
Mat mRgba = new Mat(srcGray.height(), srcGray.width(),CvType.CV_8U); Imgproc.drawContours(mRgba, contours, maxValIdx, new Scalar(255,255,100),5); imageCodecs.imwrite(folder+"2. contour corner detection.jpg",mRgba);
Nah kalian bisa melihat hasilnya yaitu objek terbesar akan ditampilkan, hasilnya kurang bagus karena mengikuti bentuk objek yang mempunyai penjepit spiral. Sehingga kita butuh operasi tambahan berupa convex hull
Mengapa butuh Convex Hull?
Pada algoritma Corner Detection untuk menghasilkan corner dibutuhkan approx PolyDP karena belum nemu caranya di Java, saya ganti dengan Convex Hull saja untuk kemudian sebagai input ke algoritma shi tomashi menggunakan harris detector.
//5. bikin convex hull List<MatOfPoint> contoursTerpilih = new ArrayList<>(); contoursTerpilih.add(contours.get(maxValIdx)); List<MatOfPoint> hullList = new ArrayList<>(); for (MatOfPoint contour : contoursTerpilih) { MatOfInt hull = new MatOfInt(); Imgproc.convexHull(contour, hull); Point[] contourArray = contour.toArray(); Point[] hullPoints = new Point[hull.rows()]; List<Integer> hullContourIdxList = hull.toList(); for (int i = 0; i < hullContourIdxList.size(); i++) { hullPoints[i] = contourArray[hullContourIdxList.get(i)]; } hullList.add(new MatOfPoint(hullPoints)); } //drawing hux Mat convexHullMat = Mat.zeros(mRgba.size(), CvType.CV_8U); //CV_8UC3 for (int i = 0; i < contoursTerpilih.size(); i++) { Imgproc.drawContours(convexHullMat, hullList, i, new Scalar(255,0,255),5 ); } imageCodecs.imwrite(folder+"3. convex hull corner detection.jpg",convexHullMat);
Yuk kita lihat hasilnya dalam bentuk gambar
Corner detection menggunakan shi tomashi
Untuk corner detection pada OpenCV prinsip pakainya sama seperti di Corner Detection hanya saja kita menggunakan Java sebagai bahasanya. Berikut kode yang kita gunakan
//cari corner Mat drawingCorner = Mat.zeros(mRgba.size(), CvType.CV_8U); //CV_8U int maxCorners = 4; double qualityLevel = 0.01; double minDistance = 100; int blockSize = 3, gradientSize = 3; boolean useHarrisDetector = true; MatOfPoint corners = new MatOfPoint(); double k = 0.04; Imgproc.goodFeaturesToTrack(convexHullMat, corners, maxCorners, qualityLevel, minDistance, new Mat(), blockSize, gradientSize, useHarrisDetector, k); System.out.println("** Jumlah corner terdeteksi: " + corners.rows()); int[] cornersData = new int[(int) (corners.total() * corners.channels())]; corners.get(0, 0, cornersData); int radius = 10; for (int i = 0; i < corners.rows(); i++) { Imgproc.circle(src, new Point(cornersData[i * 2], cornersData[i * 2 + 1]), radius, new Scalar(255,0,0), Core.FILLED); } imageCodecs.imwrite(folder+"4. hux corner detection.jpg",src);
Kita tampilkan hasilnya
Memperbaiki Deskewing
Langkah selanjutnya yaitu menentukan lokasi A, B, C, dan D sebagai titik perspektif sesuai pada link Mendapatkan Nilai Pixel berdasarkan Event Click Mouse. Tugas kita yaitu menentukan lokasi
- A: atas kiri
- B: atas kanan
- C: bawah kiri
- D: bawah kiri
yang diproyeksikan ulang terhadap A’, B’, C’, dan D’
Saya perlihatkan bulatan corner detection yang diganti dengan angka berikut ini
Kita harus membuat algoritma agar setiap angka diatas disesuaikan dengan proyeksi yaitu
- angka 1 sebagai titik A
- angka 3 sebagai titik B
- angka 2 sebagai titik C
- angka 4 sebagai titik D
karena urutan 1, 2, 3, dan 4 akan berbeda-beda sesuai dengan objek yang dikenali. Untuk menentukan hal tersebut kita butuh titik acuan yaitu perhitungan moment sebagai perhitungan center of gravity Center Of Gravity dan Orientation Image. Perhatikan tulisan COG adalah center of gravity sebuah objek. Setelah ketemu titik A, B, C, dan D nanti kita akan memanfaatkan function di OpenCV yaitu
Mat warpMat = Imgproc.getPerspectiveTransform(srcPoint,dstPoint);
Untuk mengubah perspektifnya seperti berikut hasilnya
Nah tugas kalian coba merancang algoritma untuk operasi deskewing nya, kalian bisa baca referensi paling bawah ya untuk merancang algoritmanya! Bagaimana menurut kalian Membuat Scanner Document Corner Detection OpenCV Java.
Hasil di Android
Berikut hasil Membuat Scanner Document Corner Detection OpenCV Java di android
Berikut contoh yang lain
Berikut contoh dari penggunaan algoritma diatas
ref:
https://stackoverflow.com/questions/7263621/how-to-find-corners-on-a-image-using-opencv
https://www.programcreek.com/java-api-examples/?class=org.opencv.imgproc.Imgproc&method=arcLength
https://learnopencv.com/contour-detection-using-opencv-python-c/
https://docs.opencv.org/3.4/d0/d49/tutorial_moments.html
https://stackoverflow.com/questions/40688491/opencv-getperspectivetransform-and-warpperspective-java