Предварительная обработка изображений с помощью OpenCV перед выполнением распознавания символов (tesseract)

Я пытаюсь разработать простое приложение для ПК для распознавания номерных знаков (Java + OpenCV + Tess4j). Изображения не очень хорошие (в дальнейшем они будут хорошими). Я хочу предварительно обработать изображение для tesseract, и я застрял на обнаружении номерного знака (обнаружение прямоугольника).

Мои шаги:

1) Исходное изображение

True Image

Mat img = new Mat();
img = Imgcodecs.imread("sample_photo.jpg"); 
Imgcodecs.imwrite("preprocess/True_Image.png", img);

2) Серые шкалы

Mat imgGray = new Mat();
Imgproc.cvtColor(img, imgGray, Imgproc.COLOR_BGR2GRAY);
Imgcodecs.imwrite("preprocess/Gray.png", imgGray);

3) Гауссовское размытие

Mat imgGaussianBlur = new Mat(); 
Imgproc.GaussianBlur(imgGray,imgGaussianBlur,new Size(3, 3),0);
Imgcodecs.imwrite("preprocess/gaussian_blur.png", imgGaussianBlur);  

4) Адаптивный порог

Mat imgAdaptiveThreshold = new Mat();
Imgproc.adaptiveThreshold(imgGaussianBlur, imgAdaptiveThreshold, 255, CV_ADAPTIVE_THRESH_MEAN_C ,CV_THRESH_BINARY, 99, 4);
Imgcodecs.imwrite("preprocess/adaptive_threshold.png", imgAdaptiveThreshold);

Здесь должен быть 5-й шаг, который является обнаружением области пластины (возможно, даже без коррекции на данный момент).

Я обрезал нужный регион из изображения (после 4-го шага) с помощью Paint и получил:

область плиты

Затем я сделал OCR (через tesseract, tess4j):

File imageFile = new File("preprocess/adaptive_threshold_AFTER_PAINT.png");
ITesseract instance = new Tesseract();
instance.setLanguage("eng");
instance.setTessVariable("tessedit_char_whitelist", "acekopxyABCEHKMOPTXY0123456789");
String result = instance.doOCR(imageFile); 
System.out.println(result);

и получил (достаточно хороший?) результат - "Y841ox EH" (почти верно)

Как я могу обнаружить и обрезать область пластины после 4-го шага? Могу ли я внести некоторые изменения (улучшения) в 1-4 шага? Хотелось бы увидеть пример, реализованный через Java + OpenCV (а не JavaCV).
Спасибо заранее.

EDIT (спасибо @Abdul Fatir) Ну, я предоставляю для меня (для меня по крайней мере) образец кода (Netbeans + Java + OpenCV + Tess4j) для тех, кто интересуется этим вопросом. Код не самый лучший, но я сделал его только для учебы.
http://pastebin.com/H46wuXWn (не забудьте поместить папку tessdata в папку проекта)

Ответ 1

Вот как я предлагаю вам выполнить эту задачу.

  • Преобразовать в оттенки серого.
  • Гауссовское размытие с фильтром 3x3 или 5x5.
  • Применить фильтр Sobel, чтобы найти вертикальные края.

    Sobel(gray, dst, -1, 1, 0)

  • Порог результирующего изображения для получения двоичного изображения.
  • Применить морфологическую операцию закрытия с использованием подходящего структурирующего элемента.
  • Найдите контуры результирующего изображения.
  • Найти minAreaRect каждого контура. Выберите прямоугольники на основе соотношения сторон и минимальной и максимальной областей.
  • Для каждого выбранного контура найдите плотность края. Установите порог плотности краев и выберите прямоугольники, которые пробивают этот порог как возможные области плитки.
  • После этого останется несколько прямоугольников. Вы можете отфильтровать их на основе ориентации или любых критериев, которые вы считаете подходящими.
  • Закрепите эти обнаруженные прямоугольные части изображения после adaptiveThreshold и примените OCR.

a) Результат после шага 5

Результат после шага 5

b) Результат после шага 7. Зеленые - это все minAreaRect, а красные - это те, которые удовлетворяют следующим критериям: Диапазон соотношения сторон (2,12) и диапазон областей (300 10000)

c) Результат после шага 9. Выбранный прямоугольник. Критерии: плотность края > 0,5

введите описание изображения здесь

EDIT

Для краевой плотности то, что я сделал в приведенных выше примерах, следующее.

  • Применить детектор Canny Edge непосредственно на входное изображение. Пусть cannyED изображение будет Ic.
  • Умножить результаты фильтра Собеля и Ic. В основном, возьмите изображения AND и Sobel и Canny.
  • Гауссов. Размытие изображения с большим фильтром. Я использовал 21x21.
  • Порог результирующего изображения с использованием метода OTSU. Вы получите двоичное изображение
  • Для каждого красного прямоугольника вращайте часть внутри этого прямоугольника (в бинарном изображении), чтобы сделать ее вертикальной. Прокрутите пиксели прямоугольника и подсчитайте белые пиксели. (Как повернуть?)

Плотность края = количество белых пикселей в прямоугольнике/общее число. пикселей в прямоугольнике

  1. Выберите порог плотности краев.

ПРИМЕЧАНИЕ. Вместо выполнения шагов с 1 по 3 вы также можете использовать двоичное изображение с шага 5 для вычисления плотности ребер.

Ответ 2

На самом деле OpenCV имеет предварительно подготовленную модель специально для российских номерных знаков: haarcascade_russian_plate_number

Также есть открытый проект ANPR для российских номерных знаков: plate_recognition. Он не использует tesseract, но имеет неплохую предварительно подготовленную нейронную сеть.

Ответ 3

  • Вы найдете все подключенные компоненты (белые области) и определите их контуры.
  • Если вы отфильтровываете их по размеру (как часть изображения), соотношению (ширина-высота) и бело-черному соотношению, чтобы получить кандидатные пластины.
  • Отменить преобразование прямоугольника
  • Снимите болты
  • Передайте изображение движку OCR.