对血常规检验报告的OCR识别、深度学习与分析

项目背景

2016是人工智能爆发的一年,各种层出不穷的新技术、新概念让人眼花缭乱。医疗保健领域中的大数据在改善患者护理以及最终实现合理成本方面具有巨大的潜力。大数据时代的出现给统计机器学习提供了更多的机遇,因为海量的数据更加需要统计、抽样的方法。

本学习孟宁老师的网络程序设计课程内容为基于神经网络的医疗辅助诊断专家系统设计,我和同学们都满怀兴趣和激情加入了课程的学习。同学们在分享讨论中,对机器学习的相关算法、图片和数据的处理方法都进行了学习和了解,这样的学习方式是高效且充满意义的。同时,对课程项目内容也不断地充实、完善,在此进行回顾和总结。

项目目标

能够将手机拍摄的血常规检验报告图片预处理,并且实现图像识别,将检验结果输入到神经网络,进行性别和年龄的预测。对项目进行展望,可以通过更加丰富的检验数据,基于更加完善的深度学习模型,对对象的健康状况给出预测。

课程中的贡献与学习成果

课程贡献:

与同学们分享了机器学习中的决策树算法,并进行了具体应用的演示。

学习成果:

(1)通过参与同学们的分享和讨论,对机器学习的方法有了基础地学习和认识。学习了常见的机器学习算法(SVM、随机森林、决策树、感知机、Adaboost等)的原理和特性。感受到了opencv在图像预处理方面的强大功能,学习了本项目中对图片进行处理的方法原理,掌握了利用ocr方法进行图像文本识别的方法。

(2)在对神经网络的学习中,掌握了BP神经网络的算法原理。通过同学们的分享交流,对深度学习的常用框架caffe、tensorflow、MxNet等有了更进一步的了解。其中,对caffe框架进行了较为深入的研究,受到启发,在工程实践项目中采用caffe实现了图像多目标检测任务。

(3)在认真聆听同学们对各种算法的介绍中,开拓了眼界,能够主动思考比较各类算法和框架的有点与不足,考虑何种算法更适合应用在何种场合,产生了对机器学习的浓厚兴趣。

(4)在学习中,能够与老师和同学们步调保持一致,逐步把项目完善。最终能够成功运行项目Demo,并在同学们的指导和帮助下,能够理解项目代码。

项目部署和Demo演示

项目地址:对血常规检验报告的OCR识别、深度学习与分析

安装numpy

$ sudo apt-get install Python-numpy

安装Opencv

$ sudo apt-get install python-opencv

安装pytesseract

$ sudo apt-get install tesseract-ocr

$ sudo pip install pytesseract

$ sudo apt-get install python-tk

$ sudo pip install pillow

安装Flask框架

$ sudo pip install Flask

安装mongodb

$ sudo apt-get install mongodb # 如果提示no modulename mongodb, 先执行sudo apt-get update

$ sudo service mongodb started

$ sudo pip install pymongo

安装Tensorflow

$ sudo apt-get install python-numpy

$ sudo apt-get install python-imaging

$ pip install --upgradehttps://storage.googleapis.com/tensorflow/Linux/cpu/tensorflow-0.12.0rc0-cp27-none-linux_x86_64.whl

运行

$ git clone https://git.coding.net/mengning/np2016.git

$ cd np2016

$ cd BloodTestReportOCR

$ python view.py # upload图像,在浏览器打开http://localhost:8080

访问 localhost:8080

选择报告单图片上传

点击生成报告

点击predict

设计分析

1.Web模块设计

采用flask框架,json部分用来传输数据,index.html为网页编辑

app = Flask(__name__, static_url_path="")
# 读取配置文件
app.config.from_object('config')
# 连接数据库,并获取数据库对象
db = MongoClient(app.config['DB_HOST'], app.config['DB_PORT']).test
# 将矫正后图片与图片识别结果(JSON)存入数据库
def save_file(file_str, f, report_data):content = StringIO(file_str)try:mime = Image.open(content).format.lower()print 'content of mime is:', mimeif mime not in app.config['ALLOWED_EXTENSIONS']:raise IOError()except IOError:abort(400)c = dict(report_data=report_data, content=bson.binary.Binary(content.getvalue()), filename=secure_filename(f.name),mime=mime)db.files.save(c)return c['_id'], c['filename']
@app.route('/', methods=['GET', 'POST'])
def index():return redirect('/index.html')

2.opencv图片预处理,将检验报告图片进行预处理并切割,为ocr识别做准备

import cv2
def  digitsimg(src):#灰度化img_gray = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)#Otsu thresholding 二值化ret,result= cv2.threshold(img_gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)#腐蚀去除一些小的点kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,2))eroded = cv2.erode(result,kernel)#将结果放大便于识别result = cv2.resize(result,(128,128),interpolation=cv2.INTER_CUBIC)#腐蚀去除放大后的一些小的点eroded = cv2.erode(result,kernel)#膨胀使数字更饱满result = cv2.dilate(eroded,kernel)#直方图均衡化使图像更清晰cv2.equalizeHist(result)#中值滤波去除噪点result = cv2.medianBlur(result,5)return result

3.perspect函数用于透视image,他会缓存一个透视后的opencv numpy矩阵,并返回该矩阵

    def perspect(self, param=default):#载入参数gb_param = param[0] #必须是奇数canny_param_upper = param[1]canny_param_lower = param[2]ref_lenth_multiplier = param[3]ref_close_multiplier = param[4]kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))# 载入图像,灰度化,开闭运算,描绘边缘img_sp = self.img.shaperef_lenth = img_sp[0] * img_sp[1] * ref_lenth_multiplierimg_gray = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)img_gb = cv2.GaussianBlur(img_gray, (gb_param, gb_param), 0)closed = cv2.morphologyEx(img_gb, cv2.MORPH_CLOSE, kernel)opened = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel)edges = cv2.Canny(opened, canny_param_lower , canny_param_upper)# 调用findContours提取轮廓contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

4. filter函数返回img经过透视过后的PIL格式的Image对象,如果缓存中有PerspectivImg则直接使用,没有先进行透视过滤失败则返回None

    def filter(self, param=default):if self.PerspectiveImg is None:self.PerspectivImg = self.perspect(param)if self.PerspectiveImg is None:return Noneimg = Image.open(self.output_path + 'region.jpg')if not(classifier.isReport(img)):print "it is not a is Report!",classifier.isReport(self.PerspectiveImg)return Nonetry:Image.fromarray(self.PerspectivImg)except Exception:return Nonereturn Image.fromarray(self.PerspectivImg)

5. autocut函数用于剪切ImageFilter中的img成员,剪切之后临时图片保存在out_path,如果剪切失败,返回-1,成功返回0

    def autocut(self, num, param=default):if self.PerspectiveImg is None:self.PerspectivImg = self.filter(param)# 仍然是空,说明不是报告if self.PerspectiveImg is None:return -1#输出年龄img_age = self.PerspectiveImg[15 : 70, 585 : 690]cv2.imwrite(self.output_path + 'age.jpg', img_age)#输出性别img_gender = self.PerspectiveImg[15 : 58, 365 : 420]cv2.imwrite(self.output_path + 'gender.jpg', img_gender)#输出时间img_time = self.PerspectiveImg[722 : 760, 430 : 630]cv2.imwrite(self.output_path + 'time.jpg', img_time)#转换后的图分辨率是已知的,所以直接从这个点开始读数据就可以了startpoint = [199, 132]vertical_lenth = 37lateral_lenth = 80

6.ocr函数用于对img进行ocr识别,他会先进行剪切,之后进一步做ocr识别,返回一个json对象如果剪切失败,则返回None

    def ocr(self, num):digtitsresult = []chiresult = []# 不是报告if self.autocut(num) == -1:return None# 识别def image_to_string(image, flag=True):if flag:text = pytesseract.image_to_string(Image.fromarray(image), config='-psm 7 digits')else:text = pytesseract.image_to_string(Image.fromarray(image), lang='chi_sim', config=' -psm 7 Bloodtest')return text# 读取图片def read(url):image = cv2.imread(url)return image# load json examplewith open('bloodtestdata.json') as json_file:data = json.load(json_file)# 识别检测项目编号及数字for i in range(num):item = read('temp_pics/p' + str(i) + '.jpg')item_num = classifier.getItemNum(item)image = read('temp_pics/data' + str(i) + '.jpg')image = imgproc.digitsimg(image)digtitstr = image_to_string(image)digtitstr = digtitstr.replace(" ", '')digtitstr = digtitstr.replace("-", '')digtitstr = digtitstr.strip(".")data['bloodtest'][item_num]['value'] = digtitstrjson_data = json.dumps(data,ensure_ascii=False,indent=4)return json_data

切割后的数据:

利用TensorFlow框架进行模型训练和预测:

模型定义(以年龄属性为例)

    x_sex = tf.placeholder("float", [None, n_input])y_sex = tf.placeholder("float", [None, n_classes_sex])def multilayer_perceptron_sex(x_sex, weights_sex, biases_sex):# Hidden layer with RELU activationlayer_1 = tf.add(tf.matmul(x_sex, weights_sex['h1']), biases_sex['b1'])layer_1 = tf.nn.relu(layer_1)# Hidden layer with RELU activationlayer_2 = tf.add(tf.matmul(layer_1, weights_sex['h2']), biases_sex['b2'])layer_2 = tf.nn.relu(layer_2)# Output layer with linear activationout_layer = tf.matmul(layer_2, weights_sex['out']) + biases_sex['out']return out_layerweights_sex = {'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1_sex])),'h2': tf.Variable(tf.random_normal([n_hidden_1_sex, n_hidden_2_sex])),'out': tf.Variable(tf.random_normal([n_hidden_2_sex, n_classes_sex]))}biases_sex = {'b1': tf.Variable(tf.random_normal([n_hidden_1_sex])),'b2': tf.Variable(tf.random_normal([n_hidden_2_sex])),'out': tf.Variable(tf.random_normal([n_classes_sex]))}pred_sex = multilayer_perceptron_sex(x_sex, weights_sex, biases_sex)

模型训练

# 激活计算图
sess.run(init_op)
# 启动队列
threads = tf.train.start_queue_runners(sess=sess)
# 迭代次数 = 10000
for i in range(10000):# batchimage, label = sess.run([img_batch, label_batch])# 输出局部正确率if i % 100 == 0:train_accuracy = accuracy.eval(feed_dict={x: image, y_:dense_to_one_hot(label)})print("step %d, training accuracy %g" % (i, train_accuracy))result = sess.run(merged,feed_dict={x:image,y_:dense_to_one_hot(label)})writer.add_summary(result,i)train_step.run(feed_dict={x: image, y_: dense_to_one_hot(label)})
# 加载测试集
test_img, test_label = sess.run([test_img_batch, test_label_batch])
# 输出整体正确率
print("test accuracy %g" % accuracy.eval(feed_dict={x: test_img, y_: dense_to_one_hot(test_label)}))
# 保存模型
save_path = saver.save(sess, cwd + "/ckpt_sex/sex.ckpt", write_meta_graph=None)
print("Model saved in file: %s" % save_path)

训练后产生模型文件model.ckpt.data-00000-of-00001和model.ckpt.index

调用训练好的模型进行预测

saver.restore(sess, "./model.ckpt")
print ("load model success!")
p_sex = sess.run(pred_sex, feed_dict={x_sex: data_predict})
p_age = sess.run(pred_age, feed_dict={x_age: data_predict})

收获与感悟

在这门课的学习过程中,虽然对项目所涉及到的工具和方法还没有达到精通的程度,但是收获是巨大的。

首先,在与同学们的分享交流中,让我体会到了分享的快乐。在课程的开始阶段,我与同学们分享了我对机器学习算法中决策树的理解和应用,在分享准备过程中也加深了我对知识的掌握程度。在其他同学分享知识和项目进展的过程中,也让我收获了之前没有涉及到的方法,对于我在项目中遇到的疑问也能够得到很好解答。这样的学习方式比自己闭门造车高效许多。

其次,项目中基于opencv对图片预处理的过程令我感到很神奇,这是之前从未接触到的,不断地去了解新方法、新技术为将来的学习和开发提供了新的思路。

最重要的是,在课程学习中接触到了机器学习这个领域,在学习中收获了很多新的思路和方法,这也指导我在工程实践项目中取得突破和进步。使我认识到,机器学习是未来几年应用比较广泛的方法,也激起了我在这一领域深入研究的兴趣。计划利用寒假期间,从算法原理到代码实现对机器学习进行深入学习。

2016年秋-网络程序设计 学习总结相关推荐

  1. 2016年,网络程序设计,ustc se,SA16225161,梁昱森

    <网络程序设计>署名博客 完成一篇署名博客,博客内容至少包括课程学习心得总结.通过commit/pr等说明自己的功劳和苦劳.提供自己的版本库URL并附上安装运行方法和Demo过程截图.其他 ...

  2. 神经网络程序设计学习心得

    神经网络程序设计学习心得 简枢 SB16225001   本学期有幸再次选择了孟宁老师的2016年秋-网络程序设计课程.该课程主要聚焦于神经网络程序设计,基于深度学习神经网络等机器学习技术实现一个医学 ...

  3. 2016学c语言用的软件下载,|C/C++程序设计学习与实验系统下载c2016版 - 欧普软件下载...

    C/C++程序设计学习与实验系统是为学习C语言和C++朋友推出的一款实验系统,包含入门指导.典型案列.函数算法.编程建议.学习经验等干货,还有常见错误信息解决方案,新增试题解析.自动评分,有需要的朋友 ...

  4. [渝粤教育] 西南科技大学 网络程序设计 在线考试复习资料

    网络程序设计--在线考试复习资料 一.单选题 1.Sng函数的作用是( ). A.将字符串转换为日期 B.将字符串转换为长整型 C.将字符串转换为布尔型 D.将数值转换为单精度型 2.数据库常用的函数 ...

  5. java面试题32:Java网络程序设计中,下列正确的描述是()

    java面试题32:Java网络程序设计中,下列正确的描述是() A:Java网络编程API建立在Socket基础之上 B:Java网络接口只支持tcP以及其上层协议 C:Java网络接口只支持UDP ...

  6. 关于如何学好网络 送给学习网络工程的学生

    一.拨开云雾 写这篇文章的时候,心有点胆突.毕竟, 只有仙人才能指路. 我?呵呵.....修行ing. 自己在学计算机的时候,就希望得高人指点.也曾问过,我怎么才能学好计算机这样的问题.现在看来,问这 ...

  7. 《开发者突击:精通ASP.NET AJAX网络程序设计》终于面世

    今天是我非常激动的日子,由自己第一次主编的图书<开发者突击:精通ASP.NET AJAX网络程序设计>终于与诸位读者见面了.本书由电子工作出版社于2008年7月下式出版发行,ISBN为97 ...

  8. 网络程序设计 Sockets

    关于Socket编程,在<Linux从入门到精通>里有简单的介绍,更详细的可以参考<UNIX网络编程 卷1:联网的API:套接字与XTI 第2版>清华影印版,其中还讲了线程(T ...

  9. 基于SSM的概念可视化程序设计学习系统 毕业设计-附源码021009

    SSM概念可视化程序设计学习系统 摘 要 随着计算机技术的发展,特别是计算机网络技术与数据库技术的发展,使用人们的生活与工作方式发生了很大的改观.网络技术的应用使得计算机之间通信.在线学习成为可能,而 ...

最新文章

  1. Python搭建Keras CNN模型破解网站验证码
  2. cap理论与分布式事务的解决方案
  3. 2020级HAUT新生周赛(四)@张承树专场
  4. 数据库连接字符串大全
  5. java swing http请求_JavaWeb核心编程之(三.5)HTTP请求和接受表单数据
  6. StyleAI:印象坐标-感情色彩量化/感情近邻关系
  7. Python运维-获取当前操作系统的各种信息
  8. 详解SMS下OSD2008
  9. 打印狗的健康值Java_嵌入式狗的JAVA之路 HTML 补课
  10. edge浏览器下载位置设置
  11. 从零开始学架构3 - 高可用篇
  12. 【正则表达式】正则表达式引发的惨案 回溯 超时 cpu 100
  13. day4-软件目录开发规范
  14. c语言里变量要求,c语言中要求对变量作强制定义的主要理由是什么?
  15. CANFD MCP2517FD 滤波ID设置例子
  16. 学计算机到35岁后转行容易吗,本人已经35岁了,转行学IT风险是不是很大?
  17. 垃圾小白羊的leetcode刷题记录6
  18. 珍藏绝版MTV全套 -《最动听的BEYOND
  19. Python爬虫网易云歌词及词频统计--(周杰伦top50)
  20. 智慧城市概述:算法与数据链接下的未来设想

热门文章

  1. 家用监控摄像头的清晰度如何选择
  2. 064_《Delphi7程序设计与开发技术大全》
  3. npm,node更新最新版本
  4. python语言的优势-Python语言的七大优势
  5. Activity跳转到Fragment
  6. 转行要趁早 !一个过来人的忠告~
  7. linux jad 反编译,使用Jad或JadClipse进行反编译
  8. 分析初识vue小案例
  9. postgres之窗口函数
  10. EPSON墨盒及打印机型号对照