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

完成一篇署名博客,博客内容至少包括课程学习心得总结、通过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 = 37lateral_lenth = 80def 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] + 40elif num > 13:for i in range(13):getobjname(int(i), 25, startpoint[1])getobjdata(int(i), startpoint[0], startpoint[1])startpoint[1] = startpoint[1] + 40startpoint = [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#正常结束返回0return 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'] = digtitstrjson_data = json.dumps(data,ensure_ascii=False,indent=4)

二、机器学习算法

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

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] - tmpb[:, i] = b[:, i] - tmpif 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])) - 1else:b[:, i] = 0return b

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

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

b)卷积神经网络概述

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

c)卷积层

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

d)池化层

池化层主要作用是减少过拟合。过拟合在实际操作中很容易发生,主要是在训练中准确率很高,但在测试中准确率确很一般的情况,可能是因为样本较少,参数数量较大所致。所以这里设置一个池化层,主要是对前一层的数据进行最大值采样或平均值采样,然后降维,减少参数数量。

e)LeNet-5

LeNet-5是一个典型的卷积神经网络模型,它是由Yann Lecun在Gradient-based learning applied to document recognition. Proceedings of the IEEE, november 1998中提出的,可以称为卷积神经网络的鼻祖。模型结构如图所示:

从图中可以看到,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/<fid>')
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行数据下来,老师在群里边说希望修改为图片的格式,便于比对,于是我将表格分成了左右两边,分别显示左右两边的数据

<table id= "table_left" class="table table-inverse table-hover table-bordered">
<table 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])) - 1else:a[:, i] = 0return a

简化读取数据方式

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

原本的代码为:

# 读取数据def write_to_tensor(name, csv_name):if os.path.exists(name):returncsv_file = csv.reader(open(cwd + '/' + csv_name, 'rb'))writer = tf.python_io.TFRecordWriter(name)for line in csv_file:if not line:breakif len(line) is not 29:continueindex = [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# 序列化并写入tfrecordwriter.write(example.SerializeToString())writer.close()# 读取数据并解析def read_and_decode(filename):# 根据文件名生成一个队列filename_queue = tf.train.string_input_producer([filename])# 创建tfrecord readerreader = tf.TFRecordReader()# 返回文件名和文件_, serialized_example = reader.read(filename_queue)# 读取时要注意fix shapefeatures = 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, labelwrite_to_tensor('train_sex.tfrecords', 'train.csv')write_to_tensor('predict_sex.tfrecords', 'predict.csv')# 读取tfrecordtrain_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 前后端传值

<button type="button" v-on:click="test()" class="btn btn-primary btn-lg btn-block">predict</button>
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 = "男";elsevar 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] - tmpb[:, i] = b[:, i] - tmpif 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])) - 1else:b[:, i] = 0return bdef 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.005display_step = 100n_input = 22n_hidden_1_age = 32n_hidden_2_age = 16n_classes_age = 1n_hidden_1_sex = 16n_hidden_2_sex = 8n_classes_sex = 2data = 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 activationlayer_1 = tf.add(tf.matmul(x_age, weights_age['h1']), biases_age['b1'])layer_1 = tf.nn.relu(layer_1)# Hidden layer with RELU activationlayer_2 = tf.add(tf.matmul(layer_1, weights_age['h2']), biases_age['b2'])layer_2 = tf.nn.relu(layer_2)# Output layer with linear activationout_layer = tf.matmul(layer_2, weights_age['out']) + biases_age['out']return out_layerweights_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 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)'''共同的初始化'''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 = 1else:sex_result = 0age_result = p_age[0][0] * 50 +50return 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/<fid>', methods=['POST'])
def predict(fid):

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

def update_report(fid,ss):# load json examplewith 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

然后打开浏览器,输入localhost:8080

上传图片后得到矫正后的图片如图

点击“生成报告”,得到OCR的结果如图所示

点击“predict”,得到预测结果

2016年,网络程序设计,ustc se,SA16225161,梁昱森相关推荐

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

    对血常规检验报告的OCR识别.深度学习与分析 项目背景 2016是人工智能爆发的一年,各种层出不穷的新技术.新概念让人眼花缭乱.医疗保健领域中的大数据在改善患者护理以及最终实现合理成本方面具有巨大的潜 ...

  2. 《互联网软件应用与开发(网络程序设计)》

    设计一个服务器端程序,该程序能计算一组数列.这组数列的第0项为0,第1项为1,此后每一项都是前两项之和,数列如下:0,1,1,2,3,5,8-.要求计算到第20项.[10分] 设计一个服务器端程序.该 ...

  3. 勘误表:《网络程序设计(第二版)》西安电子科技大学出版社

    勘误表是本人自己在上这门课时整理的,欢迎大家补充,本人联系方式zhongyi1997@126.com. <网络程序设计(第二版)>,西安电子科技大学出版社 (封面是这样风格的,暂时没找到匹 ...

  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. C++中的IPv6网络程序设计

    IPv4 最初是由美国国防部开发的用于网际互联(IP)协议,后来它不仅发展了TCP,而且还进一步发展了IPv4(IP 协议4.0版).IPv4现在已经广泛应用于Internet网络中,同时也应用于大多 ...

  7. 《Python网络程序设计(微课版)》前2章110页免费阅读

    开学第一课:一定不要这样问老师Python问题 中国大学MOOC"Python程序设计基础"第6次开课时间 董付国老师Python系列教材推荐与选用参考 ============= ...

  8. 董老师又双叒叕送书啦,8本《Python网络程序设计(微课版)》

    推荐教材: <Python网络程序设计(微课版)>,ISBN:978-7-3025-8312-7,董付国,清华大学出版社,2021年8月出版 配套资源: 教学大纲.PPT.91个例题源码. ...

  9. 《Python网络程序设计(微课版)》223道习题参考答案

    推荐教材: <Python网络程序设计(微课版)>,ISBN:978-7-3025-8312-7,董付国,清华大学出版社,2021年8月出版 配套资源: 教学大纲.450页PPT.91个例 ...

最新文章

  1. [zz]启动apache后访问系统,提示没有权限访问目录,报403错误。
  2. winform 界面库SunnyUI初次使用
  3. 【python图像处理】图像的缩放、旋转与翻转
  4. Android基础——数据持久化存储
  5. CodeForces - 1055C Lucky Days(数论)
  6. 字符串匹配算法(一):BF(BruteForce)算法和RK(RabinKarp)算法
  7. shell 变量相关的命令
  8. 如何查找UI5应用对应在ABAP Netweaver服务器上的BSP应用名称
  9. jq之slidedown()
  10. 惠普服务器查看主板型号,win10惠普主板型号查看图文教程
  11. 【汇编优化】之linux下如何利用gdb调试汇编代码
  12. 1055. 集体照 (25)-PAT乙级真题
  13. Maxent Source code reading experience
  14. java读CSV文件入数组
  15. 金刚狼java,金刚狼3 【4K原盘】2017.2160p.BluRay.HEVC.TrueHD.7.1.Atmos-TERMiNAL 47GB
  16. adprw指令通讯案例_S71200 ModbusTCP 通讯配置向导说明
  17. java sqrt函数源码_Java sqrt源码解析
  18. License information could not be obtained from Elasticsearch due to Error: Request Timeout after 300
  19. inferred type_您最终可以使用var在Java中声明Inferred Type局部变量-这就是为什么它很棒...
  20. 侦测单IP是否为路由器,级联PC的原理

热门文章

  1. vue02——vue中v-XXX指令
  2. MFC中关于char[]转换成LPCWSTR的问题
  3. 计算机组成原理 光盘中试题答案,白中英计算机组成原理光盘上试题及答案.doc...
  4. elementui 表格的简单封装
  5. ASP.NET的隐藏功能[关闭]
  6. java计算年龄_java根据出生年月日精确计算年龄的算法
  7. 显示购物车列表和修改商品数量
  8. 学习笔记——SRAM、DRAM、SDRAM区别
  9. 你好,法语!A1课文背诵汇总
  10. 微型计算机的使用寿命,PC产品的MTBF和寿命:用户怎么去选择。