python - 尝试裁剪图像并使用 pydicom 保存 dicom,

标签 python python-imaging-library dicom pydicom jpeg2000

尝试加载具有 JPEG2000 压缩的胸部 X 射线 DICOM 文件,提取像素阵列,裁剪它,然后另存为新的 DICOM 文件。在 Windows10 和 MacOS 机器上试过这个,但得到类似的错误。在conda环境下运行Python 3.6.13、GDCM 2.8.0、OpenJpeg 2.3.1、Pillow 8.1.2(先安装OpenJPEG和GDCM,再安装Pillow和Pydicom)。

我的初始代码:

file_list = [f.path for f in os.scandir(basepath)]
ds = pydicom.dcmread(file_list[0])
arr = ds.pixel_array
arr = arr[500:1500,500:1500]
ds.Rows = arr.shape[0]
ds.Columns = arr.shape[1]
ds.PixelData = arr.tobytes()
outputpath = os.path.join(basepath, "test.dcm")
ds.save_as(outputpath)

后续错误:ValueError: With tag (7fe0, 0010) got exception: (7FE0,0010) Pixel Data has an undefined length indicated that it's compressed,但数据未按要求封装。有关更多信息,请参见 pydicom.encaps.encapsulate()

然后我尝试将 ds.PixelData 行修改为 ds.PixelData = pydicom.encaps.encapsulate([arr.tobytes()]) 以创建 .dcm没有错误,但是当我打开 .dcm 进行查看时,它没有显示任何图像(全黑)。

我的下一次尝试是看看我是否需要以某种方式压缩回 JPEG2000,所以我尝试:

arr = Image.fromarray(arr)
output = io.BytesIO()
arr.save(output, format='JPEG2000')

但随后出现错误:OSError: encoder jpeg2k not available。我也试过 format='JPEG' 但它告诉我 OSError: cannot write mode I;16 as JPEG ...

非常感谢任何帮助!

最佳答案

能够通过使用 imagecodecs 库和 jpeg2k_encode 函数实现此功能。一个潜在的陷阱是您需要 .copy() 数组以满足函数的 C 连续要求,如果需要,您可以通过运行 arr_crop.flag 来确认这一点。这是最适合我的更新代码:

import os
import numpy as np
import matplotlib.pyplot as plt
import pydicom
from pydicom.encaps import encapsulate
from pydicom.uid import JPEG2000
from imagecodecs import jpeg2k_encode

file_list = [f.path for f in os.scandir(basepath)]
ds = pydicom.dcmread(file_list[0])
arr = ds.pixel_array
#Need to copy() to meet jpeg2k_encodes C contiguous requirement
arr_crop = arr[500:1500,500:1500].copy() 
# jpeg2k_encode to perform JPEG2000 compression
arr_jpeg2k = jpeg2k_encode(arr_crop)
# convert from bytearray to bytes before saving to PixelData
arr_jpeg2k = bytes(arr_jpeg2k)
ds.Rows = arr_crop.shape[0]
ds.Columns = arr_crop.shape[1]
ds.PixelData = encapsulate([arr_jpeg2k])
outputpath = os.path.join(basepath, "test.dcm")
ds.save_as(outputpath)

我最后还使用了 interactivecrop 包来相对快速地获得我需要的裁剪指数(一个提示,以防 future 的人在 jupyter 中尝试这个)。如果有帮助,这里有一段代码(在上面运行之前运行):

from interactivecrop.interactivecrop import main as crop
file_names = [os.path.split(f)[1].split(".")[0] for f in file_list]
image_list = []
for x in file_list:
    ds = pydicom.dcmread(x)
    arr = ds.pixel_array
    image_list.append(arr)
crop(image_list, file_names, optimize=True)
#After cropping all images, will print a dictionary
#copied and pasted this dictionary to a new cell as crop_dict
#use the below function to convert the output to actual indices
def convert_crop_to_index(fname, crop_dict):
    x = [crop_dict[fname][1], crop_dict[fname][1] + crop_dict[fname][3]]
    y = [crop_dict[fname][0], crop_dict[fname][0] + crop_dict[fname][2]]
    return x, y
arr_crop = arr[x[0]:x[1],y[0]:y[1]].copy()

一直无法弄清楚为什么 ds.decompress() 并保存解压后的 dicom 会生成全黑图像。我觉得这应该是最简单的方法,但上面的方法最终对我有用,所以我很高兴能够弄清楚。

关于python - 尝试裁剪图像并使用 pydicom 保存 dicom,,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66912863/

相关文章:

python - 使用 PIL 在 Django 中调整图像大小两次

python - 带有图像的 numpy vstack

c++ - 如何在 C++ 中读取 dicom 像素

Android 将 2D 图像转换为 3D

python - Python 中的 DICOM 切片厚度

python - python中多类数据的真阳性率和假阳性率(TPR,FPR)

Python:逐行读取文件的最佳方式

python - 使用 Session.run 在 Tensorflow 代码中进行并行编程

python - 更新记分员

tkinter - PIL-GIF 动画,但有些帧是黑色的