5.29. Códigos de barras e códigos Data Matrix

Mais duas famílias de códigos completam os descodificadores da câmara. Os códigos de barras unidimensionais – as riscas na lateral de uma caixa de cereais, uma pulseira hospitalar, uma etiqueta de envio – são os símbolos legíveis por máquina mais antigos ainda em uso quotidiano. Os códigos Data Matrix são bidimensionais como os códigos QR, mas mais densos para o mesmo tamanho de carga útil e destinados à marcação industrial – a marca do fabricante gravada a laser numa placa de circuito em vez do cartaz numa parede. O módulo image tem um descodificador dedicado para cada um, cobrindo as aplicações industriais, de retalho e de inventário que os códigos 2D de consumo nunca chegaram a alcançar.

5.29.1. Códigos de barras 1D

Um código de barras unidimensional codifica a sua carga útil como uma sequência de barras verticais de larguras variáveis, lida da esquerda para a direita (ou de cima para baixo para códigos com orientação vertical). As larguras quantizam para um de um pequeno conjunto de valores, e a sequência de larguras soletrar caracteres em qualquer simbologia que a impressora tenha escolhido: numérico para um código de produto UPC, alfanumérico para um número de peça de armazém, ou texto arbitrário para uma etiqueta Code 128.

find_barcodes() examina o fotograma à procura de códigos de barras 1D em qualquer das simbologias suportadas e devolve uma lista de objetos de resultado 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)

O descodificador examina horizontal e verticalmente o fotograma numa única chamada, pelo que um código de barras impresso em qualquer ângulo é encontrado numa única passagem sem que a aplicação precise de rodar a entrada. roi restringe a pesquisa; não existem outros parâmetros de ajuste – o descodificador é autossuficiente.

As simbologias suportadas cobrem as famílias comuns de consumo e industriais. O conjunto de retalho é image.EAN2, image.EAN5, image.EAN8, image.UPCE, image.UPCA, image.EAN13 (os códigos numéricos de comprimento fixo na maioria das embalagens de consumo), image.ISBN10 e image.ISBN13 (as mesmas famílias reutilizadas para livros). O conjunto de uso geral é image.I25 (Interleaved 2 of 5, comum em etiquetas de envio), image.CODABAR (usado em bibliotecas e bancos de sangue), image.CODE39, image.CODE93 e image.CODE128 (simbologias alfanuméricas de comprimento variável para texto arbitrário). A família de prateleira image.DATABAR (RSS-14) e image.DATABAR_EXP (RSS-Expanded) completam a lista.

Cada deteção contém o vocabulário de caixa delimitadora – x, y, w, h, rect, corners – e o payload descodificado como uma string. type é a constante de simbologia da lista acima, que uma aplicação verifica quando se importa especificamente com qual família foi descodificada (por exemplo, aceitar apenas EAN13 para uma aplicação de scanner de supermercado).

Os dois campos que importam para filtragem são rotation e quality. rotation é o ângulo no plano da imagem do código de barras em radianos: o descodificador suporta rotações arbitrárias, mas código posterior que queira apresentar a deteção de forma limpa pode querer filtrar códigos que chegam inclinados para além de um determinado limiar.

quality é a contagem de descodificações: o número de linhas de varrimento que descodificaram com sucesso a mesma carga útil. O descodificador percorre todas as linhas (e colunas) do fotograma que intersectam o código de barras, e incrementa o contador cada vez que a descodificação tem sucesso. Um código de barras impresso em foco nítido e boa iluminação produz um quality na casa das dezenas; um código de barras parcialmente ocluído ou borrado pode descodificar em apenas uma ou duas linhas de varrimento e reportar um quality de 1 – 2. Filtrar deteções abaixo de quality > 5 descarta descodificações incorretas transitórias de linha única sem custo para as deteções genuínas.

Uma aplicação de código de barras 1D é pequena. Capturar um fotograma, chamar find_barcodes(), iterar a lista devolvida, filtrar em c.type e c.quality, e encaminhar c.payload via UART ou USB para qualquer fase posterior que esteja a registar ou a processar a leitura.

5.29.2. Data Matrix

Um código Data Matrix é um símbolo 2D que codifica a sua carga útil como uma grelha de células pretas e brancas, à semelhança de um código QR. Difere de um código QR em dois aspetos práticos: é mais pequeno para o mesmo tamanho de carga útil (a codificação é mais densa) e destina-se a uso industrial em vez de uso de consumo (onde os códigos QR dominam). Os padrões gravados a laser em peças metálicas no chão de uma fábrica, as etiquetas impressas em embalagens de circuitos integrados, as marcas colocadas em seringas médicas – todos esses são tipicamente Data Matrices, não códigos QR.

find_datamatrices() examina o fotograma à procura de códigos Data Matrix e devolve uma lista de objetos de resultado 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 restringe a pesquisa da forma habitual. O único parâmetro de ajuste específico do descodificador é effort, um inteiro que controla a intensidade com que o descodificador trabalha para encontrar uma correspondência. Valores mais altos melhoram a deteção de códigos fracos, danificados ou oblíquos ao custo da taxa de fotogramas; valores mais baixos executam mais rapidamente mas podem falhar códigos que um esforço maior teria encontrado. Valores abaixo de aproximadamente 160 falham efetivamente a deteção; valores acima de aproximadamente 240 produzem retornos decrescentes. O padrão de 200 é um equilíbrio razoável para uma imagem clara, e o ponto de partida certo para uma nova aplicação é o padrão mais ou menos 20 dependendo de se os alvos estão limpos (menor) ou danificados (maior).

Cada deteção contém o vocabulário de caixa delimitadora e os quatro cantos detetados, o payload descodificado, e a rotation no plano da imagem em radianos. Os metadados de disposição descrevem o tamanho e a densidade do símbolo que o descodificador leu: rows e columns são as contagens de células da grelha de dados; capacity é o número máximo de caracteres de carga útil que o símbolo poderia transportar nesse tamanho; padding indica quantas dessas posições ficaram por usar (capacity - len(payload)).

Os campos de disposição são úteis para aplicações que precisam de validar o formato de uma marca gravada em vez do seu conteúdo. Um sistema de rastreio de peças pode exigir que todas as marcas sejam códigos 12 por 12 com no máximo dois caracteres de preenchimento; uma deteção que voltar a 8 por 8 (um símbolo mais pequeno do que o especificado) ou com 10 caracteres de preenchimento (maioritariamente vazia) é assinalada para regravar.

5.29.3. Quando escolher qual

Enquanto a escolha entre QR e AprilTag se baseava no tipo de carga útil (dados arbitrários versus ID pequeno), a escolha entre códigos de barras e códigos Data Matrix baseia-se na densidade física e na indústria.

Quando a aplicação é voltada para o consumidor e os códigos já existem no terreno – mercearias, livros, etiquetas de envio, livros de biblioteca – o detetor certo é find_barcodes(). Os códigos que a aplicação está a ler foram impressos para outro sistema os ler, e as simbologias de retalho padronizadas são o que esse sistema esperava.

Quando a aplicação é industrial e os códigos estão a ser impressos para a aplicação – rastreio de inventário num chão de fábrica, códigos de lote gravados em peças, marcas de rastreabilidade em dispositivos médicos – o detetor certo é find_datamatrices() ou find_qrcodes(), dependendo de se a aplicação necessita da maior densidade do Data Matrix ou do suporte de ferramentas mais amplo do QR.

Um punhado de aplicações mistura todos os quatro detetores num único pipeline. Uma câmara de inspeção de embalagens pode executar uma passagem find_barcodes() para o UPC impresso, uma passagem find_qrcodes() para um código QR de envio na mesma caixa, e uma passagem find_datamatrices() para um código de peça gravado, tudo no mesmo fotograma capturado; as três listas de resultados são correlacionadas por posição de caixa delimitadora e reportadas como um único registo de deteção. O custo de cada detetor acumula-se, pelo que as aplicações que fazem isto tipicamente restringem cada passagem com um roi adequado em vez de pesquisar o fotograma completo para cada tipo de código.