医保人工报销OCR识别方案

医保人工报销 OCR 识别方案

文章目录

  • [医保人工报销 OCR 识别方案](#医保人工报销 OCR 识别方案)

场景 : 医院费用清单(A4纸打印,含公章覆盖)→ OCR识别通用名 → 模糊匹配医保字典 → 确定收费等级

原则: 自动匹配 + 例外转人工,不做全自动


一、方案架构

复制代码
费用清单扫描件 → 预处理(去公章+增强) → ROI裁剪(通用名列)
    → PaddleOCR识别 → 编辑距离模糊匹配字典 → 命中介入自通过
    → 未命中/低置信 → 人工审核界面 → 确认入库

二、环境准备

2.1 环境信息

基于 Python 3.9 + PaddleOCR 2.9.1 验证通过,实测环境:

组件 版本 说明
Python 3.9.25 conda 独立环境
paddlepaddle 3.1.0 CPU 版,GPU 版替换为 paddlepaddle-gpu
paddleocr 2.9.1 PP-OCRv4 模型,含 PP-Structure 表格识别
paddlex 3.5.2 模型管理依赖,自动安装
opencv-python 4.11.0.86 图像预处理(公章去除、增强)
Pillow 11.3.0 图像加载
numpy 1.26.4 数组运算
python-Levenshtein 0.27.1 编辑距离模糊匹配(需单独安装)

重要 : CPU 模式下必须设置环境变量 FLAGS_use_mkldnn=0,否则 OneDNN 与 Windows 上的 PIR 属性转换存在兼容问题,会导致 NotImplementedError

2.2 新建 Conda 环境

bash 复制代码
conda create -n medical_ocr python=3.9 -y
conda activate medical_ocr

2.3 安装依赖(已验证完整命令)

bash 复制代码
# PaddlePaddle(CPU版)
pip install paddlepaddle==3.1.0 -i https://pypi.tuna.tsinghua.edu.cn/simple

# GPU版(如有NVIDIA卡)
# pip install paddlepaddle-gpu==3.1.0 -i https://pypi.tuna.tsinghua.edu.cn/simple

# PaddleOCR
pip install paddleocr -i https://pypi.tuna.tsinghua.edu.cn/simple

# 图像处理
pip install opencv-python pillow numpy -i https://pypi.tuna.tsinghua.edu.cn/simple

# Levenshtein距离(模糊匹配)
pip install python-Levenshtein -i https://pypi.tuna.tsinghua.edu.cn/simple

2.4 验证安装

python 复制代码
import os
os.environ['FLAGS_use_mkldnn'] = '0'  # CPU模式必须

from paddleocr import PaddleOCR
ocr = PaddleOCR(lang='ch')
print('PaddleOCR ready')

三、图像预处理

3.1 公章去除

python 复制代码
import cv2
import numpy as np

def remove_red_stamp(img_path):
    img = cv2.imread(img_path)
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    # 红色范围(公章)
    lower_red1 = np.array([0, 50, 50])
    upper_red1 = np.array([10, 255, 255])
    lower_red2 = np.array([156, 50, 50])
    upper_red2 = np.array([180, 255, 255])

    mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
    mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
    mask = mask1 | mask2

    # 膨胀后填充白色
    kernel = np.ones((3, 3), np.uint8)
    mask = cv2.dilate(mask, kernel, iterations=1)
    img[mask > 0] = [255, 255, 255]

    return img

3.2 图像增强(针式打印/褪色清单)

python 复制代码
def enhance_image(img):
    # 灰度化 + CLAHE对比度增强
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    enhanced = clahe.apply(gray)

    # 自适应二值化
    binary = cv2.adaptiveThreshold(
        enhanced, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
        cv2.THRESH_BINARY, 11, 2
    )

    # 转回三通道给PaddleOCR
    return cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)

3.3 ROI 裁剪 --- 只取通用名列

python 复制代码
def crop_drug_column(img):
    """
    根据清单模板裁剪药品通用名列区域。
    建议做成配置化:不同医院模板定义不同的列坐标。
    """
    h, w = img.shape[:2]
    # 示例:通用名列在 x=50~300, y=表头下方到页脚上方
    roi = img[200:h-80, 50:300]
    return roi

3.4 完整预处理流水线

python 复制代码
def preprocess(image_path):
    img = remove_red_stamp(image_path)
    img = enhance_image(img)
    img = crop_drug_column(img)
    return img

四、OCR 识别引擎

4.1 单实例封装

python 复制代码
import os
os.environ['FLAGS_use_mkldnn'] = '0'

from paddleocr import PaddleOCR

class MedicalOCR:
    def __init__(self, use_gpu=False):
        self.ocr = PaddleOCR(lang='ch', use_angle_cls=True)
        self.use_gpu = use_gpu

    def recognize(self, img):
        """返回文本行列表"""
        result = self.ocr.ocr(img)
        if not result or not result[0]:
            return []
        # 按y坐标排序(表格从上到下)
        lines = sorted(result[0], key=lambda x: x[0][0][1])
        return [{
            'text': line[1][0],
            'confidence': line[1][1],
            'bbox': line[0]
        } for line in lines]

ocr_engine = MedicalOCR()

4.2 并发方案(生产环境)

python 复制代码
from multiprocessing import Pool

def init_worker():
    global _ocr
    import os
    os.environ['FLAGS_use_mkldnn'] = '0'
    from paddleocr import PaddleOCR
    _ocr = PaddleOCR(lang='ch', use_angle_cls=True)

def process_image(img_path):
    img = preprocess(img_path)
    result = _ocr.ocr(img)
    return extract_lines(result)

# 4进程池
with Pool(4, initializer=init_worker) as pool:
    results = pool.map(process_image, image_files)

五、医保字典匹配

5.1 字典结构

python 复制代码
# 示例:药品通用名 → 医保编码 → 收费等级
MEDICAL_DICT = {
    '阿莫西林胶囊': {'code': 'XA01-001', 'level': '甲类', 'dosage': '胶囊'},
    '氯化钠注射液': {'code': 'XB05-023', 'level': '甲类', 'dosage': '注射液'},
    '阿托伐他汀钙片': {'code': 'XC10-056', 'level': '乙类', 'dosage': '片剂'},
    # ... 数万条
}

5.2 模糊匹配引擎

python 复制代码
from Levenshtein import distance as levenshtein

def fuzzy_match(ocr_text, dict_keys, threshold=0.85):
    """
    编辑距离 ≤1 或 相似度 ≥threshold 返回最佳匹配
    返回: (matched_key, score, level) 或 None
    """
    best_key, best_score = None, 0
    ocr_clean = ocr_text.strip().replace(' ', '')

    for key in dict_keys:
        key_clean = key.strip().replace(' ', '')

        # 完全匹配:直接返回
        if ocr_clean == key_clean:
            return (key, 1.0, MEDICAL_DICT[key]['level'])

        # 编辑距离
        max_len = max(len(ocr_clean), len(key_clean))
        if max_len == 0:
            continue
        dist = levenshtein(ocr_clean, key_clean)
        similarity = 1 - dist / max_len

        if similarity > best_score:
            best_score = similarity
            best_key = key

    if best_score >= threshold:
        return (best_key, best_score, MEDICAL_DICT[best_key]['level'])
    return None

5.3 策略优先级

python 复制代码
def match_pipeline(ocr_lines):
    results = []
    for item in ocr_lines:
        text = item['text']
        conf = item['confidence']

        # 策略1: OCR置信度 < 0.7 → 直接转人工
        if conf < 0.7:
            results.append({'status': 'REVIEW', 'reason': '低置信度', 'ocr_text': text, 'ocr_conf': conf})
            continue

        # 策略2: 完全匹配
        if text in MEDICAL_DICT:
            entry = MEDICAL_DICT[text]
            results.append({'status': 'MATCHED', 'code': entry['code'], 'level': entry['level'], 'ocr_text': text})
            continue

        # 策略3: 编辑距离 ≤1 模糊匹配
        matched = fuzzy_match(text, MEDICAL_DICT.keys(), threshold=0.85)
        if matched:
            results.append({'status': 'FUZZY', 'code': MEDICAL_DICT[matched[0]]['code'], 'level': matched[2], 'ocr_text': text, 'matched_name': matched[0], 'score': matched[1]})
            continue

        # 策略4: 未命中 → 转人工
        results.append({'status': 'REVIEW', 'reason': '未匹配字典', 'ocr_text': text, 'ocr_conf': conf})

    return results

六、业务处理流程

复制代码
扫描件 → 预处理 → ROI裁剪 → OCR识别 → 字典匹配
                ↓                             ↓
           结构化字段                     ├─ 完全匹配 → 自动通过
         (医院名、日期、                  ├─ 模糊匹配(标注) → 自动通过
          就诊号)                        └─ 低置信/未匹配 → 人工审核界面
                                               ↓
                                     人工选择/修正 → 确认入库

人工审核界面设计要点

  • 左侧显示原始清单截图,高亮待确认行
  • 右侧显示 OCR 识别文本 + 字典候选列表(编辑距离排序 Top 5)
  • 单键操作:选中确认 / 手动输入 / 跳过
  • 批量审核:全部模糊匹配的行集中展示,一键批量确认

七、准确率预估

环节 预估准确率 备注
图像预处理 95% 公章去除+增强,少数极端案例无效
OCR 单字识别 90% A4印刷清单,非针式打印
OCR 整行识别 85% 窄列(≤3字宽)易串行
字典完全匹配 70% OCR 未出错且字典有该条目
模糊匹配(编辑距离≤1) 22% 补上 OCR 小误差
自动通过合计 92% 70% + 22%
转人工审核 8% 约每 100 条 8 条需人工确认

不宜全自动的场景

  • 针式打印(点阵断续)清单 --- 准确率骤降至 60~70%
  • 公章覆盖超过 3 行文字 --- 预处理无效
  • 手写补充的药品名 --- 需单独训练手写模型

八、部署建议

环境 配置 吞吐
CPU(开发/小规模) 8核 + 4进程 6080 张/小时
GPU(生产推荐) T4/V100 + 单卡 6001000 张/小时
CPU(高并发) 16核 + 8进程 + 队列 150200 张/小时

注意事项

  1. 不同医院清单格式不同,ROI 裁剪坐标需做成模板配置,一个医院一个配置文件
  2. 医保字典定期同步更新,模糊匹配结果建议记录日志便于追溯审计
  3. OCR 所有低置信度/未匹配结果必须留痕,医保审计需要
  4. 生产环境务必使用多进程池方案,单进程 PaddleOCR 非线程安全
相关推荐
半壶清水8 小时前
PaddlePaddle、easyocr与OpenCV工具识别书法图片内容,自动批量重命名图片文件的方法
人工智能·opencv·ocr·paddlepaddle
AI人工智能+9 小时前
营业执照识别技术,通过深度学习、图像处理与NLP技术的深度融合,实现了对营业执照信息的快速、精准提取与智能解析
深度学习·自然语言处理·ocr·营业执照识别
HyperAI超神经11 小时前
在线教程丨英伟达开源LocateAnything,3B模型可实现图像+视频的目标指向/开放词汇目标检测/指代表达定位/OCR文本定位等功能
人工智能·目标检测·计算机视觉·ocr·目标文本定位
jiajia_lisa1 天前
轻量化智能升级,降本增效赋能长效运营
ocr
Komorebi_99991 天前
OCR + 大模型融合方案
大模型·ocr
AwakeFantasy2 天前
聊聊近况和最近做的踩坑项目
人工智能·python·gpt·ocr
EntyIU4 天前
mineru从安装部署到测试使用完整指南
python·ocr
OCR_133716212754 天前
技术解读:国内第一梯队 OCR 大模型现状与技术路线分析
ocr
AI人工智能+4 天前
赋能智慧监管:基于深度学习的特种行业许可证全要素精准识别系统
计算机视觉·自然语言处理·ocr·特种行业许可证识别