技术栈选型与架构说明
本系统旨在构建一个能够自动识别护照信息并进行数字化存储的轻量级档案馆。为了确保零门槛落地,我们采用以下技术栈:
- 开发语言: Python 3.9(生态丰富,OCR库支持好)
- OCR引擎: Tesseract-OCR(开源免费,支持多语言)
- Web框架: Flask(轻量级,适合快速构建API)
- 数据库: MySQL 8.0(成熟稳定,存储结构化数据)
- 图像处理: Pillow(Python图像处理标准库)
系统核心流程为:前端上传护照图片 -> 后端接收文件 -> 调用OCR识别文本 -> 正则提取关键信息 -> 存入MySQL数据库 -> 返回结构化JSON。
第一步:环境准备与依赖安装
首先需要在本地搭建Python运行环境。请确保已安装Python 3.9或更高版本。为了避免环境污染,我们创建一个独立的虚拟环境。
在命令行终端中依次执行以下命令:
```bash
创建名为passport_archive的虚拟环境
python -m venv passport_archive
激活虚拟环境(Windows)
passport_archive\Scripts\activate
激活虚拟环境(Mac/Linux)
source passport_archive/bin/activate
安装必要的Python依赖包
pip install flask pytesseract pillow pymysql cryptography
```
注意: `pytesseract` 是Python的OCR接口库,真正的识别引擎需要单独安装二进制文件。
第二步:OCR引擎Tesseract部署
Tesseract是OCR识别的核心。如果未正确安装,代码运行会报错"tesseract is not installed or it's not in your path"。
Windows系统安装
直接下载官方安装包。访问以下地址下载 Windows installer:
https://github.com/UB-Mannheim/tesseract/wiki
下载最新版(如 tesseract-ocr-w64-setup-5.x.x.exe)。安装时,务必勾选 "Additional language data" 并选择 "English" 和 "简体中文"(如需识别中文护照),或者直接全选。记住安装路径,默认为 C:\Program Files\Tesseract-OCR\tesseract.exe。
Linux系统安装
```bash
sudo apt update
sudo apt install tesseract-ocr
sudo apt install libtesseract-dev
```
语言包配置
护照识别主要针对英文和数字。在代码中调用时,我们需要指定语言参数为 'eng'(英语)。如果识别包含中文的机读码,可能需要配置 'chi_sim'。
第三步:数据库结构设计与初始化
我们需要设计一张表来存储护照的元数据和识别结果。打开MySQL客户端或命令行,执行以下SQL:
```sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS passport_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE passport_db;
-- 创建护照信息表
CREATE TABLE IF NOT EXISTS passport_records (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
file_name VARCHAR(255) NOT NULL COMMENT '原始文件名',
passport_number VARCHAR(50) DEFAULT NULL COMMENT '护照号',
full_name VARCHAR(100) DEFAULT NULL COMMENT '姓名',
nationality VARCHAR(50) DEFAULT NULL COMMENT '国籍',
sex VARCHAR(10) DEFAULT NULL COMMENT '性别',
birth_date DATE DEFAULT NULL COMMENT '出生日期',
expiry_date DATE DEFAULT NULL COMMENT '有效期至',
ocr_raw_text TEXT COMMENT 'OCR识别的完整原始文本',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
INDEX idx_passport_number (passport_number)
) ENGINE=InnoDB;
```
第四步:核心业务逻辑实现

创建项目目录结构。新建文件夹 project,并在其中创建 app.py(主程序)、config.py(配置文件)和 uploads(空文件夹,用于存图片)。
1. 配置数据库连接
在 config.py 中填入你的数据库实际账号密码:
```python
config.py
DB_CONFIG = {
'host': 'localhost',
'user': 'root', 请修改为你的MySQL用户名
'password': '123456', 请修改为你的MySQL密码
'database': 'passport_db',
'charset': 'utf8mb4'
}
Tesseract 路径配置(如果是Windows,必须显式指定路径;Linux/Mac通常不需要)
import os
如果是Windows,请取消下面这行的注释并修改为你的实际安装路径
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
```
2. 编写OCR提取逻辑
护照上的信息通常位于固定区域(MRZ机读码或VIZ视觉识别区)。为了简化实操,我们使用正则表达式对OCR识别后的全文进行匹配。护照号通常由字母和数字组成,如 G12345678。
在 app.py 中编写如下完整代码:
```python
import os
import re
import datetime
import pymysql
from flask import Flask, request, jsonify
from PIL import Image
import pytesseract
from config import DB_CONFIG
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['MAX_CONTENT_LENGTH'] = 16 1024 1024 限制上传16MB
确保上传目录存在
if not os.path.exists(app.config['UPLOAD_FOLDER']):
os.makedirs(app.config['UPLOAD_FOLDER'])
def get_db_connection():
return pymysql.connect(DB_CONFIG)
def extract_passport_info(text):
"""
使用正则表达式从OCR文本中提取护照关键信息
注意:真实生产环境建议使用专门的MRZ解析库,这里演示纯文本处理逻辑
"""
info = {}
提取护照号:通常以P开头,后接字母和数字,或者大写字母+数字组合
这里匹配常见的护照号格式,例如 G12345678 或 E1234567
passport_pattern = r'[A-Z]{1,2}[0-9]{6,9}'
passport_matches = re.findall(passport_pattern, text)
if passport_matches:
过滤掉像 "P
= 8:
info['passport_number'] = match
break
if 'passport_number' not in info:
info['passport_number'] = passport_matches[0]
提取姓名:在VIZ区,姓名通常在 "Surname/" 之后
简单逻辑:查找大写单词序列
name_pattern = r'[A-Z]{3,20}\s[A-Z]{3,20}' 姓 名
name_match = re.search(name_pattern, text)
if name_match:
info['full_name'] = name_match.group(0).strip()
提取日期:格式 DD/MM/YYYY 或 DD.MM.YYYY
date_pattern = r'(\d{2})[/.](\d{2})[/.](\d{4})'
dates = re.findall(date_pattern, text)
简单的日期区分逻辑:通常第一个出现的日期是出生日期,第二个是有效期
这里需要将OCR识别的字符串转为数据库Date对象
valid_dates = []
for d in dates:
day, month, year = d
try:
date_obj = datetime.date(int(year), int(month), int(day))
valid_dates.append(date_obj)
except ValueError:
continue
if len(valid_dates) >= 1:
info['birth_date'] = valid_dates[0]
if len(valid_dates) >= 2:
info['expiry_date'] = valid_dates[1]
提取性别:M / F
sex_pattern = r'\b([MF])\b'
sex_match = re.search(sex_pattern, text, re.IGNORECASE)
if sex_match:
info['sex'] = sex_match.group(1).upper()
return info
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return jsonify({'error': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
if file:
filename = file.filename
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
try:
1. 图像预处理:转为灰度图提高识别率
img = Image.open(filepath)
img = img.convert('L') 转灰度
2. OCR识别
psm 6 假设图像为统一的文本块
custom_config = r'--oem 3 --psm 6'
text = pytesseract.image_to_string(img, lang='eng', config=custom_config)
3. 提取信息
extracted_info = extract_passport_info(text)
4. 存入数据库
conn = get_db_connection()
try:
with conn.cursor() as cursor:
sql = """
INSERT INTO passport_records
(file_name, passport_number, full_name, sex, birth_date, expiry_date, ocr_raw_text)
VALUES (%s, %s, %s, %s, %s, %s, %s)
"""
cursor.execute(sql, (
filename,
extracted_info.get('passport_number'),
extracted_info.get('full_name'),
extracted_info.get('sex'),
extracted_info.get('birth_date'),
extracted_info.get('expiry_date'),
text
))
conn.commit()
finally:
conn.close()
return jsonify({
'status': 'success',
'data': extracted_info,
'raw_text_preview': text[:100] + '...' 返回部分原文用于调试
})
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(debug=True, port=5000)
```
第五步:系统功能验证与测试
代码编写完成后,启动服务并进行测试。
在终端中运行:
```bash
python app.py
```
看到输出 Running on http://127.0.0.1:5000 表示服务启动成功。
使用curl命令测试
准备一张清晰的护照图片文件(命名为 test_passport.jpg)放在当前目录下,执行以下命令:
```bash
curl -X POST -F "file=@test_passport.jpg" http://127.0.0.1:5000/upload
```
预期返回结果
如果识别成功,终端将返回JSON格式的数据,包含提取出的护照号、姓名等信息:
```json
{
"data": {
"birth_date": "1990-01-01",
"expiry_date": "2025-01-01",
"full_name": "SURNAME GIVENNAME",
"passport_number": "G12345678",
"sex": "M"
},
"raw_text_preview": "P常见问题排查
在实操过程中,可能会遇到以下两个主要问题,请按方案处理:
1. 识别率低或乱码:
Tesseract默认对图片质量要求较高。如果遇到乱码,请在代码的 img.convert('L') 后增加二值化处理代码:
```python
增强对比度
from PIL import ImageEnhance
enhancer = ImageEnhance.Contrast(img)
img = enhancer.enhance(2.0)
设定阈值二值化
img = img.point(lambda x: 0 if x < 140 else 255, '1')
```
2. Windows下报错找不到 tesseract:
这是最常见的问题。请再次检查 config.py 中的路径配置,确保路径指向的 .exe 文件是真实存在的,且路径字符串前加 r 以避免转义字符问题。