Python MRZ 스캐너 SDK를 빌드하고 PyPI에 게시하는 방법
이 문서에서는 Dynamsoft Label Recognizer C++ API를 기반으로 Python MRZ 스캐너 모듈을 빌드하는 단계를 살펴봅니다.
C/C++에서 Python MRZ 스캐너 SDK 구현
다음은 Python MRZ 확장 프로젝트의 구조입니다.
C/C++ MRZ SDK는 Windows 및 Linux용 MRZ 모델, JSON 형식의 모델 구성 파일, 헤더 파일 및 공유 라이브러리(*.dll 및 *.so)로 구성됩니다.
mrzscanner.cpp
는 Python MRZ 스캐너 SDK의 진입점입니다. 두 가지 방법을 정의합니다.initLicense()
: 글로벌 라이센스 키를 초기화합니다. createInstance()
: DynamsoftMrzReader
클래스의 인스턴스를 만듭니다.#include <Python.h>
#include <stdio.h>
#include "dynamsoft_mrz_reader.h"
#define INITERROR return NULL
struct module_state {
PyObject *error;
};
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
static PyObject *
error_out(PyObject *m)
{
struct module_state *st = GETSTATE(m);
PyErr_SetString(st->error, "something bad happened");
return NULL;
}
static PyObject *createInstance(PyObject *obj, PyObject *args)
{
if (PyType_Ready(&DynamsoftMrzReaderType) < 0)
INITERROR;
DynamsoftMrzReader* reader = PyObject_New(DynamsoftMrzReader, &DynamsoftMrzReaderType);
reader->handler = DLR_CreateInstance();
return (PyObject *)reader;
}
static PyObject *initLicense(PyObject *obj, PyObject *args)
{
char *pszLicense;
if (!PyArg_ParseTuple(args, "s", &pszLicense))
{
return NULL;
}
char errorMsgBuffer[512];
// Click https://www.dynamsoft.com/customer/license/trialLicense/?product=dbr to get a trial license.
int ret = DLR_InitLicense(pszLicense, errorMsgBuffer, 512);
printf("DLR_InitLicense: %s\n", errorMsgBuffer);
return Py_BuildValue("i", ret);
}
static PyMethodDef mrzscanner_methods[] = {
{"initLicense", initLicense, METH_VARARGS, "Set license to activate the SDK"},
{"createInstance", createInstance, METH_VARARGS, "Create Dynamsoft MRZ Reader object"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef mrzscanner_module_def = {
PyModuleDef_HEAD_INIT,
"mrzscanner",
"Internal \"mrzscanner\" module",
-1,
mrzscanner_methods
};
PyMODINIT_FUNC PyInit_mrzscanner(void)
{
PyObject *module = PyModule_Create(&mrzscanner_module_def);
if (module == NULL)
INITERROR;
if (PyType_Ready(&DynamsoftMrzReaderType) < 0)
INITERROR;
Py_INCREF(&DynamsoftMrzReaderType);
PyModule_AddObject(module, "DynamsoftMrzReader", (PyObject *)&DynamsoftMrzReaderType);
if (PyType_Ready(&MrzResultType) < 0)
INITERROR;
Py_INCREF(&MrzResultType);
PyModule_AddObject(module, "MrzResult", (PyObject *)&MrzResultType);
PyModule_AddStringConstant(module, "version", DLR_GetVersion());
return module;
}
DynamsoftMrzReader
클래스는 dynamsoft_mrz_reader.h
에 정의되어 있습니다. 세 가지 방법을 정의합니다.decodeFile()
: 이미지 파일에서 MRZ를 인식합니다. decodeMat()
: OpenCV Mat에서 MRZ를 인식합니다. loadModel()
: JSON 형식의 구성 파일을 구문 분석하여 MRZ 모델을 로드합니다.#ifndef __MRZ_READER_H__
#define __MRZ_READER_H__
#include <Python.h>
#include <structmember.h>
#include "DynamsoftLabelRecognizer.h"
#include "mrz_result.h"
#define DEBUG 0
typedef struct
{
PyObject_HEAD
void *handler;
} DynamsoftMrzReader;
static int DynamsoftMrzReader_clear(DynamsoftMrzReader *self)
{
if(self->handler) {
DLR_DestroyInstance(self->handler);
self->handler = NULL;
}
return 0;
}
static void DynamsoftMrzReader_dealloc(DynamsoftMrzReader *self)
{
DynamsoftMrzReader_clear(self);
Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyObject *DynamsoftMrzReader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
DynamsoftMrzReader *self;
self = (DynamsoftMrzReader *)type->tp_alloc(type, 0);
if (self != NULL)
{
self->handler = DLR_CreateInstance();
}
return (PyObject *)self;
}
static PyMethodDef instance_methods[] = {
{"decodeFile", decodeFile, METH_VARARGS, NULL},
{"decodeMat", decodeMat, METH_VARARGS, NULL},
{"loadModel", loadModel, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
static PyTypeObject DynamsoftMrzReaderType = {
PyVarObject_HEAD_INIT(NULL, 0) "mrzscanner.DynamsoftMrzReader", /* tp_name */
sizeof(DynamsoftMrzReader), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)DynamsoftMrzReader_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"DynamsoftMrzReader", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
instance_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
DynamsoftMrzReader_new, /* tp_new */
};
#endif
모델 구성 파일은 다음과 같습니다.
{
"CharacterModelArray" : [
{
"DirectoryPath": "model",
"FilterFilePath": "",
"Name": "MRZ"
}
],
"LabelRecognizerParameterArray" : [
{
"BinarizationModes" : [
{
"BlockSizeX" : 0,
"BlockSizeY" : 0,
"EnableFillBinaryVacancy" : 1,
"LibraryFileName" : "",
"LibraryParameters" : "",
"Mode" : "BM_LOCAL_BLOCK",
"ThreshValueCoefficient" : 15
}
],
"CharacterModelName" : "MRZ",
"LetterHeightRange" : [ 5, 1000, 1 ],
"LineStringLengthRange" : [30, 44],
"MaxLineCharacterSpacing" : 130,
"LineStringRegExPattern" : "([ACI][A-Z<][A-Z<]{3}[A-Z0-9<]{9}[0-9][A-Z0-9<]{15}){(30)}|([0-9]{2}[(01-12)][(01-31)][0-9][MF<][0-9]{2}[(01-12)][(01-31)][0-9][A-Z<]{3}[A-Z0-9<]{11}[0-9]){(30)}|([A-Z<]{0,26}[A-Z]{1,3}[(<<)][A-Z]{1,3}[A-Z<]{0,26}<{0,26}){(30)}|([ACIV][A-Z<][A-Z<]{3}([A-Z<]{0,27}[A-Z]{1,3}[(<<)][A-Z]{1,3}[A-Z<]{0,27}){(31)}){(36)}|([A-Z0-9<]{9}[0-9][A-Z<]{3}[0-9]{2}[(01-12)][(01-31)][0-9][MF<][0-9]{2}[(01-12)][(01-31)][0-9][A-Z0-9<]{8}){(36)}|([PV][A-Z<][A-Z<]{3}([A-Z<]{0,35}[A-Z]{1,3}[(<<)][A-Z]{1,3}[A-Z<]{0,35}<{0,35}){(39)}){(44)}|([A-Z0-9<]{9}[0-9][A-Z<]{3}[0-9]{2}[(01-12)][(01-31)][0-9][MF<][0-9]{2}[(01-12)][(01-31)][0-9][A-Z0-9<]{14}[A-Z0-9<]{2}){(44)}",
"MaxThreadCount" : 4,
"Name" : "locr",
"TextureDetectionModes" :[
{
"Mode" : "TDM_GENERAL_WIDTH_CONCENTRATION",
"Sensitivity" : 8
}
],
"ReferenceRegionNameArray" : [ "DRRegion" ]
}
],
"LineSpecificationArray" : [
{
"Name":"L0",
"LineNumber":"",
"BinarizationModes" : [
{
"BlockSizeX" : 30,
"BlockSizeY" : 30,
"Mode" : "BM_LOCAL_BLOCK"
}
]
}
],
"ReferenceRegionArray" : [
{
"Localization" : {
"FirstPoint" : [ 0, 0 ],
"SecondPoint" : [ 100, 0 ],
"ThirdPoint" : [ 100, 100 ],
"FourthPoint" : [ 0, 100 ],
"MeasuredByPercentage" : 1,
"SourceType" : "LST_MANUAL_SPECIFICATION"
},
"Name" : "DRRegion",
"TextAreaNameArray" : [ "DTArea" ]
}
],
"TextAreaArray" : [
{
"LineSpecificationNameArray" : ["L0"],
"Name" : "DTArea",
"FirstPoint" : [ 0, 0 ],
"SecondPoint" : [ 100, 0 ],
"ThirdPoint" : [ 100, 100 ],
"FourthPoint" : [ 0, 100 ]
}
]
}
DirectoryPath
를 제외하고는 기본 매개변수를 변경할 필요가 없습니다. 이 매개변수는 실행 디렉토리에 대한 상대 경로이거나 모델 파일이 있는 디렉토리에 대한 절대 경로일 수 있습니다. Python에서 모델 파일을 성공적으로 로드하려면 MRZ.json
에 모델 파일의 절대 경로를 설정해야 합니다. Python 환경에 따라 달라지는 Pythonsite-packages
폴더에 MRZ 스캐너 SDK가 설치되어야 모델 경로가 확정됩니다. 따라서 MRZ.json
에서 구현된 get_model_path()
함수를 호출할 때 __init__.py
에서 모델 파일의 절대 경로를 확인하고 동적으로 수정합니다.def get_model_path():
config_file = os.path.join(os.path.dirname(__file__), 'MRZ.json')
try:
# open json file
with open(config_file, 'r+') as f:
data = json.load(f)
if data['CharacterModelArray'][0]['DirectoryPath'] == 'model':
data['CharacterModelArray'][0]['DirectoryPath'] = os.path.join(os.path.dirname(__file__), 'model')
# print(data['CharacterModelArray'][0]['DirectoryPath'])
# write json file
f.seek(0) # rewind
f.write(json.dumps(data))
except Exception as e:
print(e)
pass
return config_file
mrz_result.h
파일에는 MRZ 인식 결과의 구조가 포함되어 있습니다.typedef struct
{
PyObject_HEAD
PyObject *confidence;
PyObject *text;
PyObject *x1;
PyObject *y1;
PyObject *x2;
PyObject *y2;
PyObject *x3;
PyObject *y3;
PyObject *x4;
PyObject *y4;
} MrzResult;
Python에서 MRZ 인식을 수행하려면:
라이센스 키를 설정하십시오.
mrzscanner.initLicense("your license key")
MRZ 스캐너 개체를 만듭니다.
scanner = mrzscanner.createInstance()
MRZ 인식 모델을 로드합니다.
scanner.loadModel(mrzscanner.get_model_path())
MRZ를 알아보려면
decodeFile()
또는 decodeMat()
로 전화하세요.results = scanner.decodeFile()
# or
results = scanner.decodeMat()
텍스트 결과를 출력합니다.
for result in results:
print(result.text)
Python C 확장 빌드 및 패키징을 위한 Setup.py 파일 구성
다음 코드는 Windows 및 Linux용 공유 라이브러리를 사용하여 Python C 확장을 빌드하는 방법을 보여줍니다.
dbr_lib_dir = ''
dbr_include = ''
dbr_lib_name = 'DynamsoftLabelRecognizer'
if sys.platform == "linux" or sys.platform == "linux2":
# Linux
dbr_lib_dir = 'lib/linux'
elif sys.platform == "win32":
# Windows
dbr_lib_name = 'DynamsoftLabelRecognizerx64'
dbr_lib_dir = 'lib/win'
if sys.platform == "linux" or sys.platform == "linux2":
ext_args = dict(
library_dirs=[dbr_lib_dir],
extra_compile_args=['-std=c++11'],
extra_link_args=["-Wl,-rpath=$ORIGIN"],
libraries=[dbr_lib_name],
include_dirs=['include']
)
long_description = io.open("README.md", encoding="utf-8").read()
if sys.platform == "linux" or sys.platform == "linux2" or sys.platform == "darwin":
module_mrzscanner = Extension(
'mrzscanner', ['src/mrzscanner.cpp'], **ext_args)
else:
module_mrzscanner = Extension('mrzscanner',
sources=['src/mrzscanner.cpp'],
include_dirs=['include'], library_dirs=[dbr_lib_dir], libraries=[dbr_lib_name])
Python 확장을 빌드한 후 한 가지 더 중요한 단계는 Python MRZ 스캐너 모듈을 패키징하기 전에 모델 파일과 모든 종속 공유 라이브러리를 출력 디렉터리에 복사하는 것입니다.
def copyfiles(src, dst):
if os.path.isdir(src):
filelist = os.listdir(src)
for file in filelist:
libpath = os.path.join(src, file)
shutil.copy2(libpath, dst)
else:
shutil.copy2(src, dst)
class CustomBuildExt(build_ext.build_ext):
def run(self):
build_ext.build_ext.run(self)
dst = os.path.join(self.build_lib, "mrzscanner")
copyfiles(dbr_lib_dir, dst)
filelist = os.listdir(self.build_lib)
for file in filelist:
filePath = os.path.join(self.build_lib, file)
if not os.path.isdir(file):
copyfiles(filePath, dst)
# delete file for wheel package
os.remove(filePath)
model_dest = os.path.join(dst, 'model')
if (not os.path.exists(model_dest)):
os.mkdir(model_dest)
copyfiles(os.path.join(os.path.join(
Path(__file__).parent, 'model')), model_dest)
shutil.copy2('MRZ.json', dst)
setup(name='mrz-scanner-sdk',
...
cmdclass={
'build_ext': CustomBuildExt},
)
패키지를 로컬로 빌드하고 설치하려면:
python setup.py build install
소스 배포를 빌드하려면:
python setup.py sdist
휠 배포를 빌드하려면 다음을 수행하십시오.
pip wheel . --verbose
# Or
python setup.py bdist_wheel
Python MRZ 스캐너 SDK 테스트
mrz 및 opencv-python을 설치합니다.
pip install mrz opencv-python
- `mrz` is used to extract and check MRZ information from recognized text.
- `opencv-python` is used to display the image.
이미지 파일에서 MRZ 텍스트를 인식하는
app.py
파일을 생성합니다.import argparse
import mrzscanner
import cv2
import sys
import numpy as np
from mrz.checker.td1 import TD1CodeChecker
from mrz.checker.td2 import TD2CodeChecker
from mrz.checker.td3 import TD3CodeChecker
from mrz.checker.mrva import MRVACodeChecker
from mrz.checker.mrvb import MRVBCodeChecker
def check(lines):
try:
td1_check = TD1CodeChecker(lines)
if bool(td1_check):
return "TD1", td1_check.fields()
except Exception as err:
pass
try:
td2_check = TD2CodeChecker(lines)
if bool(td2_check):
return "TD2", td2_check.fields()
except Exception as err:
pass
try:
td3_check = TD3CodeChecker(lines)
if bool(td3_check):
return "TD3", td3_check.fields()
except Exception as err:
pass
try:
mrva_check = MRVACodeChecker(lines)
if bool(mrva_check):
return "MRVA", mrva_check.fields()
except Exception as err:
pass
try:
mrvb_check = MRVBCodeChecker(lines)
if bool(mrvb_check):
return "MRVB", mrvb_check.fields()
except Exception as err:
pass
return 'No valid MRZ information found'
def scanmrz():
"""
Command-line script for recognize MRZ info from a given image
"""
parser = argparse.ArgumentParser(description='Scan MRZ info from a given image')
parser.add_argument('filename')
args = parser.parse_args()
try:
filename = args.filename
ui = args.ui
# Get the license key from https://www.dynamsoft.com/customer/license/trialLicense/?product=dlr
mrzscanner.initLicense("DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==")
scanner = mrzscanner.createInstance()
scanner.loadModel(mrzscanner.get_model_path())
results = scanner.decodeFile(filename)
for result in results:
print(result.text)
s += result.text + '\n'
print(check(s[:-1]))
except Exception as err:
print(err)
sys.exit(1)
if __name__ == "__main__":
scanmrz()
명령줄 MRZ 스캐닝 응용 프로그램을 실행합니다.
python app.py
GitHub 워크플로 구성
다음과 같이 새 GitHub 작업 워크플로를 만듭니다.
name: Build and upload to PyPI
on: [push, pull_request]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Run test.py in develop mode
run: |
python setup.py develop
python -m pip install opencv-python mrz
python --version
python test.py
- name: Build wheels for Linux
if: matrix.os == 'ubuntu-latest'
run: |
pip install -U wheel setuptools auditwheel patchelf
python setup.py bdist_wheel
auditwheel repair dist/mrz_scanner_sdk*.whl --plat manylinux2014_$(uname -m)
- name: Build wheels for Windows
if: matrix.os == 'windows-latest'
run: |
pip install -U wheel setuptools
python setup.py bdist_wheel -d wheelhouse
- uses: actions/upload-artifact@v2
with:
path: wheelhouse/*.whl
build_sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build sdist
run: python setup.py sdist -d dist
- uses: actions/upload-artifact@v2
with:
path: dist/*.tar.gz
upload_pypi:
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/download-artifact@v2
with:
name: artifact
path: dist
- uses: pypa/[email protected]
with:
user: __token__
password: ${{ secrets.pypi_password }}
skip_existing: true
워크플로우는 소스 및 휠 배포를 빌드하고 PyPI에 업로드하도록 구성됩니다.
PyPI에서 mrz-scanner-sdk 설치
https://pypi.org/project/mrz-scanner-sdk/
pip install mrz-scanner-sdk
소스 코드
https://github.com/yushulx/python-mrz-scanner-sdk
Reference
이 문제에 관하여(Python MRZ 스캐너 SDK를 빌드하고 PyPI에 게시하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/yushulx/how-to-build-python-mrz-scanner-sdk-and-publish-it-to-pypi-4nil텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)