【项目总结】医疗化验单的OCR识别

news2024/11/27 2:37:51

项目总结

医疗化验单OCR


文章目录

  • 项目总结
  • 前言
  • 一、项目要求
  • 二、解决思路
    • 1.模型
    • 1.扶正
    • 2.裁剪
    • 3.pipeline
  • 三、总结


前言

课题组项目的总结。


一、项目要求

课题组和广州的一家药企有合作,甲方要求把一张医疗化验单内的表格内容整体识别出来,特别是化验的数值和名称的准确率,要求达到85%以上。

比如下面一张样本,三线表之外的内容都不需要我们负责(比如姓名、年龄这些),我们只需要把三线表里面的内容识别出来,特别是项目栏、结果栏的识别精度要高。但是很明显有很多干扰(竖线、手写体),这些都会严重影响识别精度。这还是PDF版的,属于干扰最少的,还有手动拍照的、拍摄电脑屏幕的样本更难识别。

请添加图片描述

甲方的要求就是我们把数值和名称的识别准确率优先提上去。甲方之前有一个识别模型,但是准确率提不上去,也想过找百度合作,但是成本太高,所以找到了我们课题组。

二、解决思路

1.模型

OCR模型我们选用的是百度开源的PaddleOCR。
Git:PaddleOCR

1.扶正

由于要识别的样本不是很规整,有PDF、手动拍照、拍电脑屏幕的。这就导致样本有各种各样的倾斜角度,有的照片甚至有曲折,这给OCR识别造成了很大的困扰。所以针对这些干扰,首先解决倾斜问题,要把样本图片的角度扶正也就是成水平状态,这样能提高OCR的准确率。并且我们实验发现,如果把整张表传进去识别,准确率会很低。而如果只把我们需要的表格裁剪下来,那识别精度就会很高了,所以把图片扶正也是为了裁剪做准备。

甲方想要做成小程序,所以深度学习这方面就不考虑,要尽量减小模型,只能用opencv的技术。要把图片扶正,首先要找一个参考点,我们的思路是以表格的这些直线作为参考,计算他们的斜率是否为0来判断图片是否水平。

以三线表为例,通过opencv把三线表的三条直线识别出来,因为识别的直线有误差,所以决定计算三条直线的斜率取平均,平均斜率就是我们的判断依据。

opencv识别直线的算法其实有很多,我们也尝试了很多种例举两种。

一是通过找轮廓的方法,也就是opencv的cv2.findContours函数。根据找出轮廓的周长大小来把直线筛选出来。因为三线表的三条直线明显比其他的要长很多,自然周长也会大些。实验效果虽然也还不错,但是如果样本干扰太多,这个方法会有很大的误差,会找出很多非直线的轮廓。这个方法也就pass。
二是通过霍夫变换。霍夫变换是一个非常经典的算法,简单实用。霍夫变换实验的效果一开始其实不是很好,因为样本真的没有想象那么好,非常非常多的干扰,识别出来的效果如下(蓝色线即霍夫变换识别出来的直线):
在这里插入图片描述
肉眼看很明显的三条直线直接识别出来几百条,霍夫变换不可能像人一样精准的标注出一条直线,它是根据像素之间的关系来计算的,所以看起来一个地方只有一条直线,其实它预测了很多条只是斜率相差很小很小,所以这就是为什么要取平均的另一个原因。后续就开始了调参之路(调参不是漫无目的地调要弄懂原理),有的样本适合这个参数有的适合另一个参数。调参后:
在这里插入图片描述

部分代码demo

class RectifyBias():
    
    def __init__(self,pic_path):
        self.pic_path=pic_path    #图片路径
        
    def rotate_bound(self,image, angle):
        (h, w) = image.shape[:2]
        (cX, cY) = (w / 2, h / 2)
        M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
        cos = np.abs(M[0, 0])
        sin = np.abs(M[0, 1])
        nW = int((h * sin) + (w * cos))
        nH = int((h * cos) + (w * sin))
        M[0, 2] += (nW / 2) - cX
        M[1, 2] += (nH / 2) - cY
        return cv2.warpAffine(image, M, (nW, nH))
    # 轮廓方法
    def find_contour(self):
        pic=cv2.imdecode(np.fromfile(self.pic_path,dtype=np.uint8),cv2.IMREAD_COLOR)
        gray=cv2.cvtColor(pic,cv2.COLOR_BGR2GRAY)
        thresh, binary=cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
        img=pic.copy()
        a,b=cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
        row,col=binary.shape
    #     j=0
        for i in range(len(a)):
            if cv2.arcLength(a[i],closed=True)>col/2  and cv2.arcLength(a[i],closed=True)<1.9*(col+row):
    #             j+=1
                cv2.drawContours(img,a,i,(0,0,255),2)
                coor=a[i]
    #             if j==2:
                break
#         print(cv2.minAreaRect(coor)[2])
        if cv2.minAreaRect(coor)[2]<45:
            imgs=self.rotate_bound(img,-(cv2.minAreaRect(coor)[2]))
        else:
            imgs=self.rotate_bound(img,90-(cv2.minAreaRect(coor)[2]))
        cv2.namedWindow("before",cv2.WINDOW_NORMAL)
        cv2.resizeWindow("before",1200,1200)
        cv2.imshow("before",img)
        cv2.imshow("after",imgs)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
     # 霍夫变换 
    def find_lines(self):
        pic=cv2.imdecode(np.fromfile(self.pic_path,dtype=np.uint8),cv2.IMREAD_COLOR)
        gray=cv2.cvtColor(pic,cv2.COLOR_BGR2GRAY)
        thresh, binary=cv2.threshold(gray,160,255,cv2.THRESH_BINARY)

        dst=cv2.GaussianBlur(binary, (9,9), 0) 

        img=pic.copy()
        edges = cv2.Canny(dst, 70, 150,)
        lines = cv2.HoughLinesP(edges ,1,np.pi/180, 100,minLineLength= 200, maxLineGap=200)
#         lines = cv2.HoughLinesP(edges ,1,np.pi/360, 300,minLineLength= 500, maxLineGap=300)
        slope_list=[]
        for i in range(len(lines)):
            x_1, y_1, x_2, y_2 = lines[i][0]
            if (x_1-x_2)!=0:
#                 if  ((y_1-y_2)/(x_1-x_2))<1 and ((y_1-y_2)/(x_1-x_2))>-1:
                slope_list.append(round((y_1-y_2)/(x_1-x_2),2))
                cv2.line(img, (x_1, y_1), (x_2, y_2), (255, 0, 0), 3)     
#         print(slope_list)
        imgs=self.rotate_bound(img,-(math.degrees(math.atan(np.mean(slope_list)))))
        cv2.namedWindow("before",cv2.WINDOW_NORMAL)
        cv2.resizeWindow("before",1200,1200)
        cv2.imshow("before",img)
#         cv2.imshow("after",imgs)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        
# DS221789-全套体检报告    
pic_path= "pic6.png"
pic_path = ""
for image in os.listdir(pic_path):
    pic_path = ""
    pic_path +=image
    a=rectify_bias(pic_path)
    a.find_lines()


# a=rectify_bias(pic_path)
# a.find_lines()
# a=rectify_bias(pic_path)
# a.find_contour()

2.裁剪

解决完倾斜问题后,发现精度有提升但还是不够。随后做了很对实验,实验发现,如果把整张表传进去识别,准确率会很低。而如果只把我们需要的表格裁剪下来传进去,那识别精度就会很高了,所以把图片扶正也是为了裁剪做准备。

裁剪需要在扶正后的图片的基础上,找出第一根直线和最后一根直线,把表格裁剪出来。这是三线表的做法。但是,还有一种双栏表(中间还有一条竖线也就是两栏):
在这里插入图片描述
就是要把这种裁剪成两部分。这样识别精度大大提高。
demo结果参考:

三线表裁剪:
在这里插入图片描述
双栏裁剪:
在这里插入图片描述

3.pipeline

送入一张图片,经过预处理后(扶正、裁剪等)送入Paddle OCR,得出结果后通过文字纠正(模型后处理)以后,输出结果。

结果精度:
在这里插入图片描述


三、总结

项目经过几个月也算是完成了,组里算是5个人一起搞这个项目,经过很多尝试也算是做成了,一开始甲方以为我们做不成,不过最后精度不仅没问题还超过了甲方所提的要求,也顺利签合同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/86006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

测开- Junit 单元测试框架

文章目录前言了解 Junit准备工作 - 在 pom.xml 文件中引入 Junit 相关依赖1、Junit注解TestBeforeEach、BeforeAllAfterEach && AfterAll2、断言1、Assertions - assertEquals 方法2、Assertions - assertNotEquals 方法3、Assertions - assertTrue && assertF…

一个关于React数据不可变的无聊问题

对于一个React的开发者来说不知道你有没有想过为什么React追求数据不可变这个范式&#xff1b; 一个月前我想过一个问题如果我在使用useState这个hooks的时候传入的是一个改变后的引用类型对象会发生什么&#xff1f; 例如&#xff1a; import {useState} from "react&…

css之@media网页适配

原因&#xff1a; 原本是想用 iview Grid 栅格,但以下响应并不符合我的需求 【我需要的分辨率是1920和1536】&#xff0c;所以需要手动修改 解决方案&#xff1a; html <Row> <i-col :xs"6" :sm"6" :md"6" :lg"8"><d…

IB经济试卷实用指南分享

明明每个经济理论都知道&#xff0c;然而在实际答题过程中就是用不出来&#xff1f; 看到答案后却是恍然大悟&#xff0c;就像对着数学答案&#xff0c;大体还能想明白“原来是这样的”&#xff0c;但考试的时候就是想不到用这个理论、这个模型&#xff1f; 出现这种现象&#…

左值和右值

左值和右值 按字面意思&#xff0c;通俗地说。以赋值符号 为界&#xff0c; 左边的就是左值&#xff0c; 右边就是右值。 更深一层&#xff0c;可以将 L-value 的 L, 理解成 Location&#xff0c;表示定位&#xff0c;地址。将 R-value 的 R 理解成 Read&#xff0c;表示读取…

[附源码]Python计算机毕业设计电影售票管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

什么是位移电流?位移电流密度计算公式详解

位移电流变化着的电场可以存在于真空、导体、电介质中&#xff0c;本质是变化着的电场&#xff0c;不会产生化学效应&#xff0c;也不会产生焦耳热。下面一起随着小编一起了解一下什么是位移电流以及位移电流密度计算公式。 什么是位移电流&#xff1f; 1861年&#xff0c;詹姆…

[附源码]Python计算机毕业设计SSM基于web的医院门诊管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

基于java+springboot+mybatis+vue+mysql的一起来约苗系统

项目介绍 在系统流程分析当中调查分析它是比较重要的环节&#xff0c;因为在这个系统当中它都涉及到每个环节的业务流程&#xff0c;所以从JavaSprignBootVueMYSQL一起来约苗系统的设计的整体设计上要保证各个信息的正确输入和输出以及对数据储存的完整&#xff0c;并结合实际…

ASEMI肖特基二极管MBR20100FCT图片,MBR20100FCT大小

编辑-Z ASEMI肖特基二极管MBR20100FCT参数&#xff1a; 型号&#xff1a;MBR20100FCT 最大重复峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;100V 最大RMS电桥输入电压&#xff08;VRMS&#xff09;&#xff1a;70V 最大直流阻断电压&#xff08;VDC&#xff09;…

python+django车辆充电桩管理系统

启动一个新项目 执行下面的命令来创建一个新的 Django 项目&#xff1a; django-admin startproject myproject 命令行工具django-admin会在安装Django的时候一起自动安装好。 执行了上面的命令以后&#xff0c;系统会为Django项目生成基础文件夹结构。 现在&#xff0c;我…

【软件测试】测试人我懵了,产品验收时还有一堆bug?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 为什么明明写了 100…

屏幕录制怎么加上水印?这个方法,真的太实用啦

随着网络技术的飞速发展&#xff0c;短视频已经成为传播信息最快的方式之一。越来越多的人将自己喜欢的游戏直播视频和网络直播课程知识制作成短视频&#xff0c;并在各大媒体平台进行分享。然后&#xff0c;录制的视频可能会被其他人带到其他平台。屏幕录制怎么加上水印&#…

FLStudio21水果软件中文版本有哪些新增功能?

FL Studio 21即将推出 – 新功能和改进。如果您从事音乐制作&#xff0c;那么您不可能没有听说过 FL Studio&#xff0c;或者很可能已经使用过这个音乐程序。好了&#xff0c;新版本的 FL Studio 21 DAW 已经准备好向公众发布了。Image-line 正在为 2022 年的大型揭幕准备最终细…

iOS原生项目拥有Flutter热重载极速调试

1. Mac的App Store上下载安装InjectionIII. 2. 打开InjectionIII, Open Project, 选择你的项目目录. 3. 选择的项目会在Open Recent中出现, 保持File Watcher的选项勾选. 4. 在AppDelegate的DidFinishLaunchingWithOptions配置InjectionIII的路径 - (BOOL)application:(UIAp…

python+django勤工助学管理系统vue

目 录 第1章 绪论 1 1.1课题背景 1 1.2 背景意义 1 1.3 研究的内容 2 第2章 相关技术 3 第3章 系统分析 5 3.1可行性分析 5 3.2系统性能分析 6 3.3系统流程分析 6 3.3.1操作流程 6 3.3.2信息添加流程 7 3.3.3信息删除流程 8 第4章 系统设…

周志华 《机器学习初步》 绪论

周志华 《机器学习初步》 绪论 Datawhale2022年12月组队学习 ✌ 文章目录周志华 《机器学习初步》 绪论一.机器学习二.典型的机器学习过程三.计算学习理论PAC模型思考两个问题问题性质角度计算要求的角度四.基本术语五.归纳偏好六.NFL定理哪个算法更好&#xff1f;NFL定理的寓意…

Codeforces Round #837 (Div. 2) A-C

A. Hossam and Combinatorics A题意&#xff1a; 给你n个数&#xff0c;让你求有多少个数对 并且 满足等于数组中最大的绝对值之差。 思路&#xff1a;直接找最大值和最小值&#xff0c;如果最大值和最小值不是一个&#xff0c;那就是最大数的数量乘最小值的数量乘2&#x…

前端基础(一)_前端页面构成

一、前端页面构成 1.HTML(Hypertext Markup Language) Html–超文本标记语言&#xff0c; 结构层由HTML标记语言创建的&#xff0c;负责页面的语义。&#xff08;它包括一系列标签&#xff0c;主要分为块标签和行标签、行内块标签三类&#xff09; 2.CSS(Cascading style sh…

绿色中国馆设计

目 录 1工程概况 1 1.1建筑设计部分 1 1.1.1设计依据 1 1.1.2设计内容、建筑面积、标高 1 1.1.3建筑空间构成 1 1.1.4采光和通风 1 1.1.5防火及安全 2 1.1.6各部分工程构造 2 1.2 结构设计部分 3 1.2.1基本资料 3 1.2.2结构形式和基础形式 3 1.2.3结构尺寸及采用的材料 4 1.2.4…