温馨提示:本文翻译自stackoverflow.com,查看原文请点击:java - How to improve digit recognition of a model trained on MNIST?
java machine-learning MNIST opencv image-recognition

java - 如何提高在MNIST上训练的模型的数字识别能力?

发布于 2020-04-05 23:43:48

我正在使用进行手印多位数识别Java,使用OpenCV库进行预处理和分割,并使用KerasMNIST训练模型(精度为0.98)进行识别。

除了一件事之外,这种识别似乎效果很好。网络经常无法识别那些(数字“一”)。我不知道这是由于预处理的错误/分割的不正确而发生的,还是在标准MNIST上训练的网络没有看到看起来像我的测试用例的第一名。

这是经过预处理和分段后出现问题的数字的样子:

在此处输入图片说明成为在此处输入图片说明并归类为4

在此处输入图片说明成为在此处输入图片说明并归类为7

在此处输入图片说明成为在此处输入图片说明并归类为4等等...

通过改进细分过程,可以解决此问题吗?还是通过增强培训设置?

编辑:增强训练集(数据扩充)肯定会有所帮助,这已经在我测试中,正确预处理的问题仍然存在。

我的预处理包括调整大小,转换为灰度,二值化,反转和膨胀。这是代码:

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

然后将预处理后的图像分割成各个数字,如下所示:

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);
}

查看更多

提问者
youngpanda
被浏览
78
youngpanda 2020-02-01 01:36

经过一些研究和实验,我得出的结论是图像预处理本身不是问题(我确实更改了一些建议的参数,例如膨胀大小和形状,但对结果并不重要)。但是,有帮助的是以下两个方面:

  1. 正如@ f4f所注意到的,我需要收集自己的包含真实数据的数据集。这已经极大地帮助了。

  2. 我对细分预处理进行了重要更改。获得单个轮廓后,我首先对图像进行尺寸规格化以适合20x20像素盒(如中所示MNIST)。之后,我使用质心将框居中于28x28图像的中间(对于二值图像,这是两个方向上的平均值)。

当然,仍然存在困难的分割情况,例如重叠的数字或相连的数字,但是上述更改回答了我的最初问题,并改善了分类性能。