Я работаю над многозначным распознаванием от руки Java
, используя OpenCV
библиотеку для предварительной обработки и сегментации, а также Keras
модель, обученную MNIST (с точностью 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);
}
источник
Ответы:
Я считаю, что ваша проблема в процессе расширения. Я понимаю, что вы хотите нормализовать размеры изображения, но вы не должны нарушать пропорции, вы должны изменить размер до максимального желаемого на одну ось (ту, которая позволяет максимально масштабировать, не позволяя другому размеру оси превышать максимальный размер) и заполнить с цветом фона остальной части изображения. Дело не в том, что «стандартный MNIST просто не видел номер один, который выглядит как ваши контрольные примеры», вы заставляете ваши изображения выглядеть как различные обученные числа (те, которые распознаются)
Если вы сохранили правильный формат изображения ваших изображений (исходный и постобработанный), вы увидите, что вы не просто изменили размер изображения, но и "исказили" его. Это может быть результатом либо неоднородного расширения, либо неправильного изменения размера
источник
Imgproc.resize(image, resized, new Size(), 8, 8, Imgproc.INTER_CUBIC);
. Здесь соотношение сторон остается тем же, где я могу нарушить пропорции?Уже опубликовано несколько ответов, но ни один из них не отвечает на ваш актуальный вопрос о предварительной обработке изображений .
В свою очередь, я не вижу каких-либо существенных проблем с вашей реализацией, если это хорошо изученный проект.
Но одна вещь, на которую стоит обратить внимание, вы можете пропустить. Существуют основные операции в математической морфологии: эрозия и расширение (используется вами). И есть сложные операции: различные комбинации основных (например, открытие и закрытие). Ссылка на Википедию - не самая лучшая ссылка на резюме, но вы можете начать с нее, чтобы понять.
Обычно лучше использовать раскрытие вместо эрозии и закрытие вместо расширения, поскольку в этом случае исходное двоичное изображение изменяется гораздо меньше (но достигается желаемый эффект очистки острых краев или заполнения зазоров). Так что в вашем случае вы должны проверить закрытие (расширение изображения с последующей эрозией с тем же ядром). В случае, если очень маленькое изображение 8 * 8 сильно изменяется, когда вы расширяетесь даже с ядром 1 * 1 (1 пиксель составляет более 16% изображения), что меньше на больших изображениях).
Чтобы визуализировать идею, смотрите следующие рисунки (из учебных пособий OpenCV: 1 , 2 ):
дилатация:
закрытие:
Надеюсь, поможет.
источник
Таким образом, вам нужен комплексный подход, потому что каждый шаг вашего вычислительного каскада основан на предыдущих результатах. В вашем алгоритме у вас есть следующие возможности:
Как упоминалось ранее, если вы примените изменение размера, то вы потеряете информацию о пропорциях изображения. Вы должны выполнить ту же обработку цифровых изображений, чтобы получить те же результаты, что и в процессе обучения.
Лучше, если вы просто обрезаете изображение по фиксированному размеру. В этом варианте вам не нужно искать контуры и изменять их размер перед тренировкой. Затем вы можете внести небольшие изменения в алгоритм обрезки для лучшего распознавания: просто найдите контур и поместите свою цифру без изменения размера в центре соответствующей рамки изображения для распознавания.
Также стоит уделить больше внимания алгоритму бинаризации. У меня был опыт изучения влияния пороговых значений бинаризации на ошибку обучения: могу сказать, что это очень важный фактор. Вы можете попробовать другие алгоритмы бинаризации, чтобы проверить эту идею. Например, вы можете использовать эту библиотеку для тестирования альтернативных алгоритмов бинаризации.
Для повышения качества распознавания вы используете перекрестную проверку в процессе обучения. Это поможет вам избежать проблемы переобучения ваших тренировочных данных. Например, вы можете прочитать эту статью, где объясняется, как использовать ее с Keras.
Иногда более высокие показатели точности ничего не говорят о реальном качестве распознавания, потому что обученный ANN не нашел шаблон в данных обучения. Это может быть связано с процессом обучения или входным набором данных, как объяснено выше, или это может быть вызвано выбором архитектуры ANN.
Это большая проблема. Как определить лучшую архитектуру ANN для решения задачи? Там нет общих способов сделать это. Но есть несколько способов приблизиться к идеалу. Например, вы можете прочитать эту книгу . Это поможет вам лучше понять вашу проблему. Также вы можете найти здесь некоторые эвристические формулы, чтобы соответствовать количеству скрытых слоев / элементов для вашего ANN. Также здесь вы найдете небольшой обзор для этого.
Я надеюсь, что это поможет.
источник
После некоторых исследований и экспериментов я пришел к выводу, что сама предварительная обработка изображения не была проблемой (я изменил некоторые предложенные параметры, такие как, например, размер и форма дилатации, но они не имели решающего значения для результатов). Что помогло, однако, были 2 следующие вещи:
Как заметил @ f4f, мне нужно было собрать свой собственный набор данных с реальными данными. Это уже очень помогло.
Я внес важные изменения в свою предварительную обработку сегментации. После получения отдельных контуров я сначала нормализую размеры изображений, чтобы они поместились в
20x20
пиксельную рамку (как они естьMNIST
). После этого я центрирую прямоугольник в центре28x28
изображения, используя центр масс (который для двоичных изображений является средним значением по обоим измерениям).Конечно, все еще существуют сложные случаи сегментации, такие как перекрывающиеся или связанные цифры, но вышеуказанные изменения ответили на мой первоначальный вопрос и улучшили мою классификацию.
источник