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

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

Мои шаги:

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

Истинное изображение

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) Gaussian Blur

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).
Заранее спасибо.

РЕДАКТИРОВАТЬ (благодаря ответу @Abdul Fatir) Хорошо, я предоставляю рабочий (для меня по крайней мере) пример кода (Netbeans+Java+OpenCV+Tess4j) для тех, кто интересуется этим вопросом. Код не самый лучший, но я сделал это только для изучения.
http://pastebin.com/H46wuXWn (не забудьте поместить папку tessdata в папку вашего проекта)

3 ответа

Решение

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

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

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

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

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

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

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

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

РЕДАКТИРОВАТЬ

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

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

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

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

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

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

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

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