Предварительная обработка изображений в 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 ответа
Вот как я предлагаю вам выполнить эту задачу.
- Преобразовать в оттенки серого.
- Размытие по Гауссу с фильтром 3x3 или 5x5.
Примените фильтр Собела, чтобы найти вертикальные края.
Sobel(gray, dst, -1, 1, 0)
- Пороговое значение результирующего изображения, чтобы получить двоичное изображение.
- Примените морфологическую операцию закрытия, используя подходящий структурирующий элемент.
- Найти контуры полученного изображения.
- найти
minAreaRect
каждого контура. Выберите прямоугольники на основе соотношения сторон и минимальной и максимальной площади. - Для каждого выбранного контура найдите граничную плотность. Установите порог для плотности кромок и выберите прямоугольники, нарушающие этот порог, в качестве возможных областей пластины.
- Несколько прямоугольников останутся после этого. Вы можете отфильтровать их на основе ориентации или любых критериев, которые вы считаете подходящими.
- Обрезать эти обнаруженные прямоугольные части изображения после
adaptiveThreshold
и применить OCR.
а) Результат после шага 5
б) Результат после шага 7. Зеленые - это все minAreaRect
s и красные - те, которые удовлетворяют следующим критериям: диапазон соотношения сторон (2,12) и диапазон площадей (300,10000)
в) Результат после шага 9. Выбранный прямоугольник. Критерии: Плотность края> 0.5
РЕДАКТИРОВАТЬ
Что касается краевой плотности, то, что я сделал в приведенных выше примерах, заключается в следующем.
- Примените детектор Canny Edge непосредственно к входному изображению. Пусть изображение cannyED будет Ic.
- Умножьте результаты фильтра Собеля и Ic. В основном, возьмите образы Собель и Кэнни.
- Gaussian Blur результирующее изображение с большим фильтром. Я использовал 21x21.
- Пороговое значение полученного изображения с использованием метода OTSU. Вы получите двоичное изображение
- Для каждого красного прямоугольника поверните часть внутри этого прямоугольника (в двоичном изображении), чтобы сделать его вертикальным. Прокрутите пиксели прямоугольника и посчитайте белые пиксели. ( Как вращать?)
Плотность краев = количество белых пикселей в прямоугольнике / общее количество пикселей в прямоугольнике
- Выберите порог для плотности края.
ПРИМЕЧАНИЕ. Вместо выполнения шагов 1–3 вы также можете использовать двоичное изображение из шага 5 для расчета плотности кромок.
На самом деле OpenCV имеет предварительно обученную модель специально для российских номерных знаков: haarcascade_russian_plate_number
Также существует открытый проект ANPR для российских номерных знаков: plate_recognition. Он не использует тессеракт, но имеет неплохую предварительно обученную нейронную сеть.
- Вы найдете все подключенные компоненты (белые области) и определите их контур.
- Если вы отфильтруете их по размеру (как части изображения), соотношению (ширина-высота) и соотношению белого / черного, чтобы получить планшеты-кандидаты.
- Отменить преобразование прямоугольника
- Снять болты
- Передайте изображение в механизм распознавания.