在(一)中,我将肺结节检测项目总结为三阶段,这里我要讲讲这个项目的第三阶段,至于第二阶段,由于数据增强部分的代码我始终看不大懂,先不讲。

结果评估的程序在evaluationScript文件夹下,这个文件夹下的文件名比较烦,看的比较懵。

annotations文件夹里面放的是结节标签文件,无关结节标签文件(是结节,但是不统计在内,也不作为非结节区域,就是评估的时候如果你检测到了它,既不算正确,也不算错误,略过),还有用户id文件。

tool文件夹放的是读取csv文件的模块。

frocwrtdetpepchluna16.py用来将输出的.npy格式的结果转化为.csv格式。

noduleCADEvaluationLUNA16.py用来对.csv文件中的结果进行评估,得出froc曲线图。

下面详细分析下代码,首先是frocwrtdetpepchluna16.py。

def getcsv(detp, eps): #给定阈值和epoch
for ep in eps:#针对每个epoch
bboxpath = results_path + str(ep) + '/' #找到每个epoch的路径
for detpthresh in detp:
print 'ep', ep, 'detp', detpthresh
f = open(bboxpath + 'predanno'+ str(detpthresh) + 'd3.csv', 'w') #根据阈值分别创建与之对应的文件
fwriter = csv.writer(f)
fwriter.writerow(firstline) #写入第一行,包括用户id,结节坐标x,y,z,结节概率p
fnamelist = []
for fname in os.listdir(bboxpath):
if fname.endswith('_pbb.npy'): #找到以_pbb.npy结尾的文件(输出的结节预测值),添加进文件列表
fnamelist.append(fname) print(len(fnamelist))
convert = functools.partial(convertcsv, bboxpath = bboxpath, detp = detpthresh) #这个函数对convertcsv函数进行修饰,其实就是预设定几个参数,不用再输入
for fname in fnamelist:
print fname
rowlist = convert(fname) #将每一个_pbb.npy文件转换为csv文件
for row in rowlist:
print row
fwriter.writerow(row)        
       #这段注释掉的是原来的代码,用来对那末多pbb.npy文件并行处理,事实证明,确实快了好几倍,实际运行应该用下面这段
       
       #map函数也是修饰函数,将fnamelist的元素并行送给convert处理
#predannolist = p.map(functools.partial(convertcsv, bboxpath=bboxpath, detp=detpthresh), fnamelist)
                              
#for predanno in predannolist:                                         
# print predanno
# for row in predanno:
# print row
# fwriter.writerow(row)
f.close()

上面这段代码不是核心代码,这段的作用是对输出的结果文件调用convertcsv函数处理,结果就是每一个epoch都生成一个csv文件,存放80多个测试病例的预测结节位置及概率。

那么接下来就说说比较核心的convertcsv函数

def convertcsv(bboxfname, bboxpath, detp):#给定pbb.npy的文件名,pbb.npy的路径,阈值
sliceim,origin,spacing,isflip = load_itk_image(datapath+bboxfname[:-8]+'.mhd')#加载原始数据
origin = np.load(sideinfopath+bboxfname[:-8]+'_origin.npy', mmap_mode='r') #以下几行加载预处理后的坐标原点,分辨率,拓展box
spacing = np.load(sideinfopath+bboxfname[:-8]+'_spacing.npy', mmap_mode='r')
resolution = np.array([1, 1, 1])
extendbox = np.load(sideinfopath+bboxfname[:-8]+'_extendbox.npy', mmap_mode='r')
pbb = np.load(bboxpath+bboxfname, mmap_mode='r') #加载pbb.npy文件
#print "load finished!"
pbbold = np.array(pbb[pbb[:,0] > detp]) #根据阈值过滤掉概率低的
pbbold = np.array(pbbold[pbbold[:,-1] > 3]) #根据半径过滤掉小于3mm的
pbbold = pbbold[np.argsort(-pbbold[:,0])][:1000] #这条是我加上的,取概率值前1000的结节作为输出,不然直接进行nms耗时太长 pbb = nms(pbbold, nmsthresh) #对输出的结节进行nms
#print "after nms bboxs:",pbb.shape[0]
# print len(pbb), pbb[0]
# print bboxfname, pbbold.shape, pbb.shape, pbbold.shape
pbb = np.array(pbb[:, :-1]) #去掉直径
# print pbb[:, 0]
pbb[:, 1:] = np.array(pbb[:, 1:] + np.expand_dims(extendbox[:,0], 1).T) #对输出加上拓展box的坐标,其实就是恢复为原来的坐标,我对这个拓展box深恶痛绝
pbb[:, 1:] = np.array(pbb[:, 1:] * np.expand_dims(resolution, 1).T / np.expand_dims(spacing, 1).T) #将输出恢复为原来的分辨率,这样就对应了原始数据中的体素坐标
if isflip:#如果有翻转的情况,将坐标翻转(我理解是这样的,原始数据有翻转的情况,但是label还是未翻转的label,那么将label翻转,所以模型的输出也是翻转的,现在要再翻转回去,与label对应)
        #拓展box与翻转这两个操作让我神烦
Mask = np.load(sideinfopath+bboxfname[:-8]+'_mask.npy', mmap_mode='r')
pbb[:, 2] = Mask.shape[1] - pbb[:, 2]
pbb[:, 3] = Mask.shape[2] - pbb[:, 3]
pos = VoxelToWorldCoord(pbb[:, 1:], origin, spacing) #将输出转换为世界坐标
#print "voxel to world finished!"
rowlist = []
# print pos.shape
for nk in xrange(pos.shape[0]): # pos[nk, 2], pos[nk, 1], pos[nk, 0] #现在依次将文件名,z,y,x,概率(经过sigmoid处理)写入rowlist,每行都是一个输出结节
rowlist.append([bboxfname[:-8], pos[nk, 2], pos[nk, 1], pos[nk, 0], 1/(1+np.exp(-pbb[nk,0]))])
# print len(rowlist), len(rowlist[0])
return rowlist#bboxfname[:-8], pos[:K, 2], pos[:K, 1], pos[:K, 0], 1/(1+np.exp(-pbb[:K,0]))

这段代码各种操作是真的繁琐,看着都头疼。这段主要完成的就是对输出结节应用阈值和nms,输出的结果再转换为与label一样的坐标体系,因为最后的准确与否全看与label是否一致。看一下打印的输出信息,这里用的是subset9为验证集,我只贴出了一个epoch的测试结果,阈值取为-0.125,这是sigmoid函数的输入,对应概率值0.4695。

ep 1 detp -0.125
write to/home/code/DeepLung/detector/results/new_arch/retrft969/val1/predanno-0.125pbb.csv

至此,输出处理完毕,可以求取最后的FROC值了,离大功告成只差一步。

不过,每个epoch都会对应一个csv结果文件,我们还要选取一个最好的结果,选取标准就是FROC值,这些都是如何做的呢,不妨看一下代码。

def getfroc(detp, eps):
maxfroc = 0
maxep = 0
for ep in eps: #对每个epoch分别处理
bboxpath = results_path + str(ep) + '/'
predannofnamalist = []
for detpthresh in detp: #此处的detp就是阈值,只不过这里采用的是一个阈值列表,就我自己而言,我采用的阈值是-0.125,列表中只有一个元素
predannofnamalist.append(bboxpath + 'predanno'+ str(detpthresh) + 'pbb.csv')
#froclist = p.map(getfrocvalue, predannofnamalist)
froclist = [getfrocvalue(predanno) for predanno in predannofnamalist] #调用getfrocvalue求取froc值
if maxfroc < max(froclist):
maxep = ep
maxfroc = max(froclist)
print froclistprint maxfroc, maxep

接下来调用getfrocvalue函数,这个函数其实是调用了noduleCADEvaluationLUNA16.py,也就是核心模块,刚才的frocwrtdetpepchluna16.py只是做了一层处理,对输出进行筛选和变换,以用来进行最后的大决战。

def getfrocvalue(results_filename):
return noduleCADEvaluation(annotations_filename,annotations_excluded_filename,seriesuids_filename,results_filename,'./')

可以看到,我们将标签文件,无关标签文件,用户id文件,以及最后的结果文件也就是之前的csv文件作为输入,输出会是一个标量值,也就是评分。

对noduleCADEvaluationLUNA16.py的分析我想放到(三)(下)去讲,因为会比较长。

项目笔记《DeepLung:Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》(三)(上)结果评估的更多相关文章

  1. 项目笔记《DeepLung:Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》(二)(上)模型设计

    我只讲讲检测部分的模型,后面两样性分类的试验我没有做,这篇论文采用了很多肺结节检测论文都采用的u-net结构,准确地说是具有DPN结构的3D版本的u-net,直接上图. DPN是颜水成老师团队的成果, ...

  2. 项目笔记《DeepLung:Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》(三)(下)结果评估

    在(上)中讲了如何得到csv文件并调用noduleCADEvaluationLUNA16.py求取froc值,这里就讲一讲froc值是如何求取的. annotations_filename = './ ...

  3. 项目笔记《DeepLung:Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》(一)预处理

    最近一个月都在做肺结节的检测,学到了不少东西,运行的项目主要是基于这篇论文,在github上可以查到项目代码. 我个人总结的肺结节检测可以分为三个阶段,数据预处理,网络搭建及训练,结果评估. 这篇博客 ...

  4. Django商城项目笔记No.2项目准备工作

    Django商城项目笔记No.2项目准备工作 接着上篇开始,创建好工程之后,随之而来的是怎么配置工程,这篇文章记录如何进行相关的配置 1.pycharm打开工程,进行相关的配置 通过pycharm打开 ...

  5. Django项目笔记:sessions处理以及复杂对象序列化

    前言:一点题外话 我发现,不更新博客的时候,不是非常忙,就是效率非常低.最近没怎么更新博客,原因是第二种= =.惭愧惭愧. 今天效率出奇的高,一天时间把PassNote后端的接口全部写完了,Djang ...

  6. Dual Path Networks(DPN)——一种结合了ResNet和DenseNet优势的新型卷积网络结构。深度残差网络通过残差旁支通路再利用特征,但残差通道不善于探索新特征。密集连接网络通过密集连接通路探索新特征,但有高冗余度。

    如何评价Dual Path Networks(DPN)? 论文链接:https://arxiv.org/pdf/1707.01629v1.pdf在ImagNet-1k数据集上,浅DPN超过了最好的Re ...

  7. 《BI项目笔记》——微软BI项目笔记连载

    本系列文章主要是结合实际项目,加上自己的总结,整理出来的一系列项目笔记,涉及微软SQL Server2008中商务智能开发中的SSAS.SSIS模块:  准备工作: <BI项目笔记>基于雪 ...

  8. A Statistical View of Deep Learning (IV): Recurrent Nets and Dynamical Systems

    A Statistical View of Deep Learning (IV): Recurrent Nets and Dynamical Systems Recurrent neural netw ...

  9. 项目笔记---CSharp图片处理

    原文:项目笔记---CSharp图片处理 项目笔记---CSharp图片处理 最近由于项目上需要对图片进行二值化处理,就学习了相关的图片处理上的知识,从开始的二值化的意义到动态阀值检测二值化等等,并用 ...

随机推荐

  1. SqlServer——事务一编程进阶(SqlServer技术内幕 T-SQL程序设计 第九章

    事务格式如下: 1.开启事务: begin tran 2.提交事务:commit tran 3.回滚事务:rollback tran 判断事务是提交还是应该回滚有两种方式,一是全局变量 @@error ...

  2. GCD详细用法

    一.延迟执行 1.介绍 第一种方法,该方法在那个线程调用,那么run就在哪个线程执行(当前线程),通常是主线程. [self performSelector:@selector(run) withOb ...

  3. xcode编译静态库选择cpu架构

    此前编译了一个静态库,默认支持了armv7,armv7s,arm64 编译的话肯定是上面三个静态库分别编译出来,然后在把这三个合并成一个单独的库. 如果单个库的大小是10M,那编译总的库大概就30M了 ...

  4. 配置镜像yum源--解决RHN not available的问题

    由于RHN服务是收费的,在安装redhat系统时,自带的yum可能不能使用.中国有很多好用的镜像源,我们可以把yum源更改到国内镜像源上,步骤如下: 一.卸载本地yum #rpm –qa|grep y ...

  5. Windows平台上通过git下载github的开源代码

    常见指令整理: (1)检查ssh密钥是否已经存在.GitBash. 查看是否已经有了ssh密钥:cd ~/.ssh.示例中说明已经存在密钥 (2)生成公钥和私钥 $ ssh-keygen -t rsa ...

  6. 详解CSS float属性(转)

    详解CSS float属性   阅读目录 基础知识 float的详细细节 float特殊情况 clear属性 清除浮动 float的应用 总结 CSS中的float属性是一个频繁用到的属性,对于初学者 ...

  7. KNN算法实现

    import csvimport randomimport mathimport operatorimport numpy as np def loadDataset(filename,split,t ...

  8. 【摘自lvs官网】lvs介绍

    Linux Virtual Server项目的目标 :使用集群技术和Linux操作系统实现一个高性能.高可用的服务器,它具有很好的可伸缩性(Scalability).可靠性(Reliability)和 ...

  9. ROS Learning-012 beginner_Tutorials (编程) 创建自定义的ROS消息和ROS服务

    ROS Indigo beginner_Tutorials-11 创建自定义的ROS消息和ROS服务 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubunt ...

  10. hive与hbase数据类型对应关系

    hive与hbase数据类型对应关系 当hbase中double,int 类型以byte方式存储时,用字符串取出来必然是乱码. 在hivd与hbase整合时也遇到这个问题:做法是:#b 1.加#b C ...