5.29. Штрихкоды и коды Data Matrix¶
Ещё два семейства кодов дополняют набор декодеров камеры. Одномерные штрихкоды – полоски на боку коробки хлопьев, больничный браслет, транспортная этикетка – это старейшие машиночитаемые символы, всё ещё используемые в повседневной жизни. Коды Data Matrix двумерны, как и QR-коды, но плотнее при том же размере полезной нагрузки и предназначены для промышленной маркировки – метка производителя, выгравированная лазером на печатной плате, а не плакат на стене. В модуле image есть отдельный декодер для каждого из них, охватывающий промышленные, розничные и инвентаризационные приложения, до которых потребительские 2D-коды так и не добрались.
5.29.1. Одномерные штрихкоды¶
Одномерный штрихкод кодирует свою полезную нагрузку как последовательность вертикальных полос различной ширины, читаемых слева направо (или сверху вниз для вертикально ориентированных кодов). Ширины квантуются к одному из небольшого набора значений, и последовательность ширин складывается в символы той символики, которую выбрал принтер: цифровой для товарного кода UPC, буквенно-цифровой для складского номера детали или произвольный текст для этикетки Code 128.
find_barcodes() сканирует кадр на наличие одномерных штрихкодов в любой из поддерживаемых символик и возвращает список объектов результата BarCode:
codes = img.find_barcodes()
for c in codes:
img.draw_rectangle(c.rect, color=(0, 255, 0))
print(c.payload, c.type, c.quality)
Декодер сканирует кадр и горизонтально, и вертикально за один вызов, поэтому штрихкод, напечатанный под любым углом, обнаруживается за один проход без необходимости поворачивать входные данные. roi ограничивает область поиска; других параметров настройки не существует – декодер самодостаточен.
Поддерживаемые символики охватывают распространённые потребительские и промышленные семейства. Розничный набор – это image.EAN2, image.EAN5, image.EAN8, image.UPCE, image.UPCA, image.EAN13 (цифровые коды фиксированной длины на большинстве потребительских упаковок), image.ISBN10 и image.ISBN13 (те же семейства, переназначенные для книг). Набор общего назначения – это image.I25 (Interleaved 2 of 5, распространённый на транспортных этикетках), image.CODABAR (используется в библиотеках и банках крови), image.CODE39, image.CODE93 и image.CODE128 (буквенно-цифровые символики переменной длины для произвольного текста). Семейство для полочных этикеток image.DATABAR (RSS-14) и image.DATABAR_EXP (RSS-Expanded) завершает список.
Каждое обнаружение несёт словарь ограничивающей рамки – x, y, w, h, rect, corners – и декодированную полезную нагрузку payload в виде строки. type – это константа символики из приведённого выше списка, которую приложение проверяет, когда его конкретно интересует, какое семейство было декодировано (например, принимая только EAN13 для приложения сканера продуктовых товаров).
Два поля, важные для фильтрации, – это rotation и quality. rotation – это угол штрихкода в плоскости изображения в радианах: декодер справляется с произвольными поворотами, но последующий код, который хочет аккуратно отобразить обнаружение, может захотеть отфильтровать коды, наклонённые сверх некоторого порога.
quality – это счётчик декодирований: число строк сканирования, которые успешно декодировали одну и ту же полезную нагрузку. Декодер проходит по каждой строке (и столбцу) кадра, пересекающей штрихкод, и увеличивает счётчик при каждом успешном декодировании. Напечатанный штрихкод в резком фокусе и при хорошем освещении даёт quality в десятки; частично перекрытый или смазанный штрихкод может декодироваться всего на одной-двух строках сканирования и сообщать quality 1 – 2. Отфильтровывание обнаружений ниже quality > 5 отбрасывает кратковременные ложные декодирования по одной строке без ущерба для подлинных обнаружений.
Приложение для одномерных штрихкодов невелико. Захватите кадр, вызовите find_barcodes(), переберите возвращённый список, отфильтруйте по c.type и c.quality и перешлите c.payload по UART или USB на тот последующий этап, который ведёт журнал или пробивает результат сканирования.
5.29.2. Data Matrix¶
Код Data Matrix – это 2D-символ, кодирующий свою полезную нагрузку как сетку чёрных и белых ячеек, подобно тому как это делает QR-код. От QR-кода он отличается в двух практических отношениях: он меньше при том же размере полезной нагрузки (кодирование плотнее) и нацелен на промышленное применение, а не на потребительское (где доминируют QR-коды). Узоры, выгравированные лазером на металлических деталях в цеху, этикетки, напечатанные на корпусах интегральных схем, метки, нанесённые на медицинские шприцы – всё это, как правило, Data Matrix, а не QR-коды.
find_datamatrices() сканирует кадр на наличие кодов Data Matrix и возвращает список объектов результата DataMatrix:
codes = img.find_datamatrices()
for c in codes:
img.draw_rectangle(c.rect, color=(0, 255, 0))
print(c.payload, c.rows, c.columns)
roi ограничивает область поиска обычным образом. Единственный регулятор настройки, специфичный для декодера, – это effort, целое число, управляющее тем, насколько усердно декодер работает, чтобы найти совпадение. Бо́льшие значения улучшают обнаружение слабых, повреждённых или наклонных кодов ценой частоты кадров; меньшие значения работают быстрее, но могут пропускать коды, которые нашло бы большее усилие. Значения ниже примерно 160 фактически не обнаруживают; значения выше примерно 240 дают убывающую отдачу. Значение по умолчанию 200 – разумный баланс для чёткого изображения, и правильная отправная точка для нового приложения – это значение по умолчанию плюс-минус 20 в зависимости от того, являются ли цели чистыми (меньше) или повреждёнными (больше).
Каждое обнаружение несёт словарь ограничивающей рамки и четыре обнаруженных угла, декодированную полезную нагрузку payload и угол поворота rotation в плоскости изображения в радианах. Метаданные раскладки описывают размер и плотность символа, который прочитал декодер: rows и columns – это количество ячеек в сетке данных; capacity – максимальное число символов полезной нагрузки, которое символ мог бы нести при таком размере; padding – сколько из этих слотов осталось неиспользованными (capacity - len(payload)).
Поля раскладки полезны для приложений, которым нужно проверять формат выгравированной метки, а не её содержимое. Система отслеживания деталей может требовать, чтобы все метки были кодами 12 на 12 с не более чем двумя символами заполнения; обнаружение, вернувшееся как 8 на 8 (символ меньше, чем требует спецификация) или с 10 символами заполнения (в основном пустое), помечается для повторной маркировки.
5.29.3. Когда что выбирать¶
Если выбор между QR и AprilTag сводился к виду полезной нагрузки (произвольные данные против небольшого идентификатора), то выбор между штрихкодами и кодами Data Matrix сводится к физической плотности и отрасли.
Когда приложение ориентировано на потребителя и коды уже существуют на местах – продукты, книги, транспортные этикетки, библиотечные книги – правильный детектор – это find_barcodes(). Коды, которые читает приложение, были напечатаны для чтения другой системой, и стандартизированные розничные символики – это именно то, что эта система ожидала.
Когда приложение промышленное и коды печатаются для самого приложения – инвентаризация в цеху, коды партий, выгравированные на деталях, метки прослеживаемости на медицинских устройствах – правильный детектор – это find_datamatrices() или find_qrcodes(), в зависимости от того, нужна ли приложению более высокая плотность Data Matrix или более широкая поддержка инструментов QR.
Небольшое число приложений объединяет все четыре детектора в одном конвейере. Камера инспекции упаковки может выполнять проход find_barcodes() для напечатанного UPC, проход find_qrcodes() для транспортного QR-кода на той же коробке и проход find_datamatrices() для выгравированного кода детали – всё на одном захваченном кадре; три списка результатов сопоставляются по положению ограничивающей рамки и сообщаются как одна запись обнаружения. Стоимость каждого детектора суммируется, поэтому приложения, делающие так, обычно сужают каждый проход подходящим roi, а не ищут в полном кадре каждый вид кода.