распознавание bar-кодов

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: распознавание bar-кодов

Непрочитанное сообщение Olej » 04 окт 2018, 18:55

Olej писал(а): 2-й из таких пакетов - PyQRNative, в своё время продвигаемый и популяризируемый Google.
Генератор QR кодов:

Код: Выделить всё

# -*- coding: utf-8 -*- 
import sys
import argparse
import PyQRNative
from PyQRNative import *

# QR generator using PyQRNative
ap = argparse.ArgumentParser()                        # construct the argument parse and parse the arguments
ap.add_argument( "-o", "--output", required = False,  help = "path to the output image file" )
ap.add_argument( "-v", nargs='?', const=True, required=False, help = "increased verbose level" )
ap.add_argument( "-s", nargs='?', const=True, required=False, help = "single line" )
args = vars( ap.parse_args() )
#print( args )
debug = args[ "v" ] != None                           # verbose level

#print( sys.stdin.isatty() )
s = u''
if args[ "s" ] != None:                               # single line input
    if sys.stdin.isatty():
        sys.stdout.write( 'get line (Enter for finishing): ' )
        sys.stdout.flush()
    s = sys.stdin.readline()
    if s[ len( s ) - 1 ] == '\n':
        s = s[ :-1 ]
else:                                                 # multi line input
    if sys.stdin.isatty():
       print( 'Enter text (^D for finishing)' )
    while True:
        l = sys.stdin.readline()
        if l == '': break                             # ^D - завершение ввода (EOF)
        s += l.decode( 'utf-8' )
#print( type( s ), len( s ), s )

if 2 == sys.version_info.major:
    b = bytes( s )
else:
    b = bytes( s, encoding = 'utf-8' )
#print( type( b ), b )
 
def makeQR( data, path, level = 1 ):
    quality= { 1: PyQRNative.QRErrorCorrectLevel.L,
               2: PyQRNative.QRErrorCorrectLevel.M,
               3: PyQRNative.QRErrorCorrectLevel.Q,
               4: PyQRNative.QRErrorCorrectLevel.H }
    size = 3
    while 1:
        try:
            q = PyQRNative.QRCode( size, quality[ level ] )
            q.addData( data )
            q.make()
            im = q.makeImage()
            im.save( path, format = "png" )
            break
        except TypeError:
            size += 1
            if debug: print( 'increase size: {}'.format( size ) )            
    if debug: print( 'size = {}'.format( size ) )
    return im

image = makeQR( b, 'qr1.png', level = 1 )

if args[ "output" ] != None:
    ifile = open( args[ "output" ] + '.jpg', 'wb' )
    image.save( ifile, 'JPEG' )
    ifile.close()
if debug:
    image.show()
Вложения
genqr2.py
(2.25 КБ) 88 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: распознавание bar-кодов

Непрочитанное сообщение Olej » 04 окт 2018, 19:00

Olej писал(а): Генератор QR кодов:

Код: Выделить всё

Выполнение:
[olej@dell QRgenerator]$ python2 genqr2.py -s -o xxx -v
get line (Enter for finishing): фыва
(<type 'str'>, 8, '\xd1\x84\xd1\x8b\xd0\xb2\xd0\xb0')
size = 3
А вот как зашиваются в QR бинарные данные, вообще не являются символами - просто поток байт ... с одним ограничением, что среди этих двоичных значений нет байта с значением 0: конец строки в C-соглашениях:

Код: Выделить всё

[olej@dell QRgenerator]$ cat 21.bin | python2 genqr2.py -s -o xxx -v
size = 3

[olej@dell QRgenerator]$ file xxx.jpg 
xxx.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 370x370, frames 3

[olej@dell QRgenerator]$ hexdump -b 21.bin
0000000 001 002 003 004 005 006 007 010 011 020 021 022 023 024 025 026
0000010 027 030 031 040 041                                            
0000015
Вложения
21.png
21.png (9.79 КБ) 2372 просмотра

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: распознавание bar-кодов

Непрочитанное сообщение Olej » 04 окт 2018, 20:05

Olej писал(а): Генератор QR кодов:
Но пакет PyQRNative, в отличие от других здесь, которые я перепробовал, не имеет симметричных методов декодирования QR изображений, только метод кодирования, который очень тонко и разнообразно настраивается.
Поэтому для контроля создаваемых QR нужно иметь какое-то независимое приложение ... например, использующее пакет pyzbar, показываемый уже раньше. Но прежде, возможно, нужно будет установить pyzbar:

Код: Выделить всё

[olej@dell QRgenerator]$ sudo python -m pip install pyzbar
[sudo] пароль для olej: 
Collecting pyzbar
  Using cached https://files.pythonhosted.org/packages/bd/e7/dc9aa3ee5ddc71df6ea1698f7e9d12dcc874346ad3051524155e121006a6/pyzbar-0.1.7-py2.py3-none-any.whl
Collecting pathlib>=1.0.1; python_version == "2.7" (from pyzbar)
  Downloading https://files.pythonhosted.org/packages/ac/aa/9b065a76b9af472437a0059f77e8f962fe350438b927cb80184c32f075eb/pathlib-1.0.1.tar.gz (49kB)
    100% |████████████████████████████████| 51kB 360kB/s 
Requirement already satisfied: enum34>=1.1.6; python_version == "2.7" in /usr/lib/python2.7/site-packages (from pyzbar) (1.1.6)
Installing collected packages: pathlib, pyzbar
  Running setup.py install for pathlib ... done
Successfully installed pathlib-1.0.1 pyzbar-0.1.7
Вот теперь можем написать приложение, выполняющее обратное декодирование сгенерированных QR:

Код: Выделить всё

# -*- coding: utf-8 -*- 
import sys
import argparse
import PyQRNative
from PyQRNative import *

# QR generator using PyQRNative
ap = argparse.ArgumentParser()                        # construct the argument parse and parse the arguments
ap.add_argument( "-o", "--output", required = False,  help = "path to the output image file" )
ap.add_argument( "-v", nargs='?', const=True, required=False, help = "increased verbose level" )
ap.add_argument( "-s", nargs='?', const=True, required=False, help = "single line" )
args = vars( ap.parse_args() )
#print( args )
debug = args[ "v" ] != None                           # verbose level

#print( sys.stdin.isatty() )
s = u''
if args[ "s" ] != None:                               # single line input
    if sys.stdin.isatty():
        sys.stdout.write( 'get line (Enter for finishing): ' )
        sys.stdout.flush()
    s = sys.stdin.readline()
    if s[ len( s ) - 1 ] == '\n':
        s = s[ :-1 ]
else:                                                 # multi line input
    if sys.stdin.isatty():
       print( 'Enter text (^D for finishing)' )
    while True:
        l = sys.stdin.readline()
        if l == '': break                             # ^D - завершение ввода (EOF)
        s += l.decode( 'utf-8' )
#print( type( s ), len( s ), s )

if 2 == sys.version_info.major:
    b = bytes( s )
else:
    b = bytes( s, encoding = 'utf-8' )
#print( type( b ), b )
 
def makeQR( data, path, level = 1 ):
    quality= { 1: PyQRNative.QRErrorCorrectLevel.L,
               2: PyQRNative.QRErrorCorrectLevel.M,
               3: PyQRNative.QRErrorCorrectLevel.Q,
               4: PyQRNative.QRErrorCorrectLevel.H }
    size = 3
    while 1:
        try:
            q = PyQRNative.QRCode( size, quality[ level ] )
            q.addData( data )
            q.make()
            im = q.makeImage()
            im.save( path, format = "png" )
            break
        except TypeError:
            size += 1
            if debug: print( 'increase size: {}'.format( size ) )            
    if debug: print( 'size = {}'.format( size ) )
    return im

image = makeQR( b, 'qr1.png', level = 1 )

if args[ "output" ] != None:
    ifile = open( args[ "output" ] + '.jpg', 'wb' )
    image.save( ifile, 'JPEG' )
    ifile.close()
if debug:
    image.show()
Вложения
genqr2.py
(2.25 КБ) 77 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: распознавание bar-кодов

Непрочитанное сообщение Olej » 04 окт 2018, 20:08

Olej писал(а): Вот теперь можем написать приложение, выполняющее обратное декодирование сгенерированных QR:
Теперь можно проверить на адекватность QR, сгенерированных предыдущим генератором (из бинарного файла 21.bin):

Код: Выделить всё

[olej@dell QRgenerator]$ python2 restoreqr.py -i xxx.jpg 
find barcodes in greenscale 1
<type 'str'>
save file: xxx.jpg.01.rest

Код: Выделить всё

[olej@dell QRgenerator]$ cmp 21.bin xxx.jpg.01.rest 

[olej@dell QRgenerator]$ echo $?
0
То, что записывали в QR - то из него и извлекли.

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: распознавание bar-кодов

Непрочитанное сообщение Olej » 05 окт 2018, 20:21

Olej писал(а): 2-й из таких пакетов - PyQRNative, в своё время продвигаемый и популяризируемый Google.
3-й из таких пакетов, наверное, самый известный, работающий как в Python 2, так и в Python 3 - это qrcode.
Но! :

Код: Выделить всё

[olej@dell 09]$ python2
Python 2.7.15 (default, Sep 21 2018, 23:31:20) 
[GCC 7.3.1 20180712 (Red Hat 7.3.1-6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import qrcode
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named qrcode
>>> quit()
Его нет по умолчанию ни в каком дистрибутиве, и нужно устанавливать дополнительно.

Исходный Python-код проекта здесь (это бывает очень полезно разобраться в деталях): https://github.com/lincolnloop/python-qrcode

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: распознавание bar-кодов

Непрочитанное сообщение Olej » 05 окт 2018, 20:34

Olej писал(а): Его нет по умолчанию ни в каком дистрибутиве, и нужно устанавливать дополнительно.
Это можно сделать 2-мя разными способами:
1). используя Python-инсталлятор:

Код: Выделить всё

[olej@dell qrop]$ pip search qrcode | grep ^qrcode
qrcode-song (0.3)                  - A qrcode generator based on cli-qrcode and web crawler.
qrcode-converter (0.1.1.dev0)      - A qrcode generator with inner image
qrcode (6.0)                       - QR Code image generator
qrcode_terminal (0.8)              - Python QRCode Terminal
2). из репозитория дистрибутива:

Код: Выделить всё

[olej@dell 09]$ dnf list '*qrcode*'| grep python
python-qrcode.noarch                 5.1-7.fc27                          fedora
python-qrcode-core.noarch            5.1-7.fc27                          fedora
python3-qrcode.noarch                5.1-7.fc27                          fedora
python3-qrcode-core.noarch           5.1-7.fc27                          fedora
Я выберу 1-й, но только из соображений более поздней версии пакета:

Код: Выделить всё

[olej@dell qrop]$ sudo python2 -m pip install qrcode
[sudo] пароль для olej: 
Collecting qrcode
  Downloading https://files.pythonhosted.org/packages/79/be/11999004f7e6e5db0fa410c2feacd67c07f472f4500fde0026101f31d0df/qrcode-6.0-py2.py3-none-any.whl
Requirement already satisfied: six in /usr/lib/python2.7/site-packages (from qrcode) (1.11.0)
Installing collected packages: qrcode
Successfully installed qrcode-6.0

Код: Выделить всё

[olej@dell qrop]$ sudo python3 -m pip install qrcode
Collecting qrcode
  Using cached https://files.pythonhosted.org/packages/79/be/11999004f7e6e5db0fa410c2feacd67c07f472f4500fde0026101f31d0df/qrcode-6.0-py2.py3-none-any.whl
Requirement already satisfied: six in /usr/lib/python3.6/site-packages (from qrcode) (1.11.0)
Installing collected packages: qrcode
Successfully installed qrcode-6.0
Проверяем:

Код: Выделить всё

[olej@dell 09]$ python
Python 2.7.15 (default, Sep 21 2018, 23:31:20) 
[GCC 7.3.1 20180712 (Red Hat 7.3.1-6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import qrcode
>>> help( qrcode )
...
>>> help( qrcode.QRCode )
...

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: распознавание bar-кодов

Непрочитанное сообщение Olej » 05 окт 2018, 20:58

Olej писал(а): 3-й из таких пакетов, наверное, самый известный, работающий как в Python 2, так и в Python 3 - это qrcode.
Генератор QR кодов, использующий этот вариант:

Код: Выделить всё

# -*- coding: utf-8 -*- 
import sys
import argparse
try:
    import qrcode
except ImportError:
    print( 'module qrcode not installed' )
    sys.exit( 1 )

# QR generator using qrcode: https://github.com/lincolnloop/python-qrcode
ap = argparse.ArgumentParser()                    # construct the argument parse and parse the arguments
ap.add_argument( "-o", "--output", required = False,  help = "path to the output image file" )
ap.add_argument( "-l", "--level",  required=False,    help = "errors correction level" )
ap.add_argument( "-v", nargs='?', const=True, required=False, help = "increased verbose level" )
ap.add_argument( "-s", nargs='?', const=True, required=False, help = "single line" )
args = vars( ap.parse_args() )

debug = args[ "v" ] != None                       # verbose level
if not debug and args[ "output" ] == None:
    print( 'you must use -v or|and -o options' )
    sys.exit( 1 )

#print( sys.stdin.isatty() )
s = ''
if args[ "s" ] != None:
    if sys.stdin.isatty():
        sys.stdout.write( 'get line (Enter for finishing): ' )
        sys.stdout.flush()
    s = sys.stdin.readline()
    if s[ len( s ) - 1 ] == '\n':
        s = s[ :-1 ]
else:
    if sys.stdin.isatty():
       print( 'Enter text (^D for finishing)' )
    while True:
        l = sys.stdin.readline()
        if l == '': break                         # ^D - завершение ввода (EOF)
        s += l
#print( len( s ) )

if 2 == sys.version_info.major: 
    b = bytes( s )
else: 
    b = bytes( s, encoding = 'utf-8' )

print( type( b ), len( b), b )

quality = { 
    1 : qrcode.ERROR_CORRECT_L,
    2 : qrcode.ERROR_CORRECT_M,
    3 : qrcode.ERROR_CORRECT_Q,
    4 : qrcode.ERROR_CORRECT_H
}

level = qrcode.ERROR_CORRECT_M                    # error correction level
if args[ "level" ] != None:
    try:
        ilv = int( args[ "level" ] )
        if quality[ ilv ] != None:
            level = quality[ ilv ] 
    except ValueError:
        None
    except KeyError:
        None

qr = qrcode.QRCode( version = None, error_correction = level, box_size = 10, border = 4 )
qr.add_data( b )

try: qr.make( fit = True )
except qrcode.exceptions.DataOverflowError:
    print( 'exceeding the maximum data size' )
    sys.exit( 1 )

if debug: print( 'QR version: {}'.format( qr.version ) )
image = qr.make_image()
print( type( image ) )
#print( type( image ) )
if args[ "output" ] != None:
    path = args[ "output" ] + '.jpg'
    ifile = open( path, 'wb' )
    image.save( ifile, 'JPEG' )
    ifile.close()
if debug:
    image.show()
Вложения
genqr3.py
(2.73 КБ) 82 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: распознавание bar-кодов

Непрочитанное сообщение Olej » 05 окт 2018, 21:05

Olej писал(а): Генератор QR кодов, использующий этот вариант:
Вот как этот вариант зашивает в QR код бинарные данные (любые другие, ASCII, UTF-8... он зашьёт с ещё большей лёгкостью):

Код: Выделить всё

[olej@dell QRgenerator]$ cat 21.bin | python3 genqr3.py -s -o 21 -v
<class 'bytes'> 21 b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19 !'
QR version: 2
<class 'qrcode.image.pil.PilImage'>
Восстановление:

Код: Выделить всё

[olej@dell QRgenerator]$ python2 restoreqr.py -i 21.jpg
find barcodes in greenscale 1
<type 'str'>
save file: 21.jpg.01.rest

[olej@dell QRgenerator]$ ls 21.*
21.bin  21.jpg  21.jpg.01.rest
Сравнение:

Код: Выделить всё

[olej@dell QRgenerator]$ cmp 21.bin  21.jpg.01.rest

[olej@dell QRgenerator]$ echo $?
0
И вот что в QR зашито:

Код: Выделить всё

[olej@dell QRgenerator]$ hexdump -b 21.jpg.01.rest
0000000 001 002 003 004 005 006 007 010 011 020 021 022 023 024 025 026
0000010 027 030 031 040 041
0000015
Вложения
q3-1.png
q3-1.png (8.93 КБ) 2369 просмотров

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: распознавание bar-кодов

Непрочитанное сообщение Olej » 05 окт 2018, 21:15

Интересно сравнить как по-разному представляют одну и ту же информацию разные генераторы...
Повторю рядом 2 изображения QR кодов, сгенерированные из тестового бинарного файла 21.bin с помощью PyQRNative (слева) и qrcode (справа):
Изображение Изображение
Это наглядная иллюстрация того, что стандарт QR избыточен, имеет слишком много степеней свободы (параметров создания), и разные генераторы создают разные изображения.
P.S. Я предполагаю (!?) что даже если тщательно подобрать эквивалентные параметры 2-х разных генераторов (а они имеют разные наборы параметров и названы по-разному), то изображения будут разные.

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя