Ich arbeite an handprinted mehrstelligen Anerkennung mit Java
, mit OpenCV
Bibliothek zur Vorverarbeitung und Segmentierung und ein Keras
Modell auf MNIST trainiert (mit einer Genauigkeit von 0,98) für die Anerkennung.
Abgesehen von einer Sache scheint die Erkennung recht gut zu funktionieren. Das Netzwerk erkennt diese häufig nicht (Nummer "Eins"). Ich kann nicht herausfinden, ob dies auf eine Vorverarbeitung / falsche Implementierung der Segmentierung zurückzuführen ist oder ob ein auf Standard-MNIST geschultes Netzwerk die Nummer eins, die wie meine Testfälle aussieht, einfach nicht gesehen hat.
So sehen die problematischen Ziffern nach der Vorverarbeitung und Segmentierung aus:
wird und wird klassifiziert als 4
.
wird und wird klassifiziert als 7
.
wird und wird klassifiziert als 4
. Und so weiter...
Kann dies durch eine Verbesserung des Segmentierungsprozesses behoben werden? Oder eher durch die Verbesserung des Trainingssatzes?
Bearbeiten: Eine Verbesserung des Trainingssatzes (Datenerweiterung) würde definitiv helfen, was ich bereits teste, die Frage der korrekten Vorverarbeitung bleibt weiterhin bestehen.
Meine Vorverarbeitung besteht aus Größenänderung, Konvertierung in Graustufen, Binärisierung, Inversion und Dilatation. Hier ist der Code:
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);
Das vorverarbeitete Bild wird dann wie folgt in einzelne Ziffern segmentiert:
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);
}