使用Python构建护照扫描仪,支持人像识别、MRZ 编码
·
如何使用 Python 构建护照扫描仪,支持人像识别、MRZ 编码和文档检测
在本教程中,您将学习如何构建一个专业的桌面应用程序,用于读取护照和身份证上的机读区 (MRZ),并具备人像和文档识别功能。完成本指南后,您将拥有一个使用 PySide6 构建、并由 Dynamsoft Capture Vision SDK 提供支持的全功能 GUI 应用程序。
演示视频:具备人脸、磁条识别和文件检测功能的护照扫描仪
你将建造什么
一款跨平台桌面护照扫描仪,功能包括:
- 从护照和身份证件(TD1、TD2、TD3格式)中实时识别MRZ
- 旅行证件上的人脸/肖像检测和定位
- 多种输入方式:图像文件、文件夹、摄像头视频流、拖放、剪贴板粘贴
- 视觉叠加层显示文档边界、MRZ 位置和检测到的肖像
- 解析后的数据展示,并结构化提取个人信息
- 导出标准化文档图像的功能
为什么选择 Dynamsoft Capture Vision SDK?
Dynamsoft Capture Vision SDK 为文档处理提供了一套全面的解决方案,具有以下主要优势:
- 一体化文档处理:将文档检测、MRZ识别和人像提取集成于单个SDK中
- 高精度:先进的OCR引擎针对机器可读区域进行了优化
- 中间结果访问:对处理流程的精细控制
- 跨平台支持:兼容 Windows、Linux 和 macOS
- 生产就绪:深受企业信赖的身份验证系统
先决条件
开始之前,请确保您已准备好:
- 已安装 Python 3.9 或更高版本
- 网络摄像头(可选,用于摄像头拍摄功能)
- 用于测试的护照或身份证样本图像
获取试用许可证
Dynamsoft 提供免费试用许可证供评估:
- 访问Dynamsoft 许可证门户
- 选择“Capture Vision Suite (DCV)”作为产品
- 完成注册即可获得您的许可证密钥
- 试用许可证有效期为 30 天,可访问所有功能。
第一步:项目设置和依赖项
创建项目目录并安装所需的软件包:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code><span style="color:#336666">mkdir </span>mrz_scanner_gui
<span style="color:#336666">cd </span>mrz_scanner_gui
python <span style="color:#330099"><strong>-m</strong></span> venv venv
<span style="color:#336666">source </span>venv/bin/activate <span style="color:#0099ff"><em># On Windows: venv\Scripts\activate</em></span>
</code></span></span></span>
安装依赖项:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code>pip <span style="color:#336666">install </span>dynamsoft-capture-vision-bundle opencv-python PySide6
</code></span></span></span>
创建requirements.txt依赖管理文件:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code>dynamsoft-capture-vision-bundle
PySide6
opencv-python
</code></span></span></span>
步骤 2:了解 SDK 架构
Dynamsoft Capture Vision SDK 采用基于流水线的架构:
- CaptureVisionRouter:协调图像处理工作流程
- IntermediateResultManager:提供对中间处理阶段的访问
- IntermediateResultReceiver:用于捕获中间结果(例如倾斜校正后的图像和检测到的文本行)的回调接口
- 身份处理器:专门用于身份证明文件上人像区域检测的处理器
步骤三:创建数据模型
首先,定义用于存储 MRZ 结果的数据结构:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code><span style="color:#006699"><strong>from</strong></span> dataclasses <span style="color:#006699"><strong>import</strong></span> dataclass
<span style="color:#006699"><strong>from</strong></span> typing <span style="color:#006699"><strong>import</strong></span> List, Optional
<span style="color:#9999ff">@dataclass</span>
<span style="color:#006699"><strong>class</strong></span> <span style="color:#00aa88"><strong>MRZResult</strong></span>:
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Stores parsed MRZ result data.</span><span style="color:#cc3300">"""</span>
raw_lines: List[<span style="color:#336666">str</span>]
doc_type: <span style="color:#336666">str</span>
doc_id: <span style="color:#336666">str</span>
surname: <span style="color:#336666">str</span>
given_name: <span style="color:#336666">str</span>
nationality: <span style="color:#336666">str</span>
issuer: <span style="color:#336666">str</span>
gender: <span style="color:#336666">str</span>
date_of_birth: <span style="color:#336666">str</span>
date_of_expiry: <span style="color:#336666">str</span>
is_passport: <span style="color:#336666">bool</span>
mrz_locations: List[<span style="color:#cc3300">'</span><span style="color:#cc3300">Quadrilateral</span><span style="color:#cc3300">'</span>]
portrait_zone: Optional[<span style="color:#cc3300">'</span><span style="color:#cc3300">Quadrilateral</span><span style="color:#cc3300">'</span>] <span style="color:#555555">=</span> <span style="color:#336666">None</span>
</code></span></span></span>
该数据类捕获 MRZ 中的所有基本信息:原始文本行、解析的个人数据、文档位置和人像区域坐标。
步骤 4:实现人像检测及其中间结果
人像检测需要访问中间处理结果。创建一个接收器类:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code><span style="color:#006699"><strong>from</strong></span> dynamsoft_capture_vision_bundle <span style="color:#006699"><strong>import</strong></span> <span style="color:#555555">*</span>
<span style="color:#006699"><strong>class</strong></span> <span style="color:#00aa88"><strong>NeededResultUnit</strong></span>:
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Container for intermediate results needed for portrait extraction.</span><span style="color:#cc3300">"""</span>
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">__init__</span>(self):
self.deskewed_image_unit <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.localized_text_lines_unit <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.scaled_colour_img_unit <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.detected_quads_unit <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.recognized_text_lines_unit <span style="color:#555555">=</span> <span style="color:#336666">None</span>
<span style="color:#006699"><strong>class</strong></span> <span style="color:#00aa88"><strong>MyIntermediateResultReceiver</strong></span>(IntermediateResultReceiver):
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Captures intermediate processing stages for portrait detection.</span><span style="color:#cc3300">"""</span>
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">__init__</span>(self, cvr: CaptureVisionRouter):
<span style="color:#cc00ff">super</span>().<span style="color:#cc00ff">__init__</span>()
self.cvr <span style="color:#555555">=</span> cvr
self.unit_groups: Dict[<span style="color:#336666">str</span>, NeededResultUnit] <span style="color:#555555">=</span> {}
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">on_deskewed_image_received</span>(self, result, info):
<span style="color:#006699"><strong>if</strong></span> info.is_section_level_result:
<span style="color:#336666">id</span> <span style="color:#555555">=</span> result.<span style="color:#cc00ff">get_original_image_hash_id</span>()
<span style="color:#006699"><strong>if</strong></span> self.unit_groups.<span style="color:#cc00ff">get</span>(<span style="color:#336666">id</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
self.unit_groups[<span style="color:#336666">id</span>] <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>NeededResultUnit</strong></span>()
self.unit_groups[<span style="color:#336666">id</span>].deskewed_image_unit <span style="color:#555555">=</span> result
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">on_scaled_colour_image_unit_received</span>(self, result, info):
<span style="color:#336666">id</span> <span style="color:#555555">=</span> result.<span style="color:#cc00ff">get_original_image_hash_id</span>()
<span style="color:#006699"><strong>if</strong></span> self.unit_groups.<span style="color:#cc00ff">get</span>(<span style="color:#336666">id</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
self.unit_groups[<span style="color:#336666">id</span>] <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>NeededResultUnit</strong></span>()
self.unit_groups[<span style="color:#336666">id</span>].scaled_colour_img_unit <span style="color:#555555">=</span> result
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">on_localized_text_lines_received</span>(self, result, info):
<span style="color:#006699"><strong>if</strong></span> info.is_section_level_result:
<span style="color:#336666">id</span> <span style="color:#555555">=</span> result.<span style="color:#cc00ff">get_original_image_hash_id</span>()
<span style="color:#006699"><strong>if</strong></span> self.unit_groups.<span style="color:#cc00ff">get</span>(<span style="color:#336666">id</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
self.unit_groups[<span style="color:#336666">id</span>] <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>NeededResultUnit</strong></span>()
self.unit_groups[<span style="color:#336666">id</span>].localized_text_lines_unit <span style="color:#555555">=</span> result
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">on_recognized_text_lines_received</span>(self, result, info):
<span style="color:#006699"><strong>if</strong></span> info.is_section_level_result:
<span style="color:#336666">id</span> <span style="color:#555555">=</span> result.<span style="color:#cc00ff">get_original_image_hash_id</span>()
<span style="color:#006699"><strong>if</strong></span> self.unit_groups.<span style="color:#cc00ff">get</span>(<span style="color:#336666">id</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
self.unit_groups[<span style="color:#336666">id</span>] <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>NeededResultUnit</strong></span>()
self.unit_groups[<span style="color:#336666">id</span>].recognized_text_lines_unit <span style="color:#555555">=</span> result
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">on_detected_quads_received</span>(self, result, info):
<span style="color:#006699"><strong>if</strong></span> info.is_section_level_result:
<span style="color:#336666">id</span> <span style="color:#555555">=</span> result.<span style="color:#cc00ff">get_original_image_hash_id</span>()
<span style="color:#006699"><strong>if</strong></span> self.unit_groups.<span style="color:#cc00ff">get</span>(<span style="color:#336666">id</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
self.unit_groups[<span style="color:#336666">id</span>] <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>NeededResultUnit</strong></span>()
self.unit_groups[<span style="color:#336666">id</span>].detected_quads_unit <span style="color:#555555">=</span> result
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">get_portrait_zone</span>(self, hash_id: <span style="color:#336666">str</span>) <span style="color:#555555">-></span> Optional[<span style="color:#cc3300">'</span><span style="color:#cc3300">Quadrilateral</span><span style="color:#cc3300">'</span>]:
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Extract portrait zone using IdentityProcessor.</span><span style="color:#cc3300">"""</span>
<span style="color:#006699"><strong>if</strong></span> self.unit_groups.<span style="color:#cc00ff">get</span>(hash_id) <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
<span style="color:#006699"><strong>return</strong></span> <span style="color:#336666">None</span>
id_processor <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>IdentityProcessor</strong></span>()
units <span style="color:#555555">=</span> self.unit_groups[hash_id]
ret, portrait_zone <span style="color:#555555">=</span> id_processor.<span style="color:#cc00ff">find_portrait_zone</span>(
units.scaled_colour_img_unit,
units.localized_text_lines_unit,
units.recognized_text_lines_unit,
units.detected_quads_unit,
units.deskewed_image_unit
)
<span style="color:#006699"><strong>if</strong></span> ret <span style="color:#555555">!=</span> EnumErrorCode.EC_OK:
<span style="color:#006699"><strong>return</strong></span> <span style="color:#336666">None</span>
<span style="color:#006699"><strong>return</strong></span> portrait_zone
</code></span></span></span>
该IdentityProcessor.find_portrait_zone()方法通过分析 MRZ 文本行和文档边界之间的空间关系来智能地定位人像区域——这是 Dynamsoft SDK 独有的强大功能。
步骤 5:解析 MRZ 结果
创建一个处理器,将 SDK 结果转换为您的数据模型:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code><span style="color:#006699"><strong>class</strong></span> <span style="color:#00aa88"><strong>DCPResultProcessor</strong></span>:
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Converts ParsedResultItem into structured MRZ data.</span><span style="color:#cc3300">"""</span>
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">__init__</span>(self, item: ParsedResultItem):
self.doc_type <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_code_type</span>()
self.raw_text <span style="color:#555555">=</span> []
self.doc_id <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.surname <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.given_name <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.nationality <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.issuer <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.gender <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.date_of_birth <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.date_of_expiry <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.is_passport <span style="color:#555555">=</span> <span style="color:#336666">False</span>
<span style="color:#0099ff"><em># Handle passport-specific fields
</em></span> <span style="color:#006699"><strong>if</strong></span> self.doc_type <span style="color:#555555">==</span> <span style="color:#cc3300">"</span><span style="color:#cc3300">MRTD_TD3_PASSPORT</span><span style="color:#cc3300">"</span>:
<span style="color:#006699"><strong>if</strong></span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">passportNumber</span><span style="color:#cc3300">"</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
self.doc_id <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">passportNumber</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>elif</strong></span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">documentNumber</span><span style="color:#cc3300">"</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
self.doc_id <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">documentNumber</span><span style="color:#cc3300">"</span>)
self.is_passport <span style="color:#555555">=</span> <span style="color:#336666">True</span>
<span style="color:#0099ff"><em># Extract raw MRZ lines
</em></span> <span style="color:#006699"><strong>for</strong></span> i <span style="color:#000000"><strong>in</strong></span> <span style="color:#cc00ff">range</span>(<span style="color:#ff6600">1</span>, <span style="color:#ff6600">4</span>):
line <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(f<span style="color:#cc3300">"</span><span style="color:#cc3300">line</span><span style="color:#aa0000">{</span>i<span style="color:#aa0000">}</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>if</strong></span> line <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
<span style="color:#006699"><strong>if</strong></span> item.<span style="color:#cc00ff">get_field_validation_status</span>(f<span style="color:#cc3300">"</span><span style="color:#cc3300">line</span><span style="color:#aa0000">{</span>i<span style="color:#aa0000">}</span><span style="color:#cc3300">"</span>) <span style="color:#555555">==</span> EnumValidationStatus.VS_FAILED:
line <span style="color:#555555">+=</span> <span style="color:#cc3300">"</span><span style="color:#cc3300"> [Validation Failed]</span><span style="color:#cc3300">"</span>
self.raw_text.<span style="color:#cc00ff">append</span>(line)
<span style="color:#0099ff"><em># Extract structured fields with validation checks
</em></span> <span style="color:#006699"><strong>if</strong></span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">nationality</span><span style="color:#cc3300">"</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
self.nationality <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">nationality</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>if</strong></span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">issuingState</span><span style="color:#cc3300">"</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
self.issuer <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">issuingState</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>if</strong></span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">dateOfBirth</span><span style="color:#cc3300">"</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
self.date_of_birth <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">dateOfBirth</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>if</strong></span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">dateOfExpiry</span><span style="color:#cc3300">"</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
self.date_of_expiry <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">dateOfExpiry</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>if</strong></span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">sex</span><span style="color:#cc3300">"</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
self.gender <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">sex</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>if</strong></span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">primaryIdentifier</span><span style="color:#cc3300">"</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
self.surname <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">primaryIdentifier</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>if</strong></span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">secondaryIdentifier</span><span style="color:#cc3300">"</span>) <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
self.given_name <span style="color:#555555">=</span> item.<span style="color:#cc00ff">get_field_value</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">secondaryIdentifier</span><span style="color:#cc3300">"</span>)
</code></span></span></span>
步骤 6:使用 PySide6 构建 GUI
创建采用双面板布局的主应用程序窗口:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code><span style="color:#006699"><strong>from</strong></span> PySide6.QtWidgets <span style="color:#006699"><strong>import</strong></span> (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QPushButton, QLabel, QFileDialog, QTextEdit, QSplitter,
QComboBox, QGroupBox, QListWidget, QMessageBox
)
<span style="color:#006699"><strong>from</strong></span> PySide6.QtCore <span style="color:#006699"><strong>import</strong></span> Qt, QThread, Signal
<span style="color:#006699"><strong>from</strong></span> PySide6.QtGui <span style="color:#006699"><strong>import</strong></span> QImage, QPixmap, QPainter, QPen, QColor, QFont
<span style="color:#006699"><strong>class</strong></span> <span style="color:#00aa88"><strong>MRZScannerWindow</strong></span>(QMainWindow):
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Main application window for MRZ scanning.</span><span style="color:#cc3300">"""</span>
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">__init__</span>(self):
<span style="color:#cc00ff">super</span>().<span style="color:#cc00ff">__init__</span>()
self.<span style="color:#cc00ff">setWindowTitle</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">MRZ Scanner - Dynamsoft Capture Vision</span><span style="color:#cc3300">"</span>)
self.<span style="color:#cc00ff">setMinimumSize</span>(<span style="color:#ff6600">1200</span>, <span style="color:#ff6600">800</span>)
<span style="color:#0099ff"><em># Initialize SDK components
</em></span> self.<span style="color:#cc00ff">_init_sdk</span>()
<span style="color:#0099ff"><em># Setup UI
</em></span> self.<span style="color:#cc00ff">_setup_ui</span>()
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">_init_sdk</span>(self):
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Initialize Dynamsoft Capture Vision SDK.</span><span style="color:#cc3300">"""</span>
<span style="color:#0099ff"><em># Initialize license - replace with your license key
</em></span> error_code, error_message <span style="color:#555555">=</span> LicenseManager.<span style="color:#cc00ff">init_license</span>(
<span style="color:#cc3300">"</span><span style="color:#cc3300">YOUR_LICENSE_KEY_HERE</span><span style="color:#cc3300">"</span>
)
<span style="color:#006699"><strong>if</strong></span> error_code <span style="color:#555555">!=</span> EnumErrorCode.EC_OK <span style="color:#000000"><strong>and</strong></span> error_code <span style="color:#555555">!=</span> EnumErrorCode.EC_LICENSE_WARNING:
QMessageBox.<span style="color:#cc00ff">warning</span>(
<span style="color:#336666">None</span>,
<span style="color:#cc3300">"</span><span style="color:#cc3300">License Error</span><span style="color:#cc3300">"</span>,
f<span style="color:#cc3300">"</span><span style="color:#cc3300">License initialization failed: </span><span style="color:#aa0000">{</span>error_message<span style="color:#aa0000">}</span><span style="color:#cc3300">"</span>
)
<span style="color:#0099ff"><em># Create router and intermediate result manager
</em></span> self.cvr <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>CaptureVisionRouter</strong></span>()
self.irm <span style="color:#555555">=</span> self.cvr.<span style="color:#cc00ff">get_intermediate_result_manager</span>()
<span style="color:#0099ff"><em># Create and register intermediate result receiver
</em></span> self.irr <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>MyIntermediateResultReceiver</strong></span>(self.cvr)
self.irm.<span style="color:#cc00ff">add_result_receiver</span>(self.irr)
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">_setup_ui</span>(self):
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Setup the user interface.</span><span style="color:#cc3300">"""</span>
central_widget <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QWidget</strong></span>()
self.<span style="color:#cc00ff">setCentralWidget</span>(central_widget)
main_layout <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QHBoxLayout</strong></span>(central_widget)
<span style="color:#0099ff"><em># Create splitter for resizable panels
</em></span> splitter <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QSplitter</strong></span>(Qt.Horizontal)
main_layout.<span style="color:#cc00ff">addWidget</span>(splitter)
<span style="color:#0099ff"><em># Left panel - Image display and controls
</em></span> left_panel <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QWidget</strong></span>()
left_layout <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QVBoxLayout</strong></span>(left_panel)
<span style="color:#0099ff"><em># Input controls
</em></span> input_group <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QGroupBox</strong></span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Input Source</span><span style="color:#cc3300">"</span>)
input_layout <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QVBoxLayout</strong></span>(input_group)
self.source_combo <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QComboBox</strong></span>()
self.source_combo.<span style="color:#cc00ff">addItems</span>([<span style="color:#cc3300">"</span><span style="color:#cc3300">Image File</span><span style="color:#cc3300">"</span>, <span style="color:#cc3300">"</span><span style="color:#cc3300">Image Folder</span><span style="color:#cc3300">"</span>, <span style="color:#cc3300">"</span><span style="color:#cc3300">Camera</span><span style="color:#cc3300">"</span>])
input_layout.<span style="color:#cc00ff">addWidget</span>(self.source_combo)
button_layout <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QHBoxLayout</strong></span>()
self.load_btn <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QPushButton</strong></span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Load File/Folder</span><span style="color:#cc3300">"</span>)
self.paste_btn <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QPushButton</strong></span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Paste from Clipboard</span><span style="color:#cc3300">"</span>)
self.export_btn <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QPushButton</strong></span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Export Passport</span><span style="color:#cc3300">"</span>)
button_layout.<span style="color:#cc00ff">addWidget</span>(self.load_btn)
button_layout.<span style="color:#cc00ff">addWidget</span>(self.paste_btn)
button_layout.<span style="color:#cc00ff">addWidget</span>(self.export_btn)
input_layout.<span style="color:#cc00ff">addLayout</span>(button_layout)
left_layout.<span style="color:#cc00ff">addWidget</span>(input_group)
<span style="color:#0099ff"><em># Image display with overlay support
</em></span> display_group <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QGroupBox</strong></span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Image / Camera View</span><span style="color:#cc3300">"</span>)
display_layout <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QVBoxLayout</strong></span>(display_group)
self.image_display <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>ImageDisplayWidget</strong></span>()
display_layout.<span style="color:#cc00ff">addWidget</span>(self.image_display)
left_layout.<span style="color:#cc00ff">addWidget</span>(display_group, <span style="color:#ff6600">1</span>)
<span style="color:#0099ff"><em># Right panel - Results display
</em></span> right_panel <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QWidget</strong></span>()
right_layout <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QVBoxLayout</strong></span>(right_panel)
<span style="color:#0099ff"><em># Raw MRZ text
</em></span> raw_group <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QGroupBox</strong></span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">MRZ Raw Text</span><span style="color:#cc3300">"</span>)
raw_layout <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QVBoxLayout</strong></span>(raw_group)
self.raw_text_edit <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QTextEdit</strong></span>()
self.raw_text_edit.<span style="color:#cc00ff">setReadOnly</span>(<span style="color:#336666">True</span>)
self.raw_text_edit.<span style="color:#cc00ff">setFont</span>(<span style="color:#00aa88"><strong>QFont</strong></span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Courier New</span><span style="color:#cc3300">"</span>, <span style="color:#ff6600">10</span>))
raw_layout.<span style="color:#cc00ff">addWidget</span>(self.raw_text_edit)
right_layout.<span style="color:#cc00ff">addWidget</span>(raw_group)
<span style="color:#0099ff"><em># Parsed results
</em></span> parsed_group <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QGroupBox</strong></span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Parsed Results</span><span style="color:#cc3300">"</span>)
parsed_layout <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QVBoxLayout</strong></span>(parsed_group)
self.parsed_text_edit <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QTextEdit</strong></span>()
self.parsed_text_edit.<span style="color:#cc00ff">setReadOnly</span>(<span style="color:#336666">True</span>)
parsed_layout.<span style="color:#cc00ff">addWidget</span>(self.parsed_text_edit)
right_layout.<span style="color:#cc00ff">addWidget</span>(parsed_group, <span style="color:#ff6600">1</span>)
<span style="color:#0099ff"><em># Add panels to splitter
</em></span> splitter.<span style="color:#cc00ff">addWidget</span>(left_panel)
splitter.<span style="color:#cc00ff">addWidget</span>(right_panel)
splitter.<span style="color:#cc00ff">setSizes</span>([<span style="color:#ff6600">800</span>, <span style="color:#ff6600">400</span>])
</code></span></span></span>
步骤 7:处理图像
实现核心图像处理逻辑:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code><span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">_process_image_file</span>(self, file_path: <span style="color:#336666">str</span>):
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Process a single image file.</span><span style="color:#cc3300">"""</span>
<span style="color:#006699"><strong>try</strong></span>:
<span style="color:#0099ff"><em># Read image for display
</em></span> image <span style="color:#555555">=</span> cv2.<span style="color:#cc00ff">imread</span>(file_path)
<span style="color:#006699"><strong>if</strong></span> image <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
self.<span style="color:#cc00ff">statusBar</span>().<span style="color:#cc00ff">showMessage</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Failed to load image</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>return</strong></span>
<span style="color:#0099ff"><em># Process with SDK using "ReadPassportAndId" template
</em></span> result <span style="color:#555555">=</span> self.cvr.<span style="color:#cc00ff">capture</span>(file_path, <span style="color:#cc3300">"</span><span style="color:#cc3300">ReadPassportAndId</span><span style="color:#cc3300">"</span>)
self.current_captured_result <span style="color:#555555">=</span> result
<span style="color:#006699"><strong>if</strong></span> result <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
self.image_display.<span style="color:#cc00ff">set_image</span>(image, [])
self.<span style="color:#cc00ff">_update_results_display</span>([])
<span style="color:#006699"><strong>return</strong></span>
<span style="color:#0099ff"><em># Extract MRZ results with portrait zones
</em></span> mrz_results <span style="color:#555555">=</span> self.<span style="color:#cc00ff">_extract_mrz_results</span>(result)
doc_quad <span style="color:#555555">=</span> self.<span style="color:#cc00ff">_get_document_quad</span>(result)
<span style="color:#0099ff"><em># Update display
</em></span> self.image_display.<span style="color:#cc00ff">set_image</span>(image, mrz_results, doc_quad)
self.<span style="color:#cc00ff">_update_results_display</span>(mrz_results)
<span style="color:#006699"><strong>except</strong></span> <span style="color:#336666">Exception</span> <span style="color:#006699"><strong>as</strong></span> e:
self.<span style="color:#cc00ff">statusBar</span>().<span style="color:#cc00ff">showMessage</span>(f<span style="color:#cc3300">"</span><span style="color:#cc3300">Error: </span><span style="color:#aa0000">{</span><span style="color:#cc00ff">str</span>(e)<span style="color:#aa0000">}</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">_extract_mrz_results</span>(self, result: CapturedResult) <span style="color:#555555">-></span> List[MRZResult]:
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Extract MRZ results from CapturedResult.</span><span style="color:#cc3300">"""</span>
mrz_results <span style="color:#555555">=</span> []
parsed_result <span style="color:#555555">=</span> result.<span style="color:#cc00ff">get_parsed_result</span>()
<span style="color:#006699"><strong>if</strong></span> parsed_result <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
<span style="color:#006699"><strong>return</strong></span> mrz_results
<span style="color:#0099ff"><em># Get MRZ text line locations
</em></span> mrz_locations <span style="color:#555555">=</span> []
line_result <span style="color:#555555">=</span> result.<span style="color:#cc00ff">get_recognized_text_lines_result</span>()
<span style="color:#006699"><strong>if</strong></span> line_result <span style="color:#000000"><strong>is</strong></span> <span style="color:#000000"><strong>not</strong></span> <span style="color:#336666">None</span>:
<span style="color:#006699"><strong>for</strong></span> item <span style="color:#000000"><strong>in</strong></span> line_result.<span style="color:#cc00ff">get_items</span>():
mrz_locations.<span style="color:#cc00ff">append</span>(item.<span style="color:#cc00ff">get_location</span>())
hash_id <span style="color:#555555">=</span> result.<span style="color:#cc00ff">get_original_image_hash_id</span>()
<span style="color:#006699"><strong>for</strong></span> item <span style="color:#000000"><strong>in</strong></span> parsed_result.<span style="color:#cc00ff">get_items</span>():
processor <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>DCPResultProcessor</strong></span>(item)
<span style="color:#0099ff"><em># Get portrait zone for passports
</em></span> portrait_zone <span style="color:#555555">=</span> <span style="color:#336666">None</span>
<span style="color:#006699"><strong>if</strong></span> processor.is_passport <span style="color:#000000"><strong>and</strong></span> self.irr:
portrait_zone <span style="color:#555555">=</span> self.irr.<span style="color:#cc00ff">get_portrait_zone</span>(hash_id)
mrz_result <span style="color:#555555">=</span> processor.<span style="color:#cc00ff">to_mrz_result</span>(portrait_zone, mrz_locations)
mrz_results.<span style="color:#cc00ff">append</span>(mrz_result)
<span style="color:#006699"><strong>return</strong></span> mrz_results
</code></span></span></span>
步骤 8:添加视觉叠加层
创建一个自定义小部件,用于显示带有 MRZ 和纵向叠加层的图像:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code><span style="color:#006699"><strong>class</strong></span> <span style="color:#00aa88"><strong>ImageDisplayWidget</strong></span>(QLabel):
<span style="color:#cc3300">"""</span><span style="color:#cc3300">Custom widget with visual overlays for MRZ and portrait.</span><span style="color:#cc3300">"""</span>
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">__init__</span>(self, parent<span style="color:#555555">=</span><span style="color:#336666">None</span>):
<span style="color:#cc00ff">super</span>().<span style="color:#cc00ff">__init__</span>(parent)
self.<span style="color:#cc00ff">setAcceptDrops</span>(<span style="color:#336666">True</span>)
self.current_image <span style="color:#555555">=</span> <span style="color:#336666">None</span>
self.mrz_results <span style="color:#555555">=</span> []
self.doc_quad <span style="color:#555555">=</span> <span style="color:#336666">None</span>
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">set_image</span>(self, image, mrz_results<span style="color:#555555">=</span><span style="color:#336666">None</span>, doc_quad<span style="color:#555555">=</span><span style="color:#336666">None</span>):
self.current_image <span style="color:#555555">=</span> image
self.mrz_results <span style="color:#555555">=</span> mrz_results <span style="color:#000000"><strong>or</strong></span> []
self.doc_quad <span style="color:#555555">=</span> doc_quad
self.<span style="color:#cc00ff">_update_display</span>()
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">_update_display</span>(self):
<span style="color:#006699"><strong>if</strong></span> self.current_image <span style="color:#000000"><strong>is</strong></span> <span style="color:#336666">None</span>:
<span style="color:#006699"><strong>return</strong></span>
<span style="color:#0099ff"><em># Convert OpenCV image to QPixmap
</em></span> rgb_image <span style="color:#555555">=</span> cv2.<span style="color:#cc00ff">cvtColor</span>(self.current_image, cv2.COLOR_BGR2RGB)
h, w, ch <span style="color:#555555">=</span> rgb_image.shape
bytes_per_line <span style="color:#555555">=</span> ch <span style="color:#555555">*</span> w
q_image <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QImage</strong></span>(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
pixmap <span style="color:#555555">=</span> QPixmap.<span style="color:#cc00ff">fromImage</span>(q_image)
<span style="color:#0099ff"><em># Scale to fit widget
</em></span> scaled_pixmap <span style="color:#555555">=</span> pixmap.<span style="color:#cc00ff">scaled</span>(self.<span style="color:#cc00ff">size</span>(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
<span style="color:#0099ff"><em># Calculate scale factor
</em></span> self.scale_factor <span style="color:#555555">=</span> scaled_pixmap.<span style="color:#cc00ff">width</span>() <span style="color:#555555">/</span> w
<span style="color:#0099ff"><em># Draw overlays
</em></span> <span style="color:#006699"><strong>if</strong></span> self.mrz_results <span style="color:#000000"><strong>or</strong></span> self.doc_quad:
painter <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QPainter</strong></span>(scaled_pixmap)
painter.<span style="color:#cc00ff">setRenderHint</span>(QPainter.Antialiasing)
<span style="color:#0099ff"><em># Draw document boundary (blue)
</em></span> <span style="color:#006699"><strong>if</strong></span> self.doc_quad:
self.<span style="color:#cc00ff">_draw_quadrilateral</span>(painter, self.doc_quad, <span style="color:#00aa88"><strong>QColor</strong></span>(<span style="color:#ff6600">0</span>, <span style="color:#ff6600">0</span>, <span style="color:#ff6600">255</span>, <span style="color:#ff6600">200</span>), <span style="color:#cc3300">"</span><span style="color:#cc3300">Document</span><span style="color:#cc3300">"</span>)
<span style="color:#006699"><strong>for</strong></span> result <span style="color:#000000"><strong>in</strong></span> self.mrz_results:
<span style="color:#0099ff"><em># Draw MRZ locations (green)
</em></span> <span style="color:#006699"><strong>for</strong></span> location <span style="color:#000000"><strong>in</strong></span> result.mrz_locations:
self.<span style="color:#cc00ff">_draw_quadrilateral</span>(painter, location, <span style="color:#00aa88"><strong>QColor</strong></span>(<span style="color:#ff6600">0</span>, <span style="color:#ff6600">255</span>, <span style="color:#ff6600">0</span>, <span style="color:#ff6600">200</span>), <span style="color:#cc3300">"</span><span style="color:#cc3300">MRZ</span><span style="color:#cc3300">"</span>)
<span style="color:#0099ff"><em># Draw portrait zone (orange)
</em></span> <span style="color:#006699"><strong>if</strong></span> result.portrait_zone:
self.<span style="color:#cc00ff">_draw_quadrilateral</span>(painter, result.portrait_zone, <span style="color:#00aa88"><strong>QColor</strong></span>(<span style="color:#ff6600">255</span>, <span style="color:#ff6600">165</span>, <span style="color:#ff6600">0</span>, <span style="color:#ff6600">200</span>), <span style="color:#cc3300">"</span><span style="color:#cc3300">Portrait</span><span style="color:#cc3300">"</span>)
painter.<span style="color:#cc00ff">end</span>()
self.<span style="color:#cc00ff">setPixmap</span>(scaled_pixmap)
<span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">_draw_quadrilateral</span>(self, painter: QPainter, quad, color: QColor, label: <span style="color:#336666">str</span>):
pen <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QPen</strong></span>(color, <span style="color:#ff6600">3</span>)
painter.<span style="color:#cc00ff">setPen</span>(pen)
points <span style="color:#555555">=</span> quad.points
<span style="color:#006699"><strong>if</strong></span> <span style="color:#cc00ff">len</span>(points) <span style="color:#555555">>=</span> <span style="color:#ff6600">4</span>:
<span style="color:#0099ff"><em># Scale points to display coordinates
</em></span> scaled_points <span style="color:#555555">=</span> []
<span style="color:#006699"><strong>for</strong></span> p <span style="color:#000000"><strong>in</strong></span> points:
x <span style="color:#555555">=</span> <span style="color:#cc00ff">int</span>(p.x <span style="color:#555555">*</span> self.scale_factor)
y <span style="color:#555555">=</span> <span style="color:#cc00ff">int</span>(p.y <span style="color:#555555">*</span> self.scale_factor)
scaled_points.<span style="color:#cc00ff">append</span>((x, y))
<span style="color:#0099ff"><em># Draw quadrilateral
</em></span> <span style="color:#006699"><strong>for</strong></span> i <span style="color:#000000"><strong>in</strong></span> <span style="color:#cc00ff">range</span>(<span style="color:#ff6600">4</span>):
x1, y1 <span style="color:#555555">=</span> scaled_points[i]
x2, y2 <span style="color:#555555">=</span> scaled_points[(i <span style="color:#555555">+</span> <span style="color:#ff6600">1</span>) <span style="color:#555555">%</span> <span style="color:#ff6600">4</span>]
painter.<span style="color:#cc00ff">drawLine</span>(x1, y1, x2, y2)
<span style="color:#0099ff"><em># Draw label
</em></span> font <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QFont</strong></span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Arial</span><span style="color:#cc3300">"</span>, <span style="color:#ff6600">12</span>, QFont.Bold)
painter.<span style="color:#cc00ff">setFont</span>(font)
painter.<span style="color:#cc00ff">setPen</span>(<span style="color:#00aa88"><strong>QPen</strong></span>(color, <span style="color:#ff6600">2</span>))
min_y <span style="color:#555555">=</span> <span style="color:#cc00ff">min</span>(p[<span style="color:#ff6600">1</span>] <span style="color:#006699"><strong>for</strong></span> p <span style="color:#000000"><strong>in</strong></span> scaled_points)
min_x <span style="color:#555555">=</span> <span style="color:#cc00ff">min</span>(p[<span style="color:#ff6600">0</span>] <span style="color:#006699"><strong>for</strong></span> p <span style="color:#000000"><strong>in</strong></span> scaled_points)
painter.<span style="color:#cc00ff">drawText</span>(min_x, <span style="color:#cc00ff">max</span>(<span style="color:#ff6600">0</span>, min_y <span style="color:#555555">-</span> <span style="color:#ff6600">5</span>), label)
</code></span></span></span>
步骤 9:运行应用程序
使用深色主题和入口点完成应用程序:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code><span style="color:#006699"><strong>def</strong></span> <span style="color:#cc00ff">main</span>():
app <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QApplication</strong></span>(sys.argv)
app.<span style="color:#cc00ff">setStyle</span>(<span style="color:#cc3300">"</span><span style="color:#cc3300">Fusion</span><span style="color:#cc3300">"</span>)
<span style="color:#0099ff"><em># Apply dark theme
</em></span> palette <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>QPalette</strong></span>()
palette.<span style="color:#cc00ff">setColor</span>(QPalette.Window, <span style="color:#00aa88"><strong>QColor</strong></span>(<span style="color:#ff6600">53</span>, <span style="color:#ff6600">53</span>, <span style="color:#ff6600">53</span>))
palette.<span style="color:#cc00ff">setColor</span>(QPalette.WindowText, Qt.white)
palette.<span style="color:#cc00ff">setColor</span>(QPalette.Base, <span style="color:#00aa88"><strong>QColor</strong></span>(<span style="color:#ff6600">35</span>, <span style="color:#ff6600">35</span>, <span style="color:#ff6600">35</span>))
palette.<span style="color:#cc00ff">setColor</span>(QPalette.Text, Qt.white)
palette.<span style="color:#cc00ff">setColor</span>(QPalette.Button, <span style="color:#00aa88"><strong>QColor</strong></span>(<span style="color:#ff6600">53</span>, <span style="color:#ff6600">53</span>, <span style="color:#ff6600">53</span>))
palette.<span style="color:#cc00ff">setColor</span>(QPalette.ButtonText, Qt.white)
app.<span style="color:#cc00ff">setPalette</span>(palette)
window <span style="color:#555555">=</span> <span style="color:#00aa88"><strong>MRZScannerWindow</strong></span>()
window.<span style="color:#cc00ff">show</span>()
sys.<span style="color:#cc00ff">exit</span>(app.<span style="color:#cc00ff">exec</span>())
<span style="color:#006699"><strong>if</strong></span> __name__ <span style="color:#555555">==</span> <span style="color:#cc3300">"</span><span style="color:#cc3300">__main__</span><span style="color:#cc3300">"</span>:
<span style="color:#cc00ff">main</span>()
</code></span></span></span>
测试应用程序
运行应用程序:
<span style="color:#212529"><span style="color:#333333"><span style="background-color:#eaeaea"><code>python mrz_scanner_gui.py
</code></span></span></span>

源代码
https://github.com/yushulx/python-mrz-scanner-sdk/tree/main/examples/official/gui
更多推荐


所有评论(0)