Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Python > Сканер штрих-кодов на OpenCV и Python


Автор: iVovan1996 07.02.20, 18:30
Добрый вечер, форумчане! Я пишу сканер штрих-кодов по инструкциям на этом сайте:
https://habr.com/ru/company/enterra/blog/244163/
Я работаю с OpenCV 4.1.2, Python 3.7, Anaconda 2019 и PyCharm Community. В процессе реализации алгоритма я столкнулся с некоторыми проблемами.
Во-первых, подмодуль cv и константа CV_32F, которые используются в методе Собеля, были удалены в OpenCV 3.0. Я попробовал без подмодуля cv и получил ошибки, связанные с параметром --image. При этом пробная картинка лежит в папке с проектом, и путь к ней прописан. Какие аналоги есть у параметра --image и константы CV_32F в OpenCV 4.1.2 и Python 3.7?

Исходный код:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    # import the necessary packages
    import numpy as np
    import argparse
    import cv2
     
    # construct the argument parse and parse the arguments
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--image", required=True, help="5aa4dce1a6fd417e8b9df368d6c93842.jpg")
    args = vars(ap.parse_args())
     
    # load the image and convert it to grayscale
    image = cv2.imread(args["image"])
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
     
    # compute the Scharr gradient magnitude representation of the images
    # in both the x and y direction
    gradX = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
    gradY = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=0, dy=1, ksize=-1)
     
    # subtract the y-gradient from the x-gradient
    gradient = cv2.subtract(gradX, gradY)
    gradient = cv2.convertScaleAbs(gradient)
     
    # blur and threshold the image
    blurred = cv2.blur(gradient, (9, 9))
    (_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)
     
    # construct a closing kernel and apply it to the thresholded image
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
    closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
     
    # perform a series of erosions and dilations
    closed = cv2.erode(closed, None, iterations = 4)
    closed = cv2.dilate(closed, None, iterations = 4)
     
    # find the contours in the thresholded image, then sort the contours
    # by their area, keeping only the largest one
    (cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL,
                                 cv2.CHAIN_APPROX_SIMPLE)
    c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
     
    # compute the rotated bounding box of the largest contour
    rect = cv2.minAreaRect(c)
    box = np.int0(cv2.cv.BoxPoints(rect))
     
    # draw a bounding box arounded the detected barcode and display the
    # image
    cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
    cv2.imshow("Image", image)
    cv2.waitKey(0)


Ошибки:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    D:\Python\python.exe C:/barcode_scaner/barcode_scaner.py
    usage: barcode_scaner.py [-h] -i IMAGE
    barcode_scaner.py: error: the following arguments are required: -i/--image
     
    Process finished with exit code 2


Во-вторых, я хочу по цифрам на штрих-коде определить и вывести на экран информацию о товаре - его название, производителя, магазин и время его покупки, как в Едадиле. Самостоятельно я могу только создать в MySQL таблицу кодов разных стран, по таблице найти нужный код и вывести страну приобретения, а также проверить товар на подлинность, сверив хеш-сумму с последней цифрой. Где искать актуальные базы данных со штрих-кодами товаров на этот месяц и год, чтобы по ним вывести информацию о магазине, изготовителе, время покупки и название? С помощью каких библиотек и функций можно её прочитать в Python? Как подключиться к серверу Universe-HTT, чтобы отправить запрос с цифрами штрих-кода, а потом с помощью JSON считать данные о стране, названии, производителе и времени покупки?

Изображения смотрите по этим ссылкам:
Тестовое изображение
Папка с проектом

Добавлено
В-третьих, как определить область штрих-кода? Ведь я не знаю начальные координаты x0 и y0, известны только градиенты gradX и gradY, в которых лежит разность начальной и конечной координат. Я хочу обрезать картинку по области штрих-кода по иксу от x0 плюс/минус 1,5 до (x0 + gradX) плюс/минус 1,5 и точно также по игреку, создать отдельный файл, в котором пропишу функцию по извлечению и склейке цифрового кода, например, как здесь:
https://www.severcart.ru/blog/all/tesseract_ocr_python/

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    from PIL import Image
    import pytesseract
    import cv2
    import os
     
    image = '/tmp/tests.png'
     
    preprocess = "thresh"
     
    # загрузить образ и преобразовать его в оттенки серого
    image = cv2.imread(image)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
     
    # проверьте, следует ли применять пороговое значение для предварительной обработки изображения
     
    if preprocess == "thresh":
        gray = cv2.threshold(gray, 0, 255,
            cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
     
    # если нужно медианное размытие, чтобы удалить шум
    elif preprocess == "blur":
        gray = cv2.medianBlur(gray, 3)
     
    # сохраним временную картинку в оттенках серого, чтобы можно было применить к ней OCR
     
    filename = "{}.png".format(os.getpid())
    cv2.imwrite(filename, gray)
     
    # загрузка изображения в виде объекта image Pillow, применение OCR, а затем удаление временного файла
    text = pytesseract.image_to_string(Image.open(filename))
    os.remove(filename)
    print(text)
     
    # показать выходные изображения
    cv2.imshow("Image", image)
    cv2.imshow("Output", gray)
    input(‘pause…’)


А потом подключить этот файл к основному и оттуда вызвать функцию по определению цифр, в которую передам обрезанную картинку по области штрих-кода. Как узнать координаты области штрих-кода плюс/минус 1,5, чтобы правильно обрезать картинку, а потом считать и склеить цифры под штрих-кодом с помощью библиотеки pytesseract?

И в-четвёртых, как в Python включить русскую раскладку наподобии сишной функции setlocale из <locale.h>, чтобы компилятор не вывел вместо кириллицы вопросительные знаки?

Автор: amk 07.02.20, 21:11
Цитата iVovan1996 @
И в-четвёртых, как в Python включить русскую раскладку наподобии сишной функции setlocale из <locale.h>, чтобы компилятор не вывел вместо кириллицы вопросительные знаки?
Питон работает с UNICODE. Он должен нормально выводить кириллицу, если она есть в шрифтах. Попробуй вывести свою строку русского текста, записанную непосредственно в программе.

А вообще, в Python есть модуль locale, и в нём, представьте себе, есть функция setlocale.
Модуль напрямую использует библиотеку работы с локалями ANSI C.

Автор: iVovan1996 08.02.20, 11:17
Попробовал код отсюда:
https://pysource.com/2019/02/28/scanning-qr...cv-with-python/
Он даже вывел данные, но у меня остался тот же самый вопрос - как на их основе получить информацию о человеке, товаре или организации? Если это чек или товар, где взять базу данных магазинов и товаров или как и к какому серверу подключиться, чтобы вывести информацию о магазине и времени покупки, а также название товара, его стоимость и изготовителя? Если это визитка человека или организации - где взять базы данных известных личностей и организаций России и США или как подключиться к серверам с этими базами? Где взять файл barcode.csv из модулей argparse, datetime, imutils, time и cv2? В инструкциях написано:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    .vscode/opencv-tmp/barcodes.csv


Но это для линуксов. Где искать папку opencv-tmp в Anaconda-2019 и PyCharm Community?

Исходный код:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    import cv2
    import numpy as np
    import pyzbar.pyzbar as pyzbar
     
    cap = cv2.VideoCapture(0)
    font = cv2.FONT_HERSHEY_PLAIN
     
    while True:
        _, frame = cap.read()
     
        decodedObjects = pyzbar.decode(frame)
        for obj in decodedObjects:
            print("Data", obj.data)
            cv2.putText(frame, str(obj.data), (50, 50), font, 2,
                        (255, 0, 0), 3)
     
        cv2.imshow("Frame", frame)
     
        key = cv2.waitKey(1)
        if key == 27:
            break


Результат:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    D:\Python\python.exe C:/barcode_scaner/barcode_scaner.py
    Data b't=20200201T1743&s=100.00&fn=9284000100199295&i=143660&fp=1698079161&n=1'
    Data b't=20200201T1743&s=100.00&fn=9284000100199295&i=143660&fp=1698079161&n=1'
    Data b't=20200201T1743&s=100.00&fn=9284000100199295&i=143660&fp=1698079161&n=1'
    Data b't=20200201T1743&s=100.00&fn=9284000100199295&i=143660&fp=1698079161&n=1'


Изображение смотрите по этой ссылке:
Результат работы программы

Автор: amk 08.02.20, 16:54
EAN (UPC) содержит информацию:
- код страны где товар произведён. Если не ошибаюсь, это цифра, зашифрованная выбором штрихов в правой части и первая цифра, зашифрованная непосредственно штрихами (в UPC (США) есть только вторая, коды 01-09 принадлежат США и Канаде);
- предприятии, произведшем товар, это пять оставшихся цифр в левой части кода. Чтобы их распознать нужна база данных кодов предприятий. Возможно, эту таблицу можно приобрести в организации, распределяющей коды. В каждой стране отдельно. И наверняка, за большие деньги.
- внутренний номер товара предприятия это пять цифр в правой части. Здесь соответствующая база данных является внутренним делом предприятия, и искать её придётся на каждом предприятии отдельно.
Про контрольную сумму ты и сам знаешь. Как, наверняка, и про описанную только что структуру.

Даже теоретически приобрести аутентичные базы данных мало реально. Кроме того, номера товаров, снятых с производства, похоже могут использоваться повторно - база данных будет устаревать.

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

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

Да, ещё одно. Если код страны 02, то это код, присвоенный товару торговой точкой. Это коды, не имеющие EAN на упаковке, и товары, продаваемые на развес (тогда код содержит ещё и вес товара).

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)