В этой статье рассматривается алгоритм детектирования и распознавания символов с помощью библиотеки OpenCV. Работа будет интересна людям, начинающим изучение алгоритмов компьютерного зрения.
В настоящее время наблюдается рост вычислительных способностей компьютеров, смартфонов, растет качество камер, алгоритмы распознавания изображений улучшаются, и развивается такое направление в информационных технологиях как машинное зрение. Библиотека OpenCV создала инфраструктуру для людей, занимающихся алгоритмами машинного зрения, и позволила тысячам людей работать более продуктивно в этом направлении.
В этой статье будет рассмотрена проблема детектирования, и распознавания символов в реальном времени. Алгоритм, рассмотренный в этой статье, может стать основой для разработки приложения-переводчика для смартфона, которое бы переводило любые слова, которые попадают в объектив камеры. Такое приложение могло бы быть полезно туристам для перевода различных вывесок, которые они могут встретить в ходе своего путешествия по незнакомым странам.
Чтобы сделать такое приложение, нужно разработать алгоритм, который будет находить, и распознавать символы в видео. Дальнейшие шаги это группирование символов в слова и в предложение и отправка этого предложения в модуль, который будет заниматься переводом. В этой статье будет рассмотрен только алгоритм нахождения и распознавания символов.
В алгоритмах машинного зрения изображение трансформируется в другое изображение или в ответ [1]. Ответ может быть «Картинка содержит яблоко» или «Картинка содержит 2х собак и одну кошку». Чтобы достичь результата, проблема разбивается на несколько маленьких подзадач, которые решаются различными алгоритмами, многие из которых уже предоставлены библиотекой OpenCV в виде стандартных функций.
Дадим определения для выражений обнаружение объекта и распознавание объекта:
Задачу обнаружения и распознавания символов можно разделить на несколько шагов. Каждый шаг это преобразование изображения. В данном алгоритме были использованы следующие функции библиотеки.
Цветные изображения обычно представлены в формате RGB (красный, зеленый, синий). Это означает, что каждая точка изображения задается комбинацией трех чисел: красный — (0..255), зеленый — (0..255) и голубой — (0..255). Такое представление не всегда является удобным для обработки изображений, в OpenCVможно конвертировать формат изображения с помощью функции cvtColor, которая может конвертировать формат RGB в формат HSV, оттенки серого, и еще в много других форматов.
Имя и параметры функции:
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0);
Parameters: src — Входное изображение
dst — Изображение на выходе.
code — Код типа конвертации.
dstCn — Количество каналов в выходном изображении. Если параметр равен 0, количество каналов выставляется автоматически на основе входного изображения и кода конвертации” [3].
Пороговое преобразование это преобразование изображения на основе порогового значения. Каждый пиксель исходного изображения сравнивается с некоторым пороговым значением и на основе этого сравнения в выходное изображение записывается белый либо черный пиксель. Существует несколько типов порогового преобразования. Например, мы можем установить черный(0) цвет для значений меньше 100 и белый (255) для значений больше 100. В итоге мы получим черно-белое изображение, где на месте темных участков будет черный цвет, а на месте светлых белый цвет. Также мы могли задать белый цвет для значений больше 200 и оставить остальные значения без изменений. Все зависит от того что именно мы хотим выделить.
Для этой цели в библиотеке OpenCV есть две функции. Первая это cv::threshold:
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type);[3]
Эта функция делают свою работу хорошо, но приходится постоянно подбирать значение порога, чтобы достичь хороших результатов, и это значение нужно подбирать для каждого изображения.
Вторая функция автоматически подбирает пороговое значение. Эта функция называется cv::adaptiveThreshold:
void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C) [3]
В OpenCV есть функция Canny, она используется, чтобы найти края на изображении.
Нахождение краев это процесс нахождения пикселей, которые находятся на границах между отличающимися частями изображения. Например, у нас есть черный символ на белом фоне. Черные пиксели, граничащие с белыми пикселями, и есть пиксели, относящиеся к краю.
void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false); [2]
Результатом выполнения функции Canny является черно-белое изображение, где белые линии это найденные края. Чтобы получить контуры есть другая функция, которая должна быть выполнена после выполнения функции Canny. Эта функция называется cv::findContours:
void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point()) [4]
Результатом выполнения этой функции является множество контуров, каждый контур это множество точек, с помощью параметров можно задать ищем ли мы внешние или внутренние контуры.
Нахождение матрицы различий будет полезным, когда мы будем сравнивать символ с шаблоном. Чтобы найти матрицу различий в OpenCV есть простая функция absdiff:
absdiff вычисляет разницу по модулю для каждого элемента между двумя матрицами или между матрицей и числом.
void absdiff(InputArray src1, InputArray src2, OutputArray dst)
Параметры:
Был разработан алгоритм распознавания символов. Алгоритм состоит из нескольких частей:
Шаги обработки изображения
Финальный результат. Кириллические буквы заменены на латинские буквы. a) оригинальное изображение; b) результат
Используя функцию absdiff, находим матрицу разницы между шаблоном и текущим изображением выделенного объекта. Чтобы найти какой шаблон больше подходит, находим сумму всех элементов матрицы разницы, чем меньше это число, тем более похожи шаблон и изображение. Чтобы исключить ложные распознавания, будем считать, что изображение совпало с шаблоном, если в матрице различий не более 5—10 отличающихся пикселей.