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

《网络程序设计》署名博客

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

目录

  • 课程学习心得总结
    • 一图像处理算法
    • 二机器学习算法
    • 三Web相关
  • commitpr
    • 109 报告展示页面接受
    • 165 提升预测准确度拒绝
      • 数据预处理去均值归一化
      • 简化读取数据方式
    • 216 将A3集成到A2中接受
    • 245 将用户修正的数值更新到数据库中未处理
  • 辅助诊断系统
    • 版本库URL
    • 安装运行方法
      • 运行环境
      • 运行
      • Demo过程截图


课程学习心得总结

一、图像处理算法

预处理

在获取到上传的血常规化验单图片后,项目中对其进行了预处理,作用主要是为了减小噪声,为后边的识别算法服务,在这里主要用到了以下两个方法:

a)高斯平滑

img_gb = cv2.GaussianBlur(img_gray, (gb_param, gb_param), 0)

b)腐蚀、膨胀

closed = cv2.morphologyEx(img_gb, cv2.MORPH_CLOSE, kernel)
opened = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel)

线段检测

为了对图片各个数值所在的区域进行定位,这里需要检测出图片中比较明显的标识,3条黑线,然后利用这三条线对整张图片进行标定。主要用到了以下3个步骤:

a)Canny边缘检测

edges = cv2.Canny(opened, canny_param_lower , canny_param_upper)

b)轮廓提取

contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

c)求最小外接矩形

def getbox(i):
            rect = cv2.minAreaRect(contours[i])
            box = cv2.cv.BoxPoints(rect)
            box = np.int0(box)
            return box

OCR

这里主要利用OCR对血常规报告中的字符进行识别,得到具体的数值,用于后续的预测。其中步骤主要是根据上边求得的三条线段对图片进行透射变换,根据标定好的像素位置,利用pytesseract进行字符识别。

a)透射变换

#设定透视变换的矩阵
points = np.array([[line_upper[0][0], line_upper[0][1]], [line_upper[1][0], line_upper[1][1]], 
                [line_lower[0][0], line_lower[0][1]], [line_lower[1][0], line_lower[1][1]]],np.float32)
standard = np.array([[0,0], [1000, 0], [0, 760], [1000, 760]],np.float32)

#使用透视变换将表格区域转换为一个1000*760的图
PerspectiveMatrix = cv2.getPerspectiveTransform(points,standard)
self.PerspectiveImg = cv2.warpPerspective(self.img, PerspectiveMatrix, (1000, 760))

b)截图

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 = 37
        lateral_lenth = 80

        def getobjname(i, x, y):
            region_roi = self.PerspectiveImg[y : y+vertical_lenth, x : x+170]
            filename = self.output_path + 'p' + str(i) + '.jpg'
            cv2.imwrite(filename, region_roi)

        def getobjdata(i, x, y):
            region_roi = self.PerspectiveImg[y : y+vertical_lenth, x : x+lateral_lenth]
            filename = self.output_path + 'data' + str(i) + '.jpg'
            cv2.imwrite(filename, region_roi)

        #输出图片
        if num <= 13 and num > 0:
            for i in range(num):
                getobjname(int(i), 25, startpoint[1])
                getobjdata(int(i), startpoint[0], startpoint[1])
                startpoint[1] = startpoint[1] + 40
        elif num > 13:
            for i in range(13):
                getobjname(int(i), 25, startpoint[1])
                getobjdata(int(i), startpoint[0], startpoint[1])
                startpoint[1] = startpoint[1] + 40
            startpoint = [700, 135]
            for i in range(num-13):
                getobjname(int(i+13), 535, startpoint[1])
                getobjdata(int(i+13), startpoint[0], startpoint[1])
                startpoint[1] = startpoint[1] + 40


        #正常结束返回0
        return 0

c)pytesseract

# 识别检测项目编号及数字
        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'] = digtitstr
        json_data = json.dumps(data,ensure_ascii=False,indent=4)

二、机器学习算法

本门课程主要聚焦点是机器学习,尤其是深度学习,所以从中我主要初步了解了数据预处理、卷积神经网络、以及TensorFlow的初步使用。

1. 数据预处理

为了提高机器学习的准确程度,避免由于数据本身的数值不统一等对学习结果造成影响,需要对样本集进行一定的预处理。在本门课程中,我用到的预处理方法主要是去均值与归一化。
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第1张图片

a)去均值

去均值的具体做法是在每个样本上减去数据的统计平均值,去均值的意义主要在于扩大分类的效果。查看TensorFlow的MNIST源码时可以看到,程序中对每个像素点的像素值都减去了128,这就是去均值操作。

b)归一化

数据尺度归一化的原因是:数据中每个维度表示的意义不同,所以有可能导致该维度的变化范围不同,因此有必要将他们都归一化到一个固定的范围,一般情况下是归一化到[0 1]或者[-1 1]。同样在TensorFlow的MNIST源码中可以看到,去均值后,会将每点的像素值除以128,进行了归一化操作。
下边是我在本门课程中写的去均值与归一化代码,a是训练集,b是需要预测的一组样本。返回结果是去均值与归一化之后的样本b。

def normalized(a,b):
    for i in range(22):
        tmp = np.mean(a[:, i])
        a[:, i] = a[:, i] - tmp
        b[:, i] = b[:, i] - tmp
        if np.min(a[:, i]) != np.max(a[:, i]):
            b[:, i] = 2 * (b[:, i] - np.min(a[:, i])) / (np.max(a[:, i]) - np.min(a[:, i])) - 1
        else:
            b[:, i] = 0
    return b

2.卷积神经网络
a)神经网络

人工神经网络(Artificial Neural Network,即ANN ),是20世纪80 年代以来人工智能领域兴起的研究热点。它从信息处理角度对人脑神经元网络进行抽象, 建立某种简单模型,按不同的连接方式组成不同的网络。在工程与学术界也常直接简称为神经网络或类神经网络。神经网络是一种运算模型,由大量的节点(或称神经元)之间相互联接构成。每个节点代表一种特定的输出函数,称为激励函数(activation function)。每两个节点间的连接都代表一个对于通过该连接信号的加权值,称之为权重,这相当于人工神经网络的记忆。
常常会看到前馈神经网络(feedforward neural network)以及BP(back propagation)神经网络,个人的理解是这是同一种神经网络,都是普通的神经网络模型。前馈就是信号向前传递的意思。BP网络的前馈表现为输入信号从输入层(输入层不参加计算)开始,每一层的神经元计算出该层各神经元的输出并向下一层传递直到输出层计算出网络的输出结果,前馈只是用于计算出网络的输出,不对网络的参数进行调整。误差反向传播用于训练时网络权值和阈值的调整。网络前向传播计算出来的结果与实际的结果存在误差,在离线训练时,这时网络采用批量训练方法计算出整个样本数据的总误差,然后从输出层开始向前推,一般采用梯度下降法逐层求出每一层神经元的阈值和权值的调增量,循环迭代到网络参数符合要求停止。
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第2张图片

b)卷积神经网络概述

使用浅层的神经网络处理高维的数据或大尺寸的图片时,由于层与层之间是全连接的,就会导致网络中需要训练的参数个数很大,以致于无法训练。为了避免这个问题,一方面可以靠一些先验的经验对图片或者高维数据的特征进行选取后,再输入神经网络中,这样子可能会忽视掉一些特征,而且也比较依赖于设计者的经验。另一方面,可以对神经网络进行一些修改,使之在保持训练准确度的前提下,依然尽可能地保持高维数据的所有特征,这就是卷积神经网络。
卷积神经网络的主要是普通神经网络的变式,在层的功能和形式上做了一些变化,使之能够处理大尺寸的图片,而且不需要人为的提取特征。在卷积神经网络中,与普通神经网络的主要区别是增加了卷积层与池化层,一个典型的卷积神经网络模型如下图所示:
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第3张图片

c)卷积层

传统神经网络中,一个神经元会对整幅图都有权重,而这里是一个神经元只对一个窗口有权重,然后窗口会遍历整幅图,但是权重是共享的。这个一组固定权重和不同窗口内数据做内积的过程就是卷积,这样子就各个神经元分别关注了不同维度的信息。
卷积层带来的好处参数个数有所下降,提升训练的可执行性。
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第4张图片
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第5张图片

d)池化层

池化层主要作用是减少过拟合。过拟合在实际操作中很容易发生,主要是在训练中准确率很高,但在测试中准确率确很一般的情况,可能是因为样本较少,参数数量较大所致。所以这里设置一个池化层,主要是对前一层的数据进行最大值采样或平均值采样,然后降维,减少参数数量。
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第6张图片

e)LeNet-5

LeNet-5是一个典型的卷积神经网络模型,它是由Yann Lecun在Gradient-based learning applied to document recognition. Proceedings of the IEEE, november 1998中提出的,可以称为卷积神经网络的鼻祖。模型结构如图所示:
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第7张图片

从图中可以看到,LeNet-5是由卷积层1,下采样(池化)层2,卷积层3,下采样(池化)层4,卷积层5,全连接层6,输出层构成的。为了印证前边对卷积神经网络的理解,下边进行各层参数的推导:
卷积层1的神经元个数是6,卷积窗口大小为5*5,滑动步长为1,不采用补零,所以当输入1张32*32的图片后,经过卷积层1,得到6张28*28的feature maps。
下采样层2的窗口大小为2*2,滑动步长为2,卷积层1的输出经过下采样层后,变为6张14*14的feature maps。
卷积层3的神经元个数是16,卷积窗口大小为5*5,滑动步长为1,不采用补零,所以当输入6张14*14的feature maps后,经过卷积层3,得到16张10*10的feature maps。
下采样层4的窗口大小为2*2,滑动步长为2,卷积层,3的输出经过下采样层后,变为16张5*5的feature maps。
卷积层5的神经元个数是120,卷积窗口大小为5*5,滑动步长为1,不采用补零,所以当输入16张5*5的feature maps后,经过卷积层5,得到120张1*1的feature maps。也就是120*1的向量
全连接层6的神经元个数为84,接受卷积层5的120*1的输入后,输出为84*1。
输出层的神经元个数为10,接受全连接层6的84*1的输入后,输出为10*1,即为一个one-hot矩阵,矩阵中的每个值代表了输入图片为对应数字的概率。

f)神经网络调参

调参在神经网络的训练中占了很大的比重,有各种各样的小tricks。在本门课程中,为了提高年龄、性别的预测准确度,本人初步尝试了一些基本的调参。主要包括数据预处理、网络结构、激活函数、损失函数、优化方法等。取得一定的准确度提升,但是还任重而道远。

3. 深度学习平台

为了实现上述的机器学习算法,需要选择一个深度学习的平台。在这里我选择的是TensorFlow。对于我们学习来说,TensorFlow的主要优点是文档齐全,更容易找到相关的demo和出现bug的解决方法。
在本课程中,学习了TensorFlow的基本使用,基本的使用流程如下:

a) 读取数据为ndarray类型

data = np.loadtxt(open("./data.csv","rb"),delimiter=",",skiprows=0)
tmp = normalized(data[:,2:])
tmp_label_sex = one_hot(data[:,0:1],data.shape[0])
train_label_sex = tmp_label_sex[:1858, :]
test_label_sex = tmp_label_sex[1858:, :]
train_data = tmp[:1858,:]
test_data = tmp[1858:,:]

b) 定义模型(各层结构,损失,优化方法)

x = tf.placeholder("float", [None, n_input])
y = tf.placeholder("float", [None, n_classes])
keep_prob = tf.placeholder("float")
def multilayer_perceptron(x, weights, biases):
    layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['b1'])
    layer_1 = tf.nn.relu(layer_1)
    layer_2 = tf.add(tf.matmul(layer_1, weights['h2']), biases['b2'])
    layer_2 = tf.nn.relu(layer_2)
    out_layer = tf.matmul(layer_2, weights['out']) + biases['out']
    return out_layer
weights = {
    'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])),
    'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])),
    'out': tf.Variable(tf.random_normal([n_hidden_2, n_classes]))
}
biases = {
    'b1': tf.Variable(tf.random_normal([n_hidden_1])),
    'b2': tf.Variable(tf.random_normal([n_hidden_2])),
    'out': tf.Variable(tf.random_normal([n_classes]))
}
pred = multilayer_perceptron(x, weights, biases)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

c) 训练

with tf.Session() as sess:
    sess.run(init)
    for epoch in range(2000):
        _, c = sess.run([optimizer, cost], feed_dict={x: train_data, y: train_label_sex})

d) 保存模型

saver = tf.train.Saver()
save_path = saver.save(sess, "./model_sex/sex.ckpt", write_meta_graph=None)

e) 恢复模型

saver.restore(sess1, "./model_sex/sex.ckpt")

f) 预测

p = sess1.run(pred, feed_dict={x: data_predict})

三、Web相关

这门课程名为《网络程序设计》,目标是完成一个Web系统,所以在这之中,除了项目的关注点机器学习,我还学到了一部分Web相关的知识。

Vue.js

Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件[1] 。
Vue.js 自身不是一个全能框架——它只聚焦于视图层。因此它非常容易学习,非常容易与其它库或已有项目整合。另一方面,在与相关工具和支持库一起使用时,Vue.js 也能完美地驱动复杂的单页应用。
在本项目中,利用Vue.js对数据进行绑定,以表格的左半边为例

data: {
    report_items_left: new Array(),
    report_items_right: new Array(),
},
for (var i = 0; i < json_data["bloodtest"].length; i++) {
    if(i<13){
        report.report_items_left.push({
            count: i+1,
            name: json_data.bloodtest[i]["name"],
            alias: json_data.bloodtest[i].alias,
            value: json_data.bloodtest[i].value,
            range: json_data.bloodtest[i].range,
            unit: json_data.bloodtest[i].unit
        });
    }
}
<table id= "table_left" class="table table-inverse table-hover table-bordered">
    <thead>
    <tr>
        <th> th>
        <th>检测项目th>
        <th>结果th>
        <th>参考范围th>
        <th>单位th>
    tr>
    thead>
    <tbody>
    <tr v-for="item in report_items_left">
        <td>{{ item.count }}td>
        <td>{{ item.name }}td>
        <td>
            <input type="text" v-model="item.value" class="form-control" placeholder="检测值" />
        td>
        <td>{{ item.range }}td>
        <td>{{ item.unit }}td>
    tr>
    tbody>
table>

然后当用户在界面修改后,因为已经绑定,只需要直接调用data,即可获取到相关值

data[i] = Number(this.report_items_left[i].value);

Flask

Flask是Python下的一个轻量级Web框架,主要用于处理前端的http请求。

首先在运行时启动服务器:

app = Flask(__name__, static_url_path="")
app.config.from_object('config')
app.run(host=app.config['SERVER_HOST'], port=app.config['SERVER_PORT'])

然后在前端利用Ajax就可以访问到后端的对应函数

url = 'report/' + url.split('/')[2];
$.ajax({
    url: url,
    success: function(data) {
        //对返回的data进行处理

在后端接受前端的http访问请求

@app.route('/report/')
def get_report(fid):
    try:
        file = db.files.find_one(bson.objectid.ObjectId(fid))

MongoDB

在本课程中,用到的数据库是MongoDB,主要用于将矫正后的图片与OCR识别结果存入数据库中

首先是打开服务器的时候连接数据库

db = MongoClient(app.config['DB_HOST'], app.config['DB_PORT']).test

在上传图片后,将校正后的图片以及识别到的各项数值存入数据库中

c = dict(report_data=report_data, content=bson.binary.Binary(content.getvalue()), filename=secure_filename(f.name),
         mime=mime)
db.files.save(c)

也可利用fid,进行结果查询

try:
    file = db.files.find_one(bson.objectid.ObjectId(fid))
    if file is None:
        raise bson.errors.InvalidId()
    print 'type before transform:\n', type(file['report_data'])
    report_data = bson.json_util.dumps(file['report_data'])

commit/pr

1. #109 报告展示页面(接受)

原本的表格是并没有分成两边,直接22行数据下来,老师在群里边说希望修改为图片的格式,便于比对,于是我将表格分成了左右两边,分别显示左右两边的数据

id= "table_left"class="table table-inverse table-hover table-bordered">
id= "table_right"class="table table-inverse table-hover table-bordered">
//先清空表格内容
$("#table_left  tr:not(:first)").empty();
$("#table_right  tr:not(:first)").empty();

for (var i = 0; i < json_data["bloodtest"].length; i++) {
    if(i<13){
        report.report_items_left.push({
            count: i+1,
            name: json_data.bloodtest[i]["name"],
            alias: json_data.bloodtest[i].alias,
            value: json_data.bloodtest[i].value,
            range: json_data.bloodtest[i].range,
            unit: json_data.bloodtest[i].unit
        });
    }
    else {
        report.report_items_right.push({
            count: i+1,
            name: json_data.bloodtest[i]["name"],
            alias: json_data.bloodtest[i].alias,
            value: json_data.bloodtest[i].value,
            range: json_data.bloodtest[i].range,
            unit: json_data.bloodtest[i].unit
        });
    }

2. #165 提升预测准确度(拒绝)

数据预处理—去均值、归一化

这里对样本数据进行了预处理,提高了预测的准确度。

预处理部分的代码如下:

def normalized(a):
    for i in range(n_input):
        a[:, i] = a[:, i] - np.mean(a[:, i])
        if np.min(a[:, i]) != np.max(a[:, i]):
            a[:, i] = 2 * (a[:, i] - np.min(a[:, i])) / (np.max(a[:, i]) - np.min(a[:, i])) - 1
        else:
            a[:, i] = 0
    return a

简化读取数据方式

本项目数据量较低,不需要队列,batch之类的操作,可以直接直接以ndarray格式读取样本的数据。

原本的代码为:

# 读取数据

def write_to_tensor(name, csv_name):

    if os.path.exists(name):

        return

    csv_file = csv.reader(open(cwd + '/' + csv_name, 'rb'))

    writer = tf.python_io.TFRecordWriter(name)

    for line in csv_file:

        if not line:

            break

        if len(line) is not 29:

            continue

        index = [int(line[1])]

        # 提取从第4列到第28列

        data = map(float, line)[3:29]

        # 注意list类型, Feature或FeatureList等

        example = tf.train.Example(features=tf.train.Features(feature={

            "label": tf.train.Feature(int64_list=tf.train.Int64List(value=index)),

            'content': tf.train.Feature(float_list=tf.train.FloatList(value=data))

        }))

        print data, index

        # 序列化并写入tfrecord

        writer.write(example.SerializeToString())

    writer.close()





# 读取数据并解析

def read_and_decode(filename):

    # 根据文件名生成一个队列

    filename_queue = tf.train.string_input_producer([filename])

    # 创建tfrecord reader

    reader = tf.TFRecordReader()

    # 返回文件名和文件

    _, serialized_example = reader.read(filename_queue)

    # 读取时要注意fix shape

    features = tf.parse_single_example(serialized_example,

                                       features={

                                           'label': tf.FixedLenFeature([], tf.int64),

                                           'content': tf.FixedLenFeature([26], tf.float32),

                                       })

    data = tf.cast(features['content'], tf.float32)

    label = tf.cast(features['label'], tf.int32)

    return data, label


 write_to_tensor('train_sex.tfrecords', 'train.csv')

    write_to_tensor('predict_sex.tfrecords', 'predict.csv')

    # 读取tfrecord

    train_img, train_label = read_and_decode("train_sex.tfrecords")

    test_img, test_label = read_and_decode("predict_sex.tfrecords")

经过简化后,读取数据部分的代码为:

data = np.loadtxt(open("./data.csv","rb"),delimiter=",",skiprows=0)
tmp = normalized(data[:,2:])
tmp_label_sex = one_hot(data[:,0:1],data.shape[0])
train_label_sex = tmp_label_sex[:1858, :]
test_label_sex = tmp_label_sex[1858:, :]
train_data = tmp[:1858,:]
test_data = tmp[1858:,:]

但由于准确率未达到70%,以及使用了数据集版本与线上的稍有不同,本次pull request请求被拒绝。

3. #216 将A3集成到A2中(接受)

3.1 根据图片中的项,选取了测试数据集中的对应项,按照图片的顺序,重新进行了模型的训练

3.2 前后端传值


test: function(event) {

    data = [];
    for(var i=0;i<13;i++)
        data[i] = Number(this.report_items_left[i].value);
    for(var i=0;i<9;i++)
        data[13+i] = Number(this.report_items_right[i].value);

    var data = {
        data: JSON.stringify(({
            "value":data
        }))
    };


    $.ajax({
        url: "/predict",
        type: 'POST',
        data: data,
        success: function(data) {
            var obj = JSON.parse(data)
            if(obj.sex == 1)
                var sexsex = "男";
            else
                var sexsex = "女"
            alert("性别:" + sexsex + "\n年龄:" + obj.age);


        }
    })
}


@app.route("/predict", methods=['POST'])
def predict():
    print ("predict now!")

    data = json.loads(request.form.get('data'))
    ss = data['value']
    arr = numpy.array(ss)
    arr = numpy.reshape(arr, [1, 22])

    sex, age = tf_predict.predict(arr)

    result = {
        "sex":sex,
        "age":int(age)
    }

    return json.dumps(result)

3.3 预测

def normalized(a,b):
    for i in range(22):
        tmp = np.mean(a[:, i])

        a[:, i] = a[:, i] - tmp
        b[:, i] = b[:, i] - tmp


        if np.min(a[:, i]) != np.max(a[:, i]):
            b[:, i] = 2 * (b[:, i] - np.min(a[:, i])) / (np.max(a[:, i]) - np.min(a[:, i])) - 1
        else:
            b[:, i] = 0
    return b

def predict(data_predict):
    tf.reset_default_graph()
    data_nor = np.loadtxt(open("./data.csv", "rb"), delimiter=",", skiprows=0)

    data_predict = normalized(data_nor[:, 2:], data_predict)

    '''
        参数
        '''
    learning_rate = 0.005
    display_step = 100
    n_input = 22

    n_hidden_1_age = 32
    n_hidden_2_age = 16
    n_classes_age = 1

    n_hidden_1_sex = 16
    n_hidden_2_sex = 8
    n_classes_sex = 2
    data = np.loadtxt(open("./data.csv", "rb"), delimiter=",", skiprows=0)
    '''
    建立年龄模型
    '''
    x_age = tf.placeholder("float", [None, n_input])
    y_age = tf.placeholder("float", [None, n_classes_age])

    def multilayer_perceptron_age(x_age, weights_age, biases_age):
        # Hidden layer with RELU activation
        layer_1 = tf.add(tf.matmul(x_age, weights_age['h1']), biases_age['b1'])
        layer_1 = tf.nn.relu(layer_1)
        # Hidden layer with RELU activation
        layer_2 = tf.add(tf.matmul(layer_1, weights_age['h2']), biases_age['b2'])
        layer_2 = tf.nn.relu(layer_2)
        # Output layer with linear activation
        out_layer = tf.matmul(layer_2, weights_age['out']) + biases_age['out']
        return out_layer

    weights_age = {
        'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1_age])),
        'h2': tf.Variable(tf.random_normal([n_hidden_1_age, n_hidden_2_age])),
        'out': tf.Variable(tf.random_normal([n_hidden_2_age, n_classes_age]))
    }
    biases_age = {
        'b1': tf.Variable(tf.random_normal([n_hidden_1_age])),
        'b2': tf.Variable(tf.random_normal([n_hidden_2_age])),
        'out': tf.Variable(tf.random_normal([n_classes_age]))
    }
    pred_age = multilayer_perceptron_age(x_age, weights_age, biases_age)
    '''
    建立性别模型
    '''
    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 activation
        layer_1 = tf.add(tf.matmul(x_sex, weights_sex['h1']), biases_sex['b1'])
        layer_1 = tf.nn.relu(layer_1)
        # Hidden layer with RELU activation
        layer_2 = tf.add(tf.matmul(layer_1, weights_sex['h2']), biases_sex['b2'])
        layer_2 = tf.nn.relu(layer_2)
        # Output layer with linear activation
        out_layer = tf.matmul(layer_2, weights_sex['out']) + biases_sex['out']
        return out_layer

    weights_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)

    '''
    共同的初始化
    '''
    saver = tf.train.Saver()
    init = tf.global_variables_initializer()
    with tf.Session() as sess:
        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})
    if p_sex[0][0] > p_sex[0][1]:
        sex_result = 1
    else:
        sex_result = 0

    age_result = p_age[0][0] * 50 +50

    return sex_result,age_result

4. #245 将用户修正的数值更新到数据库中(未处理)

在预测中,将该份报告在数据库中的id一并传回后端,用于更新时查询

url = $("#filtered-report").attr("src");
                if (url == null) {
                    alert("请上传报告");
                    return;
                }
                url = 'predict/' + url.split('/')[2];
                $.ajax({
                    url: "/predict",
                    url: url,
@app.route('/predict/', methods=['POST'])
def predict(fid):

用户在前端对识别到的数值更正后,进行预测,把数值的更正更新到此前生成的数据库记录中

def update_report(fid,ss):
    # load json example
    with open('bloodtestdata.json') as json_file:
        data = json.load(json_file)
    for i in range(22):
        data['bloodtest'][i]['value'] = ss[i]
    json_data = json.dumps(data, ensure_ascii=False, indent=4)
    db.files.update_one({
        '_id': bson.objectid.ObjectId(fid)}, {
        '$set': {
            'report_data': json_data
        }
    }, upsert=False)
    file = db.files.find_one(bson.objectid.ObjectId(fid))
    report_data = bson.json_util.dumps(file['report_data'])
    print report_data

辅助诊断系统

版本库URL

https://coding.net/u/lys19920914/p/np2016/git

安装运行方法

运行环境

# 安装numpy,
sudo apt-get install python-numpy # http://www.numpy.org/
# 安装opencv
sudo apt-get install python-opencv # http://opencv.org/
# 安装OCR和预处理相关依赖
sudo apt-get install tesseract-ocr
sudo pip install pytesseract
sudo apt-get install python-tk
sudo pip install pillow
# 安装Flask框架、mongo
sudo pip install Flask
sudo apt-get install mongodb # 如果找不到可以先sudo apt-get update
sudo service mongodb started
sudo pip install pymongo

运行

cd  BloodTestReportOCR
python view.py # upload图像,在浏览器打开http://yourip:8080

Demo过程截图

首先定位到BloodTestReportOCR中,输入python view.py
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第8张图片
然后打开浏览器,输入localhost:8080
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第9张图片
上传图片后得到矫正后的图片如图
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第10张图片
点击“生成报告”,得到OCR的结果如图所示
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第11张图片
点击“predict”,得到预测结果
2016年,网络程序设计,ustc se,SA16225161,梁昱森_第12张图片

你可能感兴趣的:(2016年,网络程序设计,ustc se,SA16225161,梁昱森)