总结

来源:互联网 发布:美国特效软件 编辑:程序博客网 时间:2024/05/20 06:49

1 课程项目

课程最终完成了一个小项目,web前端可以接受血常规检验报告图片(实验图片在项目中),后台对图片进行剪裁矫正识别,输出一份报告。然后通过报告中各项指标预测病人的年龄性别。项目地址:https://coding.net/u/mengning/p/np2016/git/tree/master

1.1环境搭建

实验环境是ubuntu14,python2.7。推荐使用anaconda工具包2.7版本的,这样实验中用到的很多机器学习包不用单独安装了。anaconda最好先更改下镜像源,一般都用清华的。如何修改请自行百度。
conda安装tensorflow
    conda install tensorflow
conda安装flask
    conda install flask
pip安装pytesseract
    sudo apt-get install tesseract-ocr    sudo pip install pytesseract 

pip安装mongo

    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


1.2 文件说明

view.py:web端上传图片到服务器,存入mongodb并获取id。
imageFilter.py:对图像透视裁剪和orc简单的封装,以便于模块之间交互
classifier.py:用于判定裁剪矫正后的报告和裁剪出项目的编号
imgproc.py:将识别的图像进行二值化等操作,提高识别率包括对中文和数字的处理
digits:将该文件替换Tesseract-OCR\tessdata\configs中的digits

1.3 模块组成

1.3.1图像处理模块

先进行图像预处理,灰度化,二值化,腐蚀,膨胀,中值滤波去除噪点。

    #灰度化    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)    # cv2.imshow('result',result)    # cv2.waitKey(0)    #腐蚀去除放大后的一些小的点    eroded = cv2.erode(result,kernel)    #  cv2.imshow('eroded',eroded)    #  cv2.waitKey(0)    #膨胀使数字更饱满    result = cv2.dilate(eroded,kernel)    #   cv2.imshow('dilated',result)    #直方图均衡化使图像更清晰    cv2.equalizeHist(result)    #中值滤波去除噪点    result = cv2.medianBlur(result,5)    #    cv2.imshow('median',result)    #   cv2.waitKey(0)    return result

然后对图片进行进行处理,描绘边缘,调用findContours提取轮廓,选择最大的三个轮廓,将轮廓变为线,根据这三条线来确定表头和表尾的位置。用透视转换将表格区域转化成1000*700的图。

 # 载入图像,灰度化,开闭运算,描绘边缘        img_sp = self.img.shape        ref_lenth = img_sp[0] * img_sp[1] * ref_lenth_multiplier        img_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)        def getbox(i):            rect = cv2.minAreaRect(contours[i])            box = cv2.cv.BoxPoints(rect)            box = np.int0(box)            return box        def distance(box):            delta1 = box[0]-box[2]            delta2 = box[1]-box[3]            distance1 = np.dot(delta1,delta1)            distance2 = np.dot(delta2,delta2)            distance_avg = (distance1 + distance2) / 2            return distance_avg        # 筛选出对角线足够大的几个轮廓        found = []        for i in range(len(contours)):            box = getbox(i)            distance_arr = distance(box)            if distance_arr > ref_lenth:                found.append([i, box])        def getline(box):            if np.dot(box[1]-box[2],box[1]-box[2]) < np.dot(box[0]-box[1],box[0]-box[1]):                point1 = (box[1] + box[2]) / 2                point2 = (box[3] + box[0]) / 2                lenth = np.dot(point1-point2, point1-point2)                return point1, point2, lenth            else:                point1 = (box[0] + box[1]) / 2                point2 = (box[2] + box[3]) / 2                lenth = np.dot(point1-point2, point1-point2)                return point1, point2, lenth           # 将轮廓变为线        line = []        for i in found:            box = i[1]            point1, point2, lenth = getline(box)            line.append([point1, point2, lenth])        # 把不合适的线删去        if len(line)>3:            for i in line:                for j in line:                    if i is not j:                        rst = linecmp(i, j)                        if rst > 0:                            deleteline(line, j)                        elif rst < 0:                            deleteline(line, i)        #检测出的线数量不对就返回-1跳出        if len(line) != 3:            print "it is not a is Report!,len(line) =",len(line)            return None                def distance_line(i, j):            dis1 = np.dot(i[0]-j[0], i[0]-j[0])            dis2 = np.dot(i[0]-j[1], i[0]-j[1])            dis3 = np.dot(i[1]-j[0], i[1]-j[0])            dis4 = np.dot(i[1]-j[1], i[1]-j[1])            return min(dis1, dis2, dis3, dis4)        def findhead(i, j, k):            dis = []            dis.append([distance_line(i, j), i, j])            dis.append([distance_line(j, k), j, k])            dis.append([distance_line(k, i), k, i])            dis.sort()            if dis[0][1] is dis[2][2]:                return dis[0][1], dis[2][1]            if dis[0][2] is dis[2][1]:                return dis[0][2], dis[2][2]        def cross(vector1, vector2):            return vector1[0]*vector2[1]-vector1[1]*vector2[0]        # 由三条线来确定表头的位置和表尾的位置        line_upper, line_lower = findhead(line[2],line[1],line[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 = 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
最后进行识别。

1.3.2字符识别模块

pytesseract.image_to_string(Image.fromarray(image), lang='chi_sim', config=' -psm 7 Bloodtest')
  主要调用这个函数来进行识别

1.3.3预测模块

预测用sklearn中sklearn.ensemble.RandomForestClassifier随机森林算法来进行预测。随机森林,指的是利用多棵树对样本进行训练并预测的一种分类器。对于每棵树,它们使用的训练集是从总的训练集中有放回采样出来的,这意味着,总的训练集中的有些样本可能多次出现在一棵树的训练集中,也可能从未出现在一棵树的训练集中。在训练每棵树的节点时,使用的特征是从所有特征中按照一定比例随机地无放回的抽取的,根据Leo Breiman的建议,假设总的特征数量为M,这个比例可以是sqrt(M),1/2sqrt(M),2sqrt(M)。

2 课程心得

转眼,课程已进入尾声,网络程序设计的上课形式与其他的课程不太一样,由同学主导课堂,每周都会有同学上台分享自己最近新学的知识和代码。这对提升我们的演讲水平和编码能力很有帮助。我讲的是A1手写字符神经网络,发现很多时候自己能理解的东西,未必能准确的表达出来。其实还是因为自己对某些知识点一知半解,没有完全理解。倘若能完全理解,自然就能用自己的话表述出来。还有就r是自己上台演讲没有做好充足的准备,讲解不够流畅,时间也没能掌握好。最好能提前演练一两遍,控制好时间和讲解速度,这样才能确保自己的内容能够顺利讲完。本课程还有很多有意思的任务,这些对我来说都是第一次接触,我们可以自己选择做一些力所能及的工作,也可以学习一些大神们提交的代码。但我觉得最好的方式还是去强迫自己去接受一个任务并独立完成,要相信自己,可能不试一次,你永远也不会知道自己竟有这样的潜能。哪怕最后无法完成,我相信这个过程中你也会学到很多东西。再有就是git的学习使用,git是个很实用的工具,很多公司都在使用,互联网公司大都是多人协作开发,就需要要像git一样的版本控制工具。尤其是以后当我主导一个项目的时候,我知道可以用git来提高团队的开发效率。

最后感谢老师对这个项目的维护,对每个pr都认真处理,给出修改意见。也感谢同学提交的代码,让我有能学习的机会。希望下学期能继续选孟老师的高软,听说又会有很多高质量的代码可以学习。


pull request:

1.https://coding.net/u/mengning/p/np2016/git/pull/171  随机森林73%性别预测正确率(拒绝)

 2.https://coding.net/u/mengning/p/np2016/git/pull/89    前端不合格图片弹框显示(接受)

知识分享:

1.准备ppt重点分析本项目中使用的神经网络算法,应该先介绍算法涉及的主要原理等数学知识再具体解释算法的实现代码 

2.非监督kmeans算法分享





0 0
原创粉丝点击