Предварительная обработка изображений с помощью 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 по 3 вы также можете использовать двоичное изображение с шага 5 для вычисления плотности ребер.
Ответ 2
На самом деле OpenCV имеет предварительно подготовленную модель специально для российских номерных знаков: haarcascade_russian_plate_number
Также есть открытый проект ANPR для российских номерных знаков: plate_recognition. Он не использует tesseract, но имеет неплохую предварительно подготовленную нейронную сеть.
Ответ 3
- Вы найдете все подключенные компоненты (белые области) и определите их контуры.
- Если вы отфильтровываете их по размеру (как часть изображения), соотношению (ширина-высота) и бело-черному соотношению, чтобы получить кандидатные пластины.
- Отменить преобразование прямоугольника
- Снимите болты
- Передайте изображение движку OCR.