MMWHS数据集

Multi-Modality Whole Heart Segmentation (MMWHS) 数据集[1] 是多模态医疗图像数据集,有磁共振(Magnetic Resonance Imaging,MRI)和断层扫描(Computed Tomography,CT)两种,[2] 对数据形式有一些简单介绍。

原数据可在 [1/project] 下载:

  • training image & labels, test images: MM-WHS 2017 Dataset
  • test labels: MMWHS_evaluation_testdata_label_encrypt_1mm_forpublic.zip

其中 training set 有 MR、CT 各 20 份 scans,test 各 40 份。近来一些 medical domain-adaptation segmentation 的工作 [4-9] 用的都是 [3] 预处理的数据,本篇也是用这份数据(另:[19] 给了 Abdominal 数据集的预处理数据链接)。下载:

  • training & val:PnpAda_release_data.zip
  • MR test:test_mr_image&labels.zip
  • CT test:test_ct_image&labels.zip

都解压到 mmwhs/ 下,得:

mmwhs/
|- PnpAda_release_data/
|  |- ct_train_tfs/
|  |  |- ct_train_slice0.tfrecords	# image 和 label
|  |- ct_val_tfs/
|  |  |- ct_val_slice0.tfrecords
|  |- mr_train_tfs/
|  |  |- mr_train_slice0.tfrecords
|  `- mr_val_tfs/
|     |- mr_val_slice0.tfrecords
|- test_mr_image&labels/
|  |- gth_ct_1003.nii.gz			# label
|  |- image_ct_1003.nii.gz			# image
`- test_ct_image&labels/|- gth_mr_1007.nii.gz|- image_mr_1007.nii.gz

Splitting, Order

[3] 数据的划分与原数据[1]同,是只用了原数据的 training set,其中各随机选 4 scans 做 test set,剩下 16 scans 做 training 和 val set。

  • training & val 是 tfrecords 格式,每个 tfrecords 文件(image、label 都是)都是 3 张连续的 slices:前驱 slice、核心 slice、后继 slice。所以不同 tfrecords 文件是有重复的。
  • test 还是 nii.gz 格式,可用 nibabel[10]、sitk[11]、medpy[12] 读。

因为 training & val 的数据已沿 coronal 轴(参考 [2],即 z 轴)分成 slices,且由 [13],slices 是打乱的,文件名也没保留相关信息,所以数据顺序、选了哪些做 val set 都不知道。

Preprocessing

数据预处理可见 [4/code] 的 readme、[14]。

[3] 给的 tfrecords、nii.gz 文件都是预处理过的,可与 [1] 的原数据对比得知:原数据 image 数值范围明显大很多,原始 HU 值范围可达负几千至正几千[2],而 [3] 给的都在 [-5, 5] 之内(后面有相关验证)。

Loading

读 tfrecords 数据(转成 numpy)的方法参考 [4,5,8,9,15],分用、不用 eager 模式两种,主要代码来自 [8] 的 convert_tfrecords.py。此节代码用 TensorFlow 2.14.0。

eager

import os, os.path as osp
import numpy as np
import tensorflow as tf
if '2' == tf.__version__.split('.')[0]:tf = tf.compat.v1# decode tfrecords 的格式,来自 [3] 的 README
FEATURES = {'dsize_dim0': tf.FixedLenFeature([], tf.int64),'dsize_dim1': tf.FixedLenFeature([], tf.int64),'dsize_dim2': tf.FixedLenFeature([], tf.int64),'lsize_dim0': tf.FixedLenFeature([], tf.int64),'lsize_dim1': tf.FixedLenFeature([], tf.int64),'lsize_dim2': tf.FixedLenFeature([], tf.int64),'data_vol': tf.FixedLenFeature([], tf.string),'label_vol': tf.FixedLenFeature([], tf.string)
}
# image、label 的 shape,3 是因为取了连续三片
SIZE = [256, 256, 3]def _parse(example_proto):return tf.io.parse_single_example(example_proto, FEATURES)def read_tfrecord(f):dataset = tf.data.TFRecordDataset(f).map(_parse)for data in dataset:# print(type(data)) # dictimg = tf.decode_raw(data['data_vol'], tf.float32).numpy()label = tf.decode_raw(data['label_vol'], tf.float32).numpy()img = img.reshape(SIZE)label = label.reshape(SIZE)return img, label# 读
SRC = "PnpAda_release_data/mr_val_tfs"
# 顺便保存(后面对拍顺序)
DEST = "mr_val_eager"
os.makedirs(DEST, exist_ok=True)
for f in os.listdir(SRC):img, label = read_tfrecord(osp.join(SRC, f))np.save(osp.join(DEST, osp.splitext(f)[0]), img[:, :, 1]) # 只存中间的 slice

non-eager

import os, os.path as osp
import numpy as np
import tensorflow as tf
if '2' == tf.__version__.split('.')[0]:tf.compat.v1.disable_v2_behavior() # tf1 风格读数据要加这句tf = tf.compat.v1FEATURES = {'dsize_dim0': tf.FixedLenFeature([], tf.int64),'dsize_dim1': tf.FixedLenFeature([], tf.int64),'dsize_dim2': tf.FixedLenFeature([], tf.int64),'lsize_dim0': tf.FixedLenFeature([], tf.int64),'lsize_dim1': tf.FixedLenFeature([], tf.int64),'lsize_dim2': tf.FixedLenFeature([], tf.int64),'data_vol': tf.FixedLenFeature([], tf.string),'label_vol': tf.FixedLenFeature([], tf.string)
}
SIZE = [256, 256, 3]# 读
SRC = "PnpAda_release_data/mr_val_tfs"
# 顺便保存(后面对拍顺序)
DEST = "mr_val_non-eager"
os.makedirs(DEST, exist_ok=True)files = os.listdir(SRC)
files = [osp.join(SRC, f) for f in files] # 要绝对路径,否则后面报错找不到文件file_queue = tf.train.string_input_producer(files, shuffle=False) # 关 shuffle,否则顺序不同
reader = tf.TFRecordReader()
_, serialized_example = reader.read(file_queue)
data = tf.parse_single_example(serialized_example, features=FEATURES)img_vol = tf.decode_raw(data['data_vol'], tf.float32)
label_vol = tf.decode_raw(data['label_vol'], tf.float32)
img_vol = tf.reshape(img_vol, SIZE)
label_vol = tf.reshape(label_vol, SIZE)with tf.Session() as sess:sess.run(tf.initialize_all_variables())coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)for f in files: # 手动限长,否则会一直循环读img, label = sess.run([img_vol, label_vol])np.save(osp.join(DEST, osp.splitext(osp.basename(f))[0]), img[:, :, 1]) # 也是只存中间的 slicecoord.request_stop()coord.join(threads)

comparison

两种读法应该读出来的结果一样,包括顺序,对拍:

import os, os.path as osp
import numpy as np# 前面保存的 mr_val 数据
P1 = "mr_val_eager"
P2 = "mr_val_non-eager"
for f in os.listdir(P1):im1 = np.load(osp.join(P1, f))im2 = np.load(osp.join(P2, f))assert (im1 != im2).sum() == 0, f
print("DONE")
  • 结论:一致

Statistics

[4,5] 的 README 说要张数据变换到 [-1, 1],而其代码 data_loader.py 是用 min-max scaling 做的,其中 image 的最小、最大值为:

  • MR:-1.84.4
  • CT:-2.83.2

由 [17],这些值是仅由 tfrecords 文件导出的,验证:

tfrecords

import os, os.path as osp, math
import tensorflow as tf
if '2' == tf.__version__.split('.')[0]:tf.compat.v1.disable_v2_behavior()tf = tf.compat.v1for m in ("mr", "ct"):max_v, min_v = -math.inf, math.inffor sub in ("train", "val"):d = f"{m}_{sub}_tfs"max_v_sub, min_v_sub = -math.inf, math.inffiles = os.listdir(d)files = [osp.join(d, f) for f in files]file_queue = tf.train.string_input_producer(files, shuffle=False)reader = tf.TFRecordReader()_, serialized_example = reader.read(file_queue)parser = tf.parse_single_example(serialized_example, features=features)img_vol = tf.decode_raw(parser['data_vol'], tf.float32)img_vol = tf.reshape(img_vol, [256, 256, 3])with tf.Session() as sess:sess.run(tf.initialize_all_variables())coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)for f in files:img = img_vol.eval()max_v_sub = max(max_v_sub, img.max())min_v_sub = min(min_v_sub, img.min())print(f, end='\r')coord.request_stop()coord.join(threads)print(f"\n{m}, {sub}, min:", min_v_sub, ", max:", max_v_sub)max_v = max(max_v, max_v_sub)min_v = min(min_v, min_v_sub)print(f"\n{m}, min:", min_v, ", max:", max_v)
  • 输出
mr, train, min: -1.7675079 , max: 4.3754067
mr, val, min: -1.511309 , max: 3.2670646
mr, min: -1.7675079 , max: 4.3754067ct, train, min: -2.731593 , max: 3.0706542
ct, val, min: -2.4145143 , max: 2.2560735
ct, min: -2.731593 , max: 3.0706542

nii.gz

import os, os.path as osp, math
import medpy.io as mediofor m in ("mr", "ct"):max_v, min_v = -math.inf, math.infd = f"test_{m}_image&labels"for f in os.listdir(d):if not f.startswith("image_"): continueprint(f, end='\r')im, _ = medio.load(osp.join(d, f))max_v = max(max_v, im.max())min_v = min(min_v, im.min())print('\n', m, min_v, max_v)
  • 输出
mr -1.1368891922215185 2.6575754759544323
ct -1.763460938640936 2.368554272081745

结论:代码用的基本跟 tfrecords 导出的一致。另 [18] 指出 Abdominal 用的 min、max value。

References

  1. (MIA 2019) Evaluation of algorithms for Multi-Modality Whole Heart Segmentation: An open-access grand challenge - paper, project, paper with code
  2. 医疗图像分割指标
  3. (arXiv 2018) PnP-AdaNet: Plug-and-play adversarial domain adaptation network with a benchmark at cross-modality cardiac segmentation - paper, github
  4. (AAAI 2019) Synergistic Image and Feature Adaptation: Towards Cross-Modality Domain Adaptation for Medical Image Segmentation - paper, code
  5. (TMI 2020) Unsupervised Bidirectional Cross-Modality Adaptation via Deeply Synergistic Image and Feature Alignment for Medical Image Segmentation - paper, code
  6. (JBHI 2020) Margin Preserving Self-Paced Contrastive Learning Towards Domain Adaptation for Medical Image Segmentation - paper, code
  7. (MICCAI 2021) MT-UDA: Towards Unsupervised Cross-modality Medical Image Segmentation with Limited Source Labels - paper, code
  8. (TMI 2021) Self-Attentive Spatial Adaptive Normalization for Cross-Modality Domain Adaptation - paper, code
  9. (MICCAI 2022) Attention-Enhanced Disentangled Representation Learning for Unsupervised Domain Adaptation in Cardiac Segmentation - paper, code
  10. nipy/nibabel, NiBabel
  11. SimpleITK/SimpleITK, SimpleITK
  12. loli/medpy, MedPy
  13. 数据集预处理 #49
  14. The pre-processing of the original data #9 -> The Preprocess Data Issue #12
  15. tsmatz/tensorflow-mnist-batch-read-and-train-tutorial
  16. tf.compat.v1.train.string_input_producer
  17. About the minmax value #11
  18. Min Max value to normalize Abdominal datasets. #56
  19. Prepocessed Abdominal Data #51

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/113265.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索图像分割技术:使用 OpenCV 的分水岭算法

贾斯卡兰巴蒂亚 一、说明 图像分割是计算机视觉的一个基本方面,多年来经历了巨大的转变。这将是一系列三篇博客文章,深入研究三种不同的图像分割技术 - 1使用OpenCV的经典分水岭算法,2使用PyTorch实现的基于深度学习的UNet模型,3 …

【Redis】数据结构之dict

目录 dict的基本结构dict的相关操作函数底层通用的之查找插入key-value对应该放入ht表的哪个槽rehash过程 dict的基本结构 typedef struct dict {dictType *type;void *privdata;dictht ht[2];long rehashidx; /* rehashing not in progress if rehashidx -1 */unsigned long…

Ubuntu小知识总结

Ubuntu相关的小知识总结 一、Ubuntu系统下修改用户开机密码二、Vmware虚拟机和主机之间复制、粘贴内容、拖拽文件的详细方法问题描述Vmware tools灰色不能安装解决方法小知识点:MarkDown的空格 三、Ubuntu虚拟机网络无法连接的几种解决方法1.重启网络编辑器2. 重启虚…

Linux下使用openssl为harbor制作证书

openssl是一个功能丰富且自包含的开源安全工具箱。它提供的主要功能有:SSL协议实现(包括SSLv2、SSLv3和TLSv1)、大量软算法(对称/非对称/摘要)、大数运算、非对称算法密钥生成、ASN.1编解码库、证书请求(PKCS10)编解码、数字证书编解码、CRL编解码、OCSP协议、数字证…

免费高清壁纸下载(静态和动态壁纸)

一、网址下载(静态壁纸) 高清图片直接另存为就可以了。然后在电脑空白处右键——个性化设置即可替换壁纸。 ①网址:https://www.hippopx.com ②极简壁纸:https://bz.zzzmh.cn/index ③彼岸图网:http://pic.netbian…

Linux:firewalld防火墙-介绍(1)

防火墙技术 1.包过滤 packet filtering 2.应用代理 application proxy 3.状态检测 stateful inspection Linux 包过滤防火墙 概述 1.netfilter 位于Linux内核中的包过滤功能体系 称为Linux防火墙的“内核态” 2.firewalld CentOS7默认的管理防火墙规则的工具 称为Linux防火…

OpenCV17-图像形态学操作

OpenCV17-图像形态学操作 1.形态学操作1.1腐蚀1.2膨胀 2.形态学应用2.1开运算2.2闭运算2.3形态学梯度2.4顶帽运算2.5黑帽运算2.6击中击不中变换2.7形态学应用示例 1.形态学操作 1.1腐蚀 图像腐蚀(Image erosion)可用于减小图像中物体的大小、填充孔洞或…

通过数组的指针获得数组个数

这几天学习智能指针时,自己在练习写个管理数组指针的类时碰到了通过数组指针获取数组个数的问题 1.在网上查询了通过数组指针获取数组个数的方法,对于自定义数据在前四个节点保存了数组个数 Student* pAry new Student[3];size_t num *((size_t*)pAry - 1);//3测试是成功的…

华为eNSP配置专题-VRRP的配置

文章目录 华为eNSP配置专题-VRRP的配置0、参考文档1、前置环境1.1、宿主机1.2、eNSP模拟器 2、基本环境搭建2.1、基本终端构成和连接 2.VRRP的配置2.1、PC1的配置2.2、接入交换机acsw的配置2.3、核心交换机coresw1的配置2.4、核心交换机coresw2的配置2.5、配置VRRP2.6、配置出口…

C++多态、虚函数、纯虚函数、抽象类

多态的概念 通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。 举个简单的例子:抢红包,我们每个人都只需要点击一下红包,就会抢到金额。有些人能…

OpenCV中world模块介绍

OpenCV中有很多模块,模块间保持最小的依赖关系,用户可以根据自己的实际需要链接相关的库,而不需链接所有的库,这样在最终交付应用程序时可以减少总库的大小。但如果需要依赖OpenCV的库太多,有时会带来不方便,此时可以使…

vue2 element手术麻醉信息系统源码,手术预约、手术安排、排班查询、手术麻醉监测、麻醉记录单

手术麻醉临床信息系统有着完善的临床业务功能,能够涵盖整个围术期的工作,能够采集、汇总、存储、处理、展现所有的临床诊疗资料。通过该系统的实施,能够规范麻醉科的工作流程,实现麻醉手术过程的信息数字化,自动生成麻…

mac 升级node到指定版本

node版本14.15.1升级到最新稳定版18.18.2 mac系统 先查看一下自己的node版本 node -v开始升级 第一步 清除node的缓存 sudo npm cache clean -f第二步 安装n模块【管理模块 n是管理 nodejs版本】 sudo npm install -g n第三步升级node sudo n stable // 把当前系统的 Node…

计算机毕业设计 基于SpringBoot智慧养老中心管理系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…

【趣味随笔】盘点国内外做双足机器人的公司

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…

leetCode 392. 判断子序列 动态规划 + 优化空间 / 双指针 等多种解法

392. 判断子序列 - 力扣(LeetCode) 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如&#xff0c…

Aocoda-RC F405V2 FC(STM32F405RGT6 v.s. AT32F435RGT7) IO Definitions

[TOC](Aocoda-RC F405V2 FC(STM32F405RGT6 v.s. AT32F435RGT7) IO Definitions) 1. 源由 Aocoda-RC F405V2飞控支持betaflight/inav/Ardupilot固件,是一款固件兼容性非常不错的开源硬件。 之前我们对比过STM32F405RGT6 v.s. AT32F435RGT7 Comparison for Flight …

ThreadLocal源码解密

1 背景 作为一只懒懒地程序员,其实我是不太爱看源码的,晦涩、深奥、难懂、耗费时间等等,就觉得不是我这种能力平平地小老百姓能吃得消的,但现实比人强,记得曾经我就被不懂原理的情况下乱用ThreadLocal给毒打了。 犹记得当时在一个JSF服务中的责任链的校验场景中需要在源…

UART、SPI、I2C通信协议超全入门教程

本文引注: https://mp.weixin.qq.com/s/lVWK8xlDt7cOLi8WHYSuPg 1.SPI协议 1.基础 2.简介 3.工作原理 4.SPI数据传输步骤与优缺点 2.UART协议

分布式微服务技术栈-SpringCloud<Eureka,Ribbon,nacos>

微服务技术栈 一、微服务 介绍了解1 架构结构案例与 springboot 兼容关系拆分案例拆分服务拆分-服务远程调用 2 eureka注册中心Eureka-提供者与消费者Eureka-eureka原理分析Eureka-搭建eureka服务Eureka-服务注册Eureka-服务发现 3 Ribbon组件 负载均衡Ribbon-负载均衡原理Ribb…