【发布时间】:2022-01-30 00:46:59
【问题描述】:
我正在尝试使用 tf.data API 和 tensorflow_io 从 DICOM 图像创建 TensorFlow 数据集,并且我想使用图像中的 Hounsfield 单位执行一些预处理。 DICOM 图像的形状为 (512,512)。我已经从图像中提取了 PixelData,并希望使用以下代码将其转换为适当形状的 numpy 数组:
image_bytes = tf.io.read_file(image_path)
PixelData = tfio.image.decode_dicom_data(image_bytes, tfio.image.dicom_tags.PixelData).numpy()
pixel_array = np.frombuffer(PixelData, dtype=tf.uint16)
pixel_array = np.reshape(pixel_array, (512,512))
print(pixel_array)
这段代码应该等价于
Image = pydicom.dcmread(image_path)
pixel_array = Image.pixel_array
print(pixel_array)
和
Image = pydicom.dcmread(image_path)
PixelData = Image.PixelData
pixel_array = np.frombuffer(PixelData, dtype=np.uint16)
pixel_array = np.reshape(pixel_array, (512,512))
print(pixel_array)
DICOM 标记与 pydicom 使用的相同,并给出了here。 PixelData 应该返回 DICOM 图像的原始字节值。我已通过 pydicom 确认原始像素数据存储为 np.uint16 值。但是,当我尝试使用 np.frombuffer 函数将 tensorflow 给出的字节数据转换为 numpy 数组时,出现缓冲区大小不能被元素长度整除的错误。
当我运行上述脚本时,这些是以下输出形状
- Tensorflow:不使用 tf.uint16 运行,使用 tf.uint8 时给出输出形状 (1310719,)
- Pydicom 直接 pixel_array:输出形状为 (512,512)
- Pydicom PixelData 到 pixel_array:输出形状为 (512,512)
pydicom 示例在两种情况下都提供相同的输出,但是 tensorflow DICOM 标签似乎提供了完全不同的结果。请在附件中找到一个示例 DICOM 文件 here。库或我的实现有问题吗?
编辑: DICOM 图像实际上是有符号的 16 位整数,而不是无符号的。因此,以下三个 sn-ps 代码产生相同的输出:
直接来自 pydicom 的 pixel_array
import pydicom
import numpy as np
dcm = pydicom.dcmread("ID_000012eaf.dcm")
print(dcm.pixel_array)
手动将 PixelData 转换为 pixel_array
import pydicom
import numpy as np
dcm = pydicom.dcmread("ID_000012eaf.dcm")
PixelData = dcm.PixelData
pixel_array = np.frombuffer(PixelData, dtype=np.int16)
pixel_array = np.reshape(pixel_array, (512,512))
print(pixel_array)
使用tensorflow_io直接获取pixel_array
import tensorflow as tf
import tensorflow_io as tfio
import numpy as np
image_bytes = tf.io.read_file("ID_000012eaf.dcm")
pixel_array = tfio.image.decode_dicom_image(image_bytes, on_error='lossy', scale='preserve', dtype=tf.float32).numpy()
pixel_array = pixel_array.astype('int16')
pixel_array /= 2.
pixel_array = np.reshape(pixel_array, (512,512))
print(pixel_array)
但是,由于某种原因,这个最终的 sn-p 代码仍然不起作用:
import tensorflow as tf
import tensorflow_io as tfio
import numpy as np
image_bytes = tf.io.read_file("ID_000012eaf.dcm")
PixelData = tfio.image.decode_dicom_data(image_bytes, tfio.image.dicom_tags.PixelData).numpy()
pixel_array = np.frombuffer(PixelData, dtype=np.int16)
print(pixel_array)
编辑 2:这两个 sn-ps 代码理论上应该可以工作,但是它们显示错误,即字节字符串的长度不能被 int16 的大小整除:
import tensorflow as tf
import tensorflow_io as tfio
import numpy as np
image_bytes = tf.io.read_file("ID_000012eaf.dcm")
PixelData = tfio.image.decode_dicom_data(image_bytes, tfio.image.dicom_tags.PixelData).numpy()
pixel_array = np.frombuffer(PixelData, dtype=np.int16)
pixel_array = np.reshape(pixel_array, (512,512))
print(pixel_array)
和
import tensorflow as tf
import tensorflow_io as tfio
import numpy as np
image_bytes = tf.io.read_file("ID_000012eaf.dcm")
PixelData = tfio.image.decode_dicom_data(image_bytes, tfio.image.dicom_tags.PixelData)
pixel_array = tf.io.decode_raw(PixelData, tf.int16)
pixel_array = tf.reshape(pixel_array, (512,512))
print(pixel_array)
编辑 3:在得到 decode_dicom_data 提供的字节串包含十六进制值的提示后,我找到了一种将我的数据转换为所需的 pixel_array 的方法,但我很好奇为什么 PixelData 以这种方式存储:
import tensorflow as tf
import tensorflow_io as tfio
import numpy as np
image_bytes = tf.io.read_file("ID_000012eaf.dcm")
PixelData = tfio.image.decode_dicom_data(image_bytes, tfio.image.dicom_tags.PixelData).numpy()
pixel_array = np.zeros(262144, dtype=np.int16)
start,stop = 0,4
for i in range(262144):
pixel_array[i] = int(PixelData[start:stop], base=16)
start+=5
stop+=5
pixel_array = np.reshape(pixel_array, (512,512))
print(pixel_array)
来自 pydicom 的像素数据:
PixelData = b'0\xf80\xf80\xf80...'
来自 Tensorflow_io 的像素数据
PixelData = b'f830\\f830\\f830\\...'
任何关于代码重构和 linting 的建议都将受到高度赞赏。我非常感谢 @ai2ys 帮助我诊断这些问题。
【问题讨论】:
-
如果我在下面的回答回答了你的问题,你会点击“复选标记”。谢谢
标签: python numpy tensorflow pydicom medical-imaging