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为网页编辑
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对图片预处理的过程令我感到很神奇,这是之前从未接触到的,不断地去了解新方法、新技术为将来的学习和开发提供了新的思路。
最重要的是,在课程学习中接触到了机器学习这个领域,在学习中收获了很多新的思路和方法,这也指导我在工程实践项目中取得突破和进步。使我认识到,机器学习是未来几年应用比较广泛的方法,也激起了我在这一领域深入研究的兴趣。计划利用寒假期间,从算法原理到代码实现对机器学习进行深入学习。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
