Сегодня мы разберемся почему не читается QR-код с помощью OpenCV. В этом виновата камера? Попробуем найти и применить решение.
Сканер QR-кодов в OpenCV
Библиотека достаточно большая и активно развивающаяся.
В версии OpenCV 4.0 появился сканер QR-кодов. До этого обычно использовалась сторонняя библиотека ZBar, которая на данный момент является одной и самых мощных для сканирования широкого списка графических кодов.
Если вам интересно сравнение двух библиотек на практике, то напишите в комментариях об этом, и я сделаю для вас статью!
Не микроскоп, но смотрит близко
Понадобилось сканировать QR-коды с близкого расстояния (буквально пару сантиметров). Была выбрана камера Arducam USB.
Она может быть использоваться с короткофокусным и широкоугольным объективом (130 градусов FOV). Для этого на плату дополнительно устанавливается соответствующий объектив.
Первые тесты. Первые неудачи
Пробуем сделать фото QR-кода.
Пытаемся прочить QR-код и... ошибка - не удается расшифровать код.
Можете попробовать сами прочитать своей камерой код с картинки без красной рамки. Навряд ли у вас что-то выйдет.
Возникает вопрос: "Почему QR-код не читается OpenCV, не распознается, или распознается, но возвращается пустая строка?". А ответ лежит на поверхности - искажение объективом.
Контрастность и резкость - да, тоже важно. Но у нас сейчас главная проблема в дисторсии FOV (поля зрения). Эффект дисторсии (рыбий глаз) вызван примененной оптикой.
Чтобы прочитать код, нам придется откалибровать камеру. Если говорить точнее, то создать карту искажений и получить коэффициенты дисторсии, чтобы компенсировать искажения типа рыбьего глаза на нашей широкоугольной камере.
Калибруем и исправляем
Для поиска коэффициентов я набросал небольшой python скрипт calibration.py, в котором нет ничего кардинально отличающегося от официального примера OpenCV. Разве что лог и формат вывода. В общем, мелочи для удобства.
К calibration.py в репозитории прилагается udis.py и Chessboard_12x8.png - картинка шахматной доски.
Для калибровки нам понадобится шахматная доска, а вернее её изображение перед камерой.
Ищем коэффициенты
Делаем фото с разных положений и закидываем в папку img_set. Важно чтобы фото имели формат png.
Для проверки исправления закидываем пару фото в папку img_test. Из нее при выполнении udis.py будут браться фото и отправляться исправленные в папку undist.
Запускаем calibration.py (не забудьте прежде установить зависимости: pip install numpy opencv-python).
В логе мы увидим примерно следующее:
processing 0.0%, image: .\img_set\WIN_20230913_00_46_18_Pro.png... ok
processing 16.67%, image: .\img_set\WIN_20230913_00_46_35_Pro.png... ignore
processing 33.33%, image: .\img_set\WIN_20230913_00_46_53_Pro.png... ok
processing 50.0%, image: .\img_set\WIN_20230913_00_47_04_Pro.png... ok
processing 66.67%, image: .\img_set\WIN_20230913_00_47_16_Pro.png... ok
processing 83.33%, image: .\img_set\WIN_20230913_00_47_28_Pro.png... ok
processing 100%
RMS: 1.5491559181185144
camera_matrix = np.array([[484.70471536, 0. , 538.38023713],
[ 0. , 482.98833345, 544.09372506],
[ 0. , 0. , 1. ]])
dist_coefs = np. array([ 0.31932615, -0.0646646 , -0.00164196, -0.00349879, -0.04961284])
В датасете могут быть неудачные фото, на которых алгоритму не удается найти сетку. Такие фото будут пропущены и в логе отмечены соответствующей меткой, например: "...35_Pro.png... ignore".
Последние строки с camera_matrix и dist_coefs нам понадобятся для следующего скрипта - udis.py.
Прежде чем копировать строки, рекомендую проверить папку ChessboardCorners. Там можно будет увидеть найденные контрольные точки шахматной сетки.
Это важно проверить, т.к. алгоритм может расставить точки неверно. Например как на фото ниже.
Такая ошибка закрадется и в коэффициенты, что даст неверную калибровку в конечном итоге.
Если фотографий еще достаточно и данное расположение доски повторяется, то лучше удалить из исходного датасета (папки img_set) ту фотографию, на которой неверно распозналась сетка. Или удаляем, но добавляем новую фотографию.
Маленькое количество может дать неудовлетворительный (неточный) результат.
В любом случае после изменений датасета запускаем скрипт снова для получения новых коэффициентов.
Пробуем применить полученное
Копируем строки с коэффициентами в файл udis.py с заменой тех, которые там есть.
Запускаем udis.py и видим лог:
Undistorted image: ./img_test\WIN_20230913_00_48_33_Pro.png, Progress: 50.0%
Undistorted image: ./img_test\WIN_20230913_00_49_32_Pro.png, Progress: 100.0%
Идем в undist и смотрим, что получилось:
Мда! Кажется лучше не сделали. Искажения все-равно остались. Но попробуем прочить QR-код снова.
И снова сканируем
Возьмем изображение после обрезки.
Запускаем QR-code_reader.py и смотрим, что выдаст на этот раз.
Ура! Удалось победить!
Конечно полностью искажения не ушли, но для быстрого и простого исправления - результат положительный.
Выводы
С помощью OpenCV можно исправить дисторсию на фото. Калибровка очень простая и практически автоматическая. А с версии 4.0 появилась возможность считывать QR-коды, обходясь все той же OpenCV и все так же просто, буквально в пару строк кода.
Ссылки на проекты: QR-code_reader и opencv_Undistortion (calibration.py и udis.py).
—————————————————————————
Спасибо, что дочитали статью!
Подпишитесь пожалуйста на мой канал "Заметки Электроника | Alexander.Chad", этим Вы очень сильно поможете мне. Канал существует только за счет наличия и участия подписчиков.
Если Вам понравился материал - поддержите его лайком или даже донатом (ЮMoney). Есть что сказать? Оставьте комментарий! Это тоже будет помощью.
Сейчас канал нуждается в Вас как никогда прежде!