Saya bekerja pada pengenalan multi-digit yang dicetak dengan tangan Java
, menggunakan OpenCV
perpustakaan untuk preprocessing dan segmentasi, dan Keras
model yang dilatih tentang MNIST (dengan akurasi 0,98) untuk pengakuan.
Pengakuan itu tampaknya bekerja cukup baik, terlepas dari satu hal. Jaringan sering gagal mengenali yang (nomor "satu"). Saya tidak tahu apakah itu terjadi karena preprocessing / implementasi segmentasi yang tidak benar, atau jika jaringan yang dilatih tentang MNIST standar belum melihat nomor satu yang terlihat seperti kasus pengujian saya.
Inilah tampilan digit bermasalah setelah preprocessing dan segmentasi:
menjadi dan diklasifikasikan sebagai 4
.
menjadi dan diklasifikasikan sebagai 7
.
menjadi dan diklasifikasikan sebagai 4
. Dan seterusnya...
Apakah ini sesuatu yang bisa diperbaiki dengan memperbaiki proses segmentasi? Atau lebih tepatnya dengan meningkatkan set pelatihan?
Sunting: Meningkatkan set pelatihan (augmentasi data) pasti akan membantu, yang sudah saya uji, pertanyaan tentang preprocessing yang benar masih ada.
Preprocessing saya terdiri dari pengubahan ukuran, konversi ke skala abu-abu, binarisasi, inversi, dan pelebaran. Berikut kodenya:
Mat resized = new Mat();
Imgproc.resize(image, resized, new Size(), 8, 8, Imgproc.INTER_CUBIC);
Mat grayscale = new Mat();
Imgproc.cvtColor(resized, grayscale, Imgproc.COLOR_BGR2GRAY);
Mat binImg = new Mat(grayscale.size(), CvType.CV_8U);
Imgproc.threshold(grayscale, binImg, 0, 255, Imgproc.THRESH_OTSU);
Mat inverted = new Mat();
Core.bitwise_not(binImg, inverted);
Mat dilated = new Mat(inverted.size(), CvType.CV_8U);
int dilation_size = 5;
Mat kernel = Imgproc.getStructuringElement(Imgproc.CV_SHAPE_CROSS, new Size(dilation_size, dilation_size));
Imgproc.dilate(inverted, dilated, kernel, new Point(-1,-1), 1);
Gambar yang telah diproses kemudian dibagi menjadi beberapa digit sebagai berikut:
List<Mat> digits = new ArrayList<>();
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(preprocessed.clone(), contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
// code to sort contours
// code to check that contour is a valid char
List rects = new ArrayList<>();
for (MatOfPoint contour : contours) {
Rect boundingBox = Imgproc.boundingRect(contour);
Rect rectCrop = new Rect(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height);
rects.add(rectCrop);
}
for (int i = 0; i < rects.size(); i++) {
Rect x = (Rect) rects.get(i);
Mat digit = new Mat(preprocessed, x);
int border = 50;
Mat result = digit.clone();
Core.copyMakeBorder(result, result, border, border, border, border, Core.BORDER_CONSTANT, new Scalar(0, 0, 0));
Imgproc.resize(result, result, new Size(28, 28));
digits.add(result);
}