×

Membuat Scanner Document Corner Detection OpenCV Java

Membuat Scanner Document Corner Detection OpenCV Java

1,272 Views

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!)

  1. Mengubah RGB ke GrayScale
  2. Mengubah grayscale ke black white menggunakan algoritma otsu
  3. Mencari objek terbesar menggunakan contour
  4. Menerapakan convex hull agar didapatkan titik terluar
  5. 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

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";

 

See also  Belajar Java

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

See also  Mengubah Ukuran Font Netbeans dan setting Conf

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.

Hull_Original_Image.jpg

Hull_Result.jpg

Selain alasan diatas tentu yang paling penting yaitu kita harus menentukan titik terluar! mengingat timbul gerigi karena dokumen tersebut menggunakan penjepit spiral maka contour terbentuk berupa objek bergerigi sehingga perlu dihilangkan! mungkin sobat punya saran algoritma lain? kalau ada bisa comment dibawah ini. Sekarang kita hitung convex hull
//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

gambar diatas tidak cukup sempurna karena ada tonjolan dikit hasil dari operasi BW yang kurang begitu baik! namun hasil ini sudah jauh lebih baik karena sudah berbentuk lurus.

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

See also  Mendapatkan Nilai Pixel berdasarkan Event Click Mouse

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

  1. A: atas kiri
  2. B: atas kanan
  3. C: bawah kiri
  4. 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://stackoverflow.com/questions/45504604/efficient-way-of-sorting-a-listpoint-by-x-value/45504826

https://docs.opencv.org/3.4/d0/d49/tutorial_moments.html

https://stackoverflow.com/questions/40688491/opencv-getperspectivetransform-and-warpperspective-java

 

You May Have Missed