С Python прочитаем любые штрих- и QR‑коды

Штрих-код — это метод представления данных в визуальной и машиночитаемой форме, он состоит из полос и пробелов. Сегодня мы видим штрих-коды повсюду, чаще всего на продуктах в супермаркетах.

Штрих-коды можно считывать с помощью оптического сканера штрих-кода, но здесь, для начала, напишем скрипт Python для считывания и декодирования штрих-кодов с рисунков, где они изображены.

Не столь часто используемый, но, как мне кажется, более ценный QR-код — тип матричного штрих-кода, который представляет собой машиночитаемую оптическую этикетку, которая содержит информацию об элементе, к которому она прикреплена. На практике QR-коды часто содержат данные для локатора, идентификатора или трекера, который указывает на веб-сайт или приложение и т. .д.

Для начала я расскажу вам, как считывать и декодировать штрих-коды, а также находить их на изображении. Потом вы узнаете, как сгенерировать и прочитать QR-коды в Python с помощью библиотек qrcode и OpenCV.

Для выполнения описанных здесь упражнений необходимо установить нужные нам зависимости:

pip3 install opencv-python qrcode pyzbar numpy

Как сделать считыватель штрих-кода на Python

Как только зависимости будут установлены, откройте новый файл Python и импортируйте то, что нужно для считывателя:

from pyzbar import pyzbar
import cv2

У меня есть несколько изображений для тестирования, вы можете использовать любое изображение из Интернета или своего собственного диска, но вы можете получить мои тестовые изображения в этом каталоге.

Я разбил всю функциональность по функциям и первая функция, которую мы обсудим, следующая:

def decode(image):
    # decodes all barcodes from an image
    decoded_objects = pyzbar.decode(image)
    for obj in decoded_objects:
        # draw the barcode
        print(f"Обнаружен штрих-код:\n{obj}")
        image = draw_barcode(obj, image)
        # print barcode type & data
        print("Тип:", obj.type)
        print("Данные:", obj.data)
        print()

    return image

Функция decode() принимает изображение в виде массива numpy и использует pyzbar.decode(), который отвечает за декодирование всех штрих-кодов из одного изображения и возвращает кучу полезной информации о каждом обнаруженном штрих-коде.

Затем мы перебираем все обнаруженные штрих-коды, рисуем прямоугольник вокруг штрих-кода и печатаем тип и данные штрих-кода. Чтобы прояснить ситуацию, вот как каждый объект выглядел, если мы его распечатали:

Decoded(data=b'43770929851162', type='I25', rect=Rect(left=62, top=0, width=694, height=180), polygon=[Point(x=62, y=1), Point(x=62, y=179), Point(x=756, y=180), Point(x=756, y=0)])

Таким образом, функция pyzbar.decode() возвращает данные, содержащие штрих-код, тип штрих-кода, а также точки расположения в виде прямоугольника и многоугольника.

Это подводит нас к следующей функции, которую мы использовали, draw_barcode():

def draw_barcode(decoded, image):
    # n_points = len(decoded.polygon)
    # for i in range(n_points):
    #     image = cv2.line(image, decoded.polygon[i], decoded.polygon[(i+1) % n_points], color=(0, 255, 0), thickness=5)
    # раскомментируйте выше и закомментируйте ниже, если хотите нарисовать многоугольник, а не прямоугольник
    image = cv2.rectangle(image, (decoded.rect.left, decoded.rect.top), 
                            (decoded.rect.left + decoded.rect.width, decoded.rect.top + decoded.rect.height),
                            color=(0, 255, 0),
                            thickness=5)
    return image

Эта функция берет декодированный объект, который мы только что видели, и само изображение, она рисует прямоугольник вокруг штрих-кода с помощью функции cv2.rectangle(), или вы можете раскомментировать другую версию функции; рисование многоугольника с помощью функции cv2.line(), выбор за вами. Я предпочел прямоугольную версию.

Ну наконец то, он возвращает изображение, содержащее нарисованные штрих-коды. Теперь давайте воспользуемся этими функциями для наших примеров изображений:

if __name__ == "__main__":
    from glob import glob

    barcodes = glob("barcode*.png")
    for barcode_file in barcodes:
        # загружаем изображение в opencv
        img = cv2.imread(barcode_file)
        # декодировать обнаруженные штрих-коды и получить изображение
        # нарисованный
        img = decode(img)
        # показать изображение
        cv2.imshow("img", img)
        cv2.waitKey(0)

В моем текущем каталоге у меня есть barcode1.png, barcode2.png и barcode3.png, которые являются примерами изображений отсканированного штрих-кода. Я использовал glob, чтобы получить все эти изображения в виде списка и перебирать их.

В каждый файл мы загружаем его с помощью функции cv2.imread() и используем ранее обсуждавшуюся функцию decode() для декодирования штрих-кодов, а затем показываем фактическое изображение.

Обратите внимание, что скрипт также обнаружит QR-коды, и это нормально, но для получения более точных результатов читайте вторую часть этой заметки.

Когда я запускаю сценарий, он показывает каждое изображение и печатает его тип и данные, нажмите любую клавишу, и вы получите следующее изображение, вот мой результат:

================== RESTART: D:\PHYTON\qrcode\barcode_reader.py =================
Обнаружен штрих-код:
Decoded(data=b'0036000291452', type='EAN13', rect=Rect(left=124, top=58, width=965, height=812), polygon=[Point(x=124, y=59), Point(x=124, y=869), Point(x=621, y=870), Point(x=1089, y=870), Point(x=1089, y=58)])
Тип: EAN13
Данные: b'0036000291452'

Обнаружен штрих-код:
Decoded(data=b'Wikipedia', type='CODE128', rect=Rect(left=593, top=4, width=0, height=294), polygon=[Point(x=593, y=4), Point(x=593, y=298)])
Тип: CODE128
Данные: b'Wikipedia'

Обнаружен штрих-код:
Decoded(data=b'43770929851162', type='I25', rect=Rect(left=62, top=0, width=694, height=180), polygon=[Point(x=62, y=1), Point(x=62, y=179), Point(x=756, y=180), Point(x=756, y=0)])
Тип: I25
Данные: b'43770929851162'

>>> 

Вот последнее показанное изображение:

Это здорово, теперь у вас есть отличный инструмент для создания собственного сканера штрих-кода на Python. Я знаю, что вы все хотите читать прямо с камеры и подготовил код для считывания и обнаружения штрих-кода с камеры в реальном времени. Вот он:

from pyzbar import pyzbar
import cv2


def draw_barcode(decoded, image):
    # n_points = len(decoded.polygon)
    # for i in range(n_points):
    #     image = cv2.line(image, decoded.polygon[i], decoded.polygon[(i+1) % n_points], color=(0, 255, 0), thickness=5)
    image = cv2.rectangle(image, (decoded.rect.left, decoded.rect.top), 
                            (decoded.rect.left + decoded.rect.width, decoded.rect.top + decoded.rect.height),
                            color=(0, 255, 0),
                            thickness=5)
    return image

def decode(image):
    # decodes all barcodes from an image
    decoded_objects = pyzbar.decode(image)
    for obj in decoded_objects:
        # draw the barcode
        image = draw_barcode(obj, image)
        # print barcode type & data
        print("Type:", obj.type)
        print("Data:", obj.data)
        print()

    return image


if __name__ == "__main__":
    cap = cv2.VideoCapture(0)
    while True:
        # read the frame from the camera
        _, frame = cap.read()
        # decode detected barcodes & get the image
        # that is drawn
        frame, decoded_objects = decode(frame)
        # show the image in the window
        cv2.imshow("frame", frame)
        if cv2.waitKey(1) == ord("q"):
            break

Вы также можете добавить какой-то звуковой сигнал при обнаружении каждого штрих-кода, так же, как в супермаркетах, ознакомьтесь с руководством по воспроизведению звуков, которые могут помочь вам в этом.

Для получения более подробной информации приглашаю вас почитать документацию pyzbar.

Как сгенерировать и прочитать QR-код в Python

Пришло время узнать, как сгенерировать и прочитать QR-коды в Python с помощью библиотек qrcode и OpenCV.

Создание QR-кода

Во-первых, давайте начнем с создания QR-кодов, это в целом очень просто при наличии библиотеки qrcode:

import qrcode

# пример данных
data = "https://waksoft.susu.ru"

# имя выходного файла
filename = "waksoft.susu.ru.png"

# генерировать qr-код
img = qrcode.make(data)

# сохранить img в файл
img.save(filename)

Это сгенерирует новый файл изображения в текущем каталоге с именем «waksoft.susu.ru.png», который содержит изображение QR-кода указанных данных (в данном случае URL этого веб-сайта), будет выглядеть примерно так:

Вы также можете использовать эту библиотеку для полного управления генерацией QR-кода с помощью класса qrcode.QRCode(), в котором вы можете создать экземпляр и указать размер, цвет заливки, задний цвет и исправление ошибок, например:

import qrcode
import numpy as np

# данные для кодирования
data = "https://waksoft.susu.ru"

# создать экземпляр объекта QRCode
qr = qrcode.QRCode(version=1, box_size=10, border=4)

# добавить данные в QR-код
qr.add_data(data)

# компилируем данные в массив QR-кода
qr.make()

# распечатать форму изображения
print("The shape of the QR image:", np.array(qr.get_matrix()).shape)

# переносим массив в реальное изображение
img = qr.make_image(fill_color="white", back_color="black")

# сохраняем в файл
img.save("waksoft.susu.ru_inversed.png")

Итак, при создании класса QRCode мы указываем параметр версии, который представляет собой целое число от 1 до 40, которое контролирует размер изображения QR-кода (1 — маленький, матрица 21×21, 40 — матрица 185×185), но это будет перезаписано, когда данные не соответствуют указанному вами размеру. В нашем случае он автоматически масштабируется до версии 3.

Параметр box_size управляет количеством пикселей в каждом прямоугольнике QR-кода, тогда как граница определяет, сколько прямоугольников должно иметь толщину.

Затем мы добавляем данные с помощью метода qr.add_data(), компилируем их в массив с помощью метода qr.make(), а затем создаем фактическое изображение с помощью метода qr.make_image(). Мы указали белый цвет как fill_color и черный как back_color, что является полной противоположностью QR-коду по умолчанию, посмотрите:

И форма изображения действительно увеличена, а не 21×21:

>>> 
================= RESTART: D:/PHYTON/qrcode/qr-code-inversed.py ================
The shape of the QR image: (33, 33)
>>> 

Читаем QR-код

Есть много инструментов, считывающих QR-код. Однако для этого мы будем использовать библиотеку OpenCV, поскольку она популярна и легко интегрируется с веб-камерой или любым видео.

Хорошо, откройте новый файл Python и следуйте за мной, давайте прочитаем только что сгенерированное изображение:

import cv2
# читать изображение QRCODE
img = cv2.imread("waksoft.susu.ru.png")

К счастью для нас, OpenCV уже имеет встроенный детектор QR-кода:

# инициализируем детектор QRCode cv2
detector = cv2.QRCodeDetector()

У нас есть изображение и детектор, давайте обнаружим и расшифруем эти данные:

# обнаружить и декодировать
data, bbox, straight_qrcode = detector.detectAndDecode(img)

Функция detectAndDecode() принимает изображение в качестве входных данных и декодирует его, чтобы вернуть кортеж из 3 значений: данные, декодированные из QR-кода, выходной массив вершин найденного четырехугольника QR-кода и выходное изображение, содержащее исправленный и преобразованный в двоичную форму QR-код.

Здесь нам просто нужны данные и bbox, который поможет нарисовать четырехугольник на изображении, и данные будут выведены на консоль!

Давай сделаем это:

# if there is a QR code
if bbox is not None:
    print(f"QRCode data:\n{data}")
    # отображаем изображение с линиями
    # длина ограничивающей рамки
    n_lines = len (bbox)    for i in range(n_lines):
        # рисуем все линии
        point1 = tuple(bbox[i][0])
        point2 = tuple(bbox[(i+1) % n_lines][0])
        cv2.line(img, point1, point2, color=(255, 0, 0), thickness=2)

Функция cv2.line() рисует отрезок линии, соединяющий две точки, мы получаем эти точки из массива bbox, который ранее был декодирован с помощью detectAndDecode(). Мы указали синий цвет ((255, 0, 0), поскольку OpenCV использует цвета BGR) и толщину 2.

Наконец, давайте покажем изображение и выйдем при нажатии клавиши:

# отобразить результат
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

После запуска распечатываются декодированные данные:

QRCode data:
https://waksoft.susu.ru

И показано следующее изображение:

Как видите, синие линии нарисованы точно в границах QR-кода. Отлично, мы закончили с этим скриптом, попробуйте запустить его с другими данными и посмотрите свои результаты!

Обратите внимание, что это идеально подходит для QR-кодов, а не для штрих-кодов.

Если вы хотите обнаруживать и декодировать QR-коды в реальном времени с помощью веб-камеры (и я уверен, что вы это делаете), вот код для этого:

import cv2
https://pypi.org/project/qrcode/
cap = cv2.VideoCapture(0)

# инициализируем детектор QRCode cv2
detector = cv2.QRCodeDetector()
while True:
    _, img = cap.read()
    # обнаружить и декодировать
    data, bbox, _ = detector.detectAndDecode(img)
    # проверяем, есть ли на изображении QRCode
    if bbox is not None:
        # отображаем изображение с линиями
        for i in range(len(bbox)):
            # рисуем все линии
            cv2.line(img, tuple(bbox[i][0]), tuple(bbox[(i+1) % len(bbox)][0]), color=(255, 0, 0), thickness=2)
        if data:
            print("[+] QR Code detected, data:", data)
    # отобразить результат
    cv2.imshow("img", img)    
    if cv2.waitKey(1) == ord("q"):
        break
cap.release()
cv2.destroyAllWindows()

Отлично, я закончил и теперь вы можете интегрировать его в свои собственные приложения!

Почитайте официальную документацию qrcode.

Источники вдохновения How to Generate and Read QR Code in Python и How to Make a Barcode Reader in Python

Print Friendly, PDF & Email

CC BY-NC 4.0 С Python прочитаем любые штрих- и QR‑коды, опубликовано К ВВ, лицензия — Creative Commons Attribution-NonCommercial 4.0 International.


Респект и уважуха

Добавить комментарий