2016年秋-网络程序设计 学习总结

2016年秋-网络程序设计 学习总结

对血常规检验报告的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为网页编辑

[python]  view plain  copy
  1. <span style="font-size:14px;">app = Flask(__name__, static_url_path="")  
  2. # 读取配置文件  
  3. app.config.from_object('config')  
  4. # 连接数据库,并获取数据库对象  
  5. db = MongoClient(app.config['DB_HOST'], app.config['DB_PORT']).test  
  6. # 将矫正后图片与图片识别结果(JSON)存入数据库  
  7. def save_file(file_str, f, report_data):  
  8.     content = StringIO(file_str)  
  9.     try:  
  10.         mime = Image.open(content).format.lower()  
  11.         print 'content of mime is:', mime  
  12.         if mime not in app.config['ALLOWED_EXTENSIONS']:  
  13.             raise IOError()  
  14.     except IOError:  
  15.         abort(400)  
  16.     c = dict(report_data=report_data, content=bson.binary.Binary(content.getvalue()), filename=secure_filename(f.name),  
  17.              mime=mime)  
  18.     db.files.save(c)  
  19.     return c['_id'], c['filename']  
  20. @app.route('/', methods=['GET''POST'])  
  21. def index():  
  22.     return redirect('/index.html')</span>  

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

[python]  view plain  copy
  1. <span style="font-size:14px;">import cv2  
  2. def  digitsimg(src):  
  3.       
  4.     #灰度化  
  5.     img_gray = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)  
  6.     #Otsu thresholding 二值化  
  7.     ret,result= cv2.threshold(img_gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)  
  8.     #腐蚀去除一些小的点  
  9.     kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,2))  
  10.     eroded = cv2.erode(result,kernel)  
  11.     #将结果放大便于识别  
  12.     result = cv2.resize(result,(128,128),interpolation=cv2.INTER_CUBIC)  
  13.     #腐蚀去除放大后的一些小的点  
  14.     eroded = cv2.erode(result,kernel)  
  15.     #膨胀使数字更饱满  
  16.     result = cv2.dilate(eroded,kernel)  
  17.     #直方图均衡化使图像更清晰  
  18.     cv2.equalizeHist(result)  
  19.     #中值滤波去除噪点  
  20.     result = cv2.medianBlur(result,5)  
  21.     return result</span>  

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

[python]  view plain  copy
  1. <span style="font-size:14px;">    def perspect(self, param=default):  
  2.         #载入参数  
  3.         gb_param = param[0#必须是奇数  
  4.         canny_param_upper = param[1]  
  5.         canny_param_lower = param[2]  
  6.         ref_lenth_multiplier = param[3]  
  7.         ref_close_multiplier = param[4]  
  8.         kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(33))  
  9.         # 载入图像,灰度化,开闭运算,描绘边缘  
  10.           
  11.         img_sp = self.img.shape  
  12.         ref_lenth = img_sp[0] * img_sp[1] * ref_lenth_multiplier  
  13.         img_gray = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)  
  14.         img_gb = cv2.GaussianBlur(img_gray, (gb_param, gb_param), 0)  
  15.         closed = cv2.morphologyEx(img_gb, cv2.MORPH_CLOSE, kernel)  
  16.         opened = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel)  
  17.         edges = cv2.Canny(opened, canny_param_lower , canny_param_upper)  
  18.         # 调用findContours提取轮廓  
  19.         contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  
  20. </span>  

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

[python]  view plain  copy
  1. <span style="font-size:14px;">    def filter(self, param=default):  
  2.         if self.PerspectiveImg is None:  
  3.             self.PerspectivImg = self.perspect(param)  
  4.             if self.PerspectiveImg is None:  
  5.                 return None  
  6.         img = Image.open(self.output_path + 'region.jpg')  
  7.         if not(classifier.isReport(img)):  
  8.             print "it is not a is Report!",classifier.isReport(self.PerspectiveImg)  
  9.             return None  
  10.         try:  
  11.             Image.fromarray(self.PerspectivImg)  
  12.         except Exception:  
  13.             return None  
  14.         return Image.fromarray(self.PerspectivImg)</span>  

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

[python]  view plain  copy
  1. <span style="font-size:14px;">    def autocut(self, num, param=default):  
  2.         if self.PerspectiveImg is None:  
  3.             self.PerspectivImg = self.filter(param)  
  4.         # 仍然是空,说明不是报告  
  5.         if self.PerspectiveImg is None:  
  6.             return -1  
  7.         #输出年龄  
  8.         img_age = self.PerspectiveImg[15 : 70585 : 690]  
  9.         cv2.imwrite(self.output_path + 'age.jpg', img_age)  
  10.         #输出性别  
  11.         img_gender = self.PerspectiveImg[15 : 58365 : 420]  
  12.         cv2.imwrite(self.output_path + 'gender.jpg', img_gender)  
  13.         #输出时间  
  14.         img_time = self.PerspectiveImg[722 : 760430 : 630]  
  15.         cv2.imwrite(self.output_path + 'time.jpg', img_time)  
  16.         #转换后的图分辨率是已知的,所以直接从这个点开始读数据就可以了  
  17.         startpoint = [199132]  
  18.         vertical_lenth = 37  
  19.         lateral_lenth = 80</span>  

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

[python]  view plain  copy
  1. <span style="font-size:14px;">    def ocr(self, num):  
  2.         digtitsresult = []  
  3.         chiresult = []  
  4.         # 不是报告  
  5.         if self.autocut(num) == -1:  
  6.             return None  
  7.         # 识别  
  8.         def image_to_string(image, flag=True):  
  9.             if flag:  
  10.                 text = pytesseract.image_to_string(Image.fromarray(image), config='-psm 7 digits')  
  11.             else:  
  12.                 text = pytesseract.image_to_string(Image.fromarray(image), lang='chi_sim', config=' -psm 7 Bloodtest')  
  13.             return text  
  14.         # 读取图片  
  15.         def read(url):  
  16.             image = cv2.imread(url)  
  17.             return image  
  18.         # load json example  
  19.         with open('bloodtestdata.json') as json_file:  
  20.             data = json.load(json_file)  
  21.         # 识别检测项目编号及数字  
  22.         for i in range(num):  
  23.             item = read('temp_pics/p' + str(i) + '.jpg')  
  24.             item_num = classifier.getItemNum(item)  
  25.             image = read('temp_pics/data' + str(i) + '.jpg')  
  26.             image = imgproc.digitsimg(image)  
  27.             digtitstr = image_to_string(image)  
  28.             digtitstr = digtitstr.replace(" "'')  
  29.             digtitstr = digtitstr.replace("-"'')  
  30.             digtitstr = digtitstr.strip(".")  
  31.             data['bloodtest'][item_num]['value'] = digtitstr  
  32.         json_data = json.dumps(data,ensure_ascii=False,indent=4)  
  33.         return json_data</span>  

切割后的数据:



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

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

[python]  view plain  copy
  1. <span style="font-size:14px;">    x_sex = tf.placeholder("float", [None, n_input])  
  2.     y_sex = tf.placeholder("float", [None, n_classes_sex])  
  3.   
  4.     def multilayer_perceptron_sex(x_sex, weights_sex, biases_sex):  
  5.         # Hidden layer with RELU activation  
  6.         layer_1 = tf.add(tf.matmul(x_sex, weights_sex['h1']), biases_sex['b1'])  
  7.         layer_1 = tf.nn.relu(layer_1)  
  8.         # Hidden layer with RELU activation  
  9.         layer_2 = tf.add(tf.matmul(layer_1, weights_sex['h2']), biases_sex['b2'])  
  10.         layer_2 = tf.nn.relu(layer_2)  
  11.         # Output layer with linear activation  
  12.         out_layer = tf.matmul(layer_2, weights_sex['out']) + biases_sex['out']  
  13.         return out_layer  
  14.   
  15.     weights_sex = {  
  16.         'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1_sex])),  
  17.         'h2': tf.Variable(tf.random_normal([n_hidden_1_sex, n_hidden_2_sex])),  
  18.         'out': tf.Variable(tf.random_normal([n_hidden_2_sex, n_classes_sex]))  
  19.     }  
  20.     biases_sex = {  
  21.         'b1': tf.Variable(tf.random_normal([n_hidden_1_sex])),  
  22.         'b2': tf.Variable(tf.random_normal([n_hidden_2_sex])),  
  23.         'out': tf.Variable(tf.random_normal([n_classes_sex]))  
  24.     }  
  25.     pred_sex = multilayer_perceptron_sex(x_sex, weights_sex, biases_sex)</span>  

模型训练

[python]  view plain  copy
  1. <span style="font-size:14px;"># 激活计算图  
  2. sess.run(init_op)  
  3. # 启动队列  
  4. threads = tf.train.start_queue_runners(sess=sess)  
  5. # 迭代次数 = 10000  
  6. for i in range(10000):  
  7.     # batch  
  8.     image, label = sess.run([img_batch, label_batch])  
  9.     # 输出局部正确率  
  10.     if i % 100 == 0:  
  11.         train_accuracy = accuracy.eval(feed_dict={x: image, y_:dense_to_one_hot(label)})  
  12.         print("step %d, training accuracy %g" % (i, train_accuracy))  
  13.         result = sess.run(merged,feed_dict={x:image,y_:dense_to_one_hot(label)})  
  14.         writer.add_summary(result,i)  
  15.     train_step.run(feed_dict={x: image, y_: dense_to_one_hot(label)})  
  16. # 加载测试集  
  17. test_img, test_label = sess.run([test_img_batch, test_label_batch])  
  18. # 输出整体正确率  
  19. print("test accuracy %g" % accuracy.eval(feed_dict={x: test_img, y_: dense_to_one_hot(test_label)}))  
  20. # 保存模型  
  21. save_path = saver.save(sess, cwd + "/ckpt_sex/sex.ckpt", write_meta_graph=None)  
  22. print("Model saved in file: %s" % save_path)</span>  

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

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

[python]  view plain  copy
  1. <span style="font-size:14px;">saver.restore(sess, "./model.ckpt")  
  2. print ("load model success!")  
  3. p_sex = sess.run(pred_sex, feed_dict={x_sex: data_predict})  
  4. p_age = sess.run(pred_age, feed_dict={x_age: data_predict})</span>  

收获与感悟

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值