paint-brush
你能用 Python 打开医疗数据(MR、CT、X 射线)并用 AI 查找肿瘤吗?!也许吧经过@thebojda
3,808 讀數
3,808 讀數

你能用 Python 打开医疗数据(MR、CT、X 射线)并用 AI 查找肿瘤吗?!也许吧

经过 Laszlo Fazekas8m2024/04/23
Read on Terminal Reader

太長; 讀書

当程序员听到处理医疗数据时,他们可能会认为这是一件严肃的事情,只有大学和研究机构才能处理(至少我是这么认为的)。如您所见,我们谈论的是简单的灰度图像,这些图像非常容易处理,非常适合神经网络处理等。
featured image - 你能用 Python 打开医疗数据(MR、CT、X 射线)并用 AI 查找肿瘤吗?!也许吧
Laszlo Fazekas HackerNoon profile picture
0-item


几天前,我接受了核磁共振扫描。他们把我放进一个大管子里,15 分钟内,我周围的机器嗡嗡作响,嗡嗡作响,咔哒作响。检查结束时,我收到了一张包含数据的 CD。在这种情况下,一个优秀的开发人员会做什么?当然,他们一回到家,就开始检查数据,思考如何使用Python提取数据。


该 CD 包含一堆 DLL、一个 EXE 和一些用于 Windows 查看器的附加文件,这些文件在 Linux 上显然毫无用处。关键在于一个名为 DICOM 的文件夹。它包含八个文件夹中的一系列无扩展名文件。ChatGPT 帮助我弄清楚了DICOM是一种通常用于存储 MRI、CT 和 X 射线图像的标准格式。本质上,它是一种简单的打包格式,包含灰度图像以及一些元数据。


以下代码可让您轻松地导出 PNG 格式的文件:


 import os import pydicom from PIL import Image import sys def save_image(pixel_array, output_path): if pixel_array.dtype != 'uint8': pixel_array = ((pixel_array - pixel_array.min()) / (pixel_array.max() - pixel_array.min()) * 255).astype('uint8') img = Image.fromarray(pixel_array) img.save(output_path) print(f"Saved image to {output_path}") def process_dicom_directory(dicomdir_path, save_directory): if not os.path.exists(save_directory): os.makedirs(save_directory) dicomdir = pydicom.dcmread(dicomdir_path) for patient_record in dicomdir.patient_records: if 'PatientName' in patient_record: print(f"Patient: {patient_record.PatientName}") for study_record in patient_record.children: if 'StudyDate' in study_record: print(f"Study: {study_record.StudyDate}") for series_record in study_record.children: for image_record in series_record.children: if 'ReferencedFileID' in image_record: file_id = list(map(str, image_record.ReferencedFileID)) file_id_path = os.path.join(*file_id) print(f"Image: {file_id_path}") image_path = os.path.join(os.path.dirname(dicomdir_path), file_id_path) modified_filename = '_'.join(file_id) + '.png' image_save_path = os.path.join(save_directory, modified_filename) try: img_data = pydicom.dcmread(image_path) print("DICOM image loaded successfully.") save_image(img_data.pixel_array, image_save_path) except FileNotFoundError as e: print(f"Failed to read DICOM file at {image_path}: {e}") except Exception as e: print(f"An error occurred: {e}") if __name__ == "__main__": if len(sys.argv) < 3: print("Usage: python dicomsave.py <path_to_DICOMDIR> <path_to_save_images>") sys.exit(1) dicomdir_path = sys.argv[1] save_directory = sys.argv[2] process_dicom_directory(dicomdir_path, save_directory)


该代码需要两个参数。第一个是 DICOMDIR 文件的路径,第二个是将以 PNG 格式保存图像的目录。


为了读取 DICOM 文件,我们使用Pydicom库。使用pydicom.dcmread函数加载结构,从中可以提取元数据(例如患者姓名)和包含图像的研究。还可以使用dcmread读取图像数据。原始数据可通过pixelarray字段访问, save_image函数将其转换为 PNG。这并不太复杂。


结果是几个方块(通常为 512x512)灰度图像,以后可以轻松利用。


为什么我认为写这篇关于我使用 DICOM 格式的冒险经历的短篇故事很重要?当程序员听到处理医疗数据时,他们可能会认为这是一件严肃的事情,只有大学和研究机构才能处理(至少我是这么认为的)。如您所见,我们谈论的是简单的灰度图像,这些图像非常容易处理,非常适合神经网络处理之类的事情。


考虑一下这会带来哪些可能性。对于像简单的肿瘤检测器这样的东西,你只需要一个相对简单的卷积网络和足够数量的样本。实际上,这项任务与识别图像中的狗或猫没有太大区别。


为了说明这是多么真实,让我举一个例子。在 Kaggle 上进行简单搜索后,我找到了一个笔记本,其中根据 MRI 数据(灰度图像)对脑肿瘤进行分类。数据集将图像分为四类:三类脑肿瘤和第四类健康大脑图像。网络架构如下:


 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ conv2d (Conv2D) │ (None, 164, 164, 64) │ 1,664 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d (MaxPooling2D) │ (None, 54, 54, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_1 (Conv2D) │ (None, 50, 50, 64) │ 102,464 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_1 (MaxPooling2D) │ (None, 16, 16, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_2 (Conv2D) │ (None, 13, 13, 128) │ 131,200 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_2 (MaxPooling2D) │ (None, 6, 6, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_3 (Conv2D) │ (None, 3, 3, 128) │ 262,272 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_3 (MaxPooling2D) │ (None, 1, 1, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ flatten (Flatten) │ (None, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense (Dense) │ (None, 512) │ 66,048 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_1 (Dense) │ (None, 4) │ 2,052 │ └─────────────────────────────────┴────────────────────────┴───────────────┘


如您所见,前几层由卷积和最大池化三明治结构组成,用于提取肿瘤模式,然后是两个执行分类的密集层。这与使用 CIFAR-10 数据集的TensorFlow CNN 示例代码中使用的架构完全相同。我记得很清楚,因为它是我遇到的第一个神经网络之一。正如我之前提到的, CIFAR-10数据集包含 60,000 张分为十类的图像,包括狗和猫两类。网络架构如下所示:


 Model: “sequential” _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 30, 30, 32) 896 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 15, 15, 32) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 13, 13, 64) 18496 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 6, 6, 64) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 4, 4, 64) 36928 _________________________________________________________________ flatten (Flatten) (None, 1024) 0 _________________________________________________________________ dense (Dense) (None, 64) 65600 _________________________________________________________________ dense_1 (Dense) (None, 10) 650 ================================================================= Total params: 122,570 Trainable params: 122,570 Non-trainable params: 0 _________________________________________________________________


显然,我们处理的是相同的架构,只是参数略有不同,因此识别 MRI 图像中的脑肿瘤确实并不比识别图片中的猫或狗困难多少。此外,上述 Kaggle 笔记本能够以 99% 的有效性对肿瘤进行分类!


我只是想指出在某些情况下提取和处理医疗数据是多么简单,以及看似复杂的问题(如检测脑肿瘤)通常可以通过简单的传统解决方案非常有效地解决。


因此,我鼓励大家不要回避医疗数据。如您所见,我们处理的是相对简单的格式,并且使用相对简单、成熟的技术(卷积网络、视觉转换器等),可以在这里取得重大影响。如果您在业余时间加入开源医疗保健项目,只是出于爱好,并且可以对所使用的神经网络进行轻微改进,那么您可能会挽救生命!