Python如何利用OCR实现检查报告单图片格式化输出结果之二

在上一篇文章实现了检查报告数据结构化输出,但是还有问题,如何解析返回的数据并结构化处理思路,以及前置图片处理等。综合下来有几个问题,

  1. 图片大小的限制,需要出去先对图片大小尺寸修改,主要是长度。(目前由于测试样片限制,目前能获取的是大量的电子检查报告)按照长度限制按比例缩小。
  2. 解析识别结果,总计处理实现项目结果的一一对应。
  3. 结果中的特殊字符处理
  4. 针对不同医院,项目实质是同一个,但是名称存在一定的差异,项目名称不统一。

图片大小修改

由于主要是长度的限制,所以通过判断图片本来的高度,与最大长度限制的比例,来缩放图片,返回调整过大小图片路径。

实现是通过Pillow库

import os
import pandas as pd
from PIL import Image  # 来源于Pillow库
import PIL  # 来源于Pillow库

def resizeimgae(resizefilepath,imagefile):
    # 重新调整图像大小,根据高度压缩
    img = Image.open(imagefile)
    name = imagefile.split("\")[-1]
    if not os.path.exists(resizefilepath):
        os.makedirs(resizefilepath)
    resizefile = os.path.join(resizefilepath, name)  # 统一存放修改后目录
    baseh = 4096  # 最长高度限制
    basewidth, hsize = img.size
    if hsize <= baseh:
        # 原始尺寸 小于直接返回
        img.save(resizefile)
        return resizefile
    print("图片调整长度")
    wpercent = (baseh / float(hsize))  # 获取缩放比例
    nbasewidth = int((float(basewidth) * float(wpercent))) # 获取宽带缩放比例
    img1 = img.resize((nbasewidth, baseh), PIL.Image.ANTIALIAS)
    img1.save(resizefile)
    return resizefile

解析返回结果返回结果化数据

分析返回结果,发现项目名称和结果是存在在一个列表中并按照顺序排列的字典元素。而不是项目名称和结果一一对应的。这就需要自己重新解析组装。

备注:其中't1#1#itname' 、't1#1#itvalue' 是模板设置表格设置名称


Python如何利用OCR实现检查报告单图片格式化输出结果之二


Python如何利用OCR实现检查报告单图片格式化输出结果之二

解析思路

首先把itname 和 itvalue 分别都值通过循环方便形成两个列表,然后在多对这个两个列表,重新组合。

由于不同医院存在名称不一致,针对每个医院定义不同名称列表。

1,是存在跨行的项目名称需要二次组装名称,

2,作为不同的医院名称目标,可以定义需要的项目名称。

def parserRet(dictres,nametmp,resultfile):
    # 结果处理取出项目和数字列表
    name = []
    valuse = []
    for i in dictres:
        namestr = "itname"
        vstr = "itvalue"
        wordstr = "word"
        wordname = i["word_name"]
        if namestr in wordname:
            wordvalue = i[wordstr]
            name.append(wordvalue.strip().strip(":"))
        if vstr in wordname:
            wordvalue = i[wordstr]
            valuse.append(wordvalue.strip())
    resDict = reZipRetlist(name,valuse,nametmp)  # 重新组合函数
    writeExecl(file=resultfile,data=resDict) # 输出到execl

重新组合函数

对两个项目和结果列表一起循环组合,如果项目名称通过提前定义好的项目名称模板,与下一个进行组合后的名称是否在项目名称模板中,如果是的就组合在一起,并对结果列表取值,组合到字典中。

# 项目名称列表
nameslistzl = ["白细胞",
            "红细胞",
            "血红蛋白",
            "红细胞压积",
            "平均红细胞体积",
            "平均RBC血红蛋白含量",
            "平均RBC血红蛋白浓度",
            "血小板",
            "血小板平均体积",
            "血小板分布宽度",
            "中性粒细胞绝对值",
            "中性粒细胞百分比",
            "淋巴细胞绝对值",
            "淋巴细胞百分比",
            "单核细胞绝对值",
            "单核细胞百分比",
            "嗜酸性粒细胞绝对值",
            "嗜酸性粒细胞百分比",
            "嗜碱性粒细胞绝对值",
            "嗜碱性粒细胞百分比",
            "红细胞分布密度CV值",
            "红细胞分布密度SD值",
            "血小板比积",
             "报告时间",
             "报告",
            ]
def reZipRetlist(namelist,valuelist,nametmp):
    # 重新组合项目列表和数字,返回结果输出到execl
    print("重新组合项目列表和数字,返回结果输出到execl")
    resDict={}
    numn = len(namelist)
    numv = len(valuelist)
    for i in range(numn):
        n = namelist[i].strip(':')  # 分别取两个列表的值
        v = valuelist[i].strip("%")
        if n in nametmp:
            resDict[n] = valueStrip(v)  # 去字符
        if i == numv - 1:
            # 到最后一个元素了索引比长度小1
            break
        if n not in nametmp:
            # 解决项目名称跨行问题,重新与下一个名称拼接与名称列表对比
            nn = namelist[i+1]
            nv = valuelist[i+1]
            newn = n + nn
            if nv != "":
                newv = nv  # 有值取该值 ,没值取上一个的
            if v != "":
                newv = v
            if newn in nametmp:
                resDict[newn] = valueStrip(newv)
    return resDict

特殊字符去除

由于结果可能存在各种字符串,而我们只需要数据,需要去除多余的字符串(单位)。单位可以根据到时候定义一个项目编码名称,通过编码统一,定义固定的单位。

python本身提供字符去除strip方法一个个定义去除,但是字符不固定,效果不是很好。只能自己实现一个方法,简单粗暴的,对字符串一个个去循环,找到第一个不是数字的地方,就返回字符串的切片索引前一个位置。

def Isint(v):
    try:
        newv = int(v)
    except Exception as e:
        print("value is not int")
        return False
    return True

def IsFloat(v):
    try:
        newv = float(v)
    except Exception as e:
        print("value is not Float")
        return False
    return True
    
def valueStrip(v):
    # 用于取数字值 去掉后面字符
    l = len(v)
    if v == "":
        return v
    if l == 1:
        if not Isint(v):
            return ""
        return v
    else:
        if "." in v:
            for i in range(1, l+1):
                iv = v[:i]
                if not IsFloat(iv):
                    return v[:i-1]
            return v
        else:
            for i in range(1, l+1):
                iv = v[:i]
                if not Isint(iv):
                    return v[:i - 1]
            return v

通过reZipRetlist函数得到字典,我这里将字典写入到execl中,

# 写入到execl中
def writeExecl(file,sheetName="Sheet1",data={}):
    if not os.path.exists(file):
        writer = pd.ExcelWriter(file)
        df = pd.DataFrame()
        df.to_excel(writer, sheetName, index=False)
        writer.save()
    writer = pd.ExcelWriter(file)
    df = pd.read_excel(file, sheet_name=sheetName)
    df = df.append(data, ignore_index=True)
    df.to_excel(writer, sheetName, index=False)
    writer.save()

结果

通过目前结果看识别率还是可以的,后续通过批量处理成功率也还是在90%以上。当然还有坑需要填的,因为目前这是电子检查报告单的,还对不同的手机机型(安卓/苹果,不同屏幕尺寸等)等没有测试,敬请期待后续填坑。


Python如何利用OCR实现检查报告单图片格式化输出结果之二

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章