Tôi đang làm việc với nhận dạng nhiều chữ số được in bằng tay Java
, sử dụng OpenCV
thư viện để tiền xử lý và phân đoạn, và một Keras
mô hình được đào tạo trên MNIST (với độ chính xác 0,98) để nhận dạng.
Sự công nhận dường như hoạt động khá tốt, ngoài một điều. Mạng thường không nhận ra được cái nào (số "một"). Tôi không thể biết liệu điều đó xảy ra do quá trình tiền xử lý / triển khai phân đoạn không chính xác hay nếu một mạng được đào tạo trên MNIST tiêu chuẩn chỉ không thấy số một giống như các trường hợp thử nghiệm của tôi.
Đây là những chữ số có vấn đề trông như thế nào sau khi tiền xử lý và phân đoạn:
trở thành và được phân loại là 4
.
trở thành và được phân loại là 7
.
trở thành và được phân loại là 4
. Và như thế...
Đây có phải là một cái gì đó có thể được sửa chữa bằng cách cải thiện quá trình phân khúc? Hay đúng hơn là bằng cách tăng cường tập huấn luyện?
Chỉnh sửa: Tăng cường tập huấn luyện (tăng dữ liệu) chắc chắn sẽ giúp ích, mà tôi đã thử nghiệm, câu hỏi về tiền xử lý chính xác vẫn còn.
Quá trình tiền xử lý của tôi bao gồm thay đổi kích thước, chuyển đổi sang thang độ xám, nhị phân, đảo ngược và giãn nở. Đây là mã:
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);
Hình ảnh được xử lý trước sau đó được phân đoạn thành các chữ số riêng lẻ như sau:
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);
}