简短版本Pydicom
:通过以下代码从 DICOM 文件导出 MPEG-4 视频流时,16 字节偏移量来自哪里?(另外,附加问题是,它始终是 16 字节偏移量吗?)
from pathlib import Path
import pydicom
in_dcm_filename: str = ...
out_mp4_filename: str = ...
ds = pydicom.dcmread(in_dcm_filename)
Path(out_mp4_filename).write_bytes(ds.PixelData[16:]) # 16-byte offset necessary
为了可重复性,可以使用我在Google 群组的旧讨论中找到的这个 DICOM 文件(内容警告:该视频展示了神经外科干预中的开放大脑)。
长版本
我有许多包含手术 MPEG-4 视频流的 DICOM 文件(传输语法 UID 1.2.840.10008.1.2.4.102 – MPEG-4 AVC/H.264 High Profile / Level 4.1)。我想从 DICOM 文件中导出视频流,以便在下游任务中更轻松地处理。
经过一番谷歌搜索后,我发现了以下讨论,建议使用dcmdump
from DCMTK
,如下所示(我能够重现):
- 跑步
dcmdump +P 7fe0,0010 <in_dcm_filename> +W <out_folder>
。 - 从得到的两个文件中
<out_folder>
,mpeg4.dcm.0.raw
和mpeg4.dcm.1.raw
,丢弃第一个文件(大小为 0 字节),保留第二个文件(可能将其后缀更改为.mp4
),它是一个常规的可播放视频文件。
从命令中看到的内容dcmdump
,我得出结论,这只是标签7fe0,0010
(即像素数据属性)的原始转储,因此我认为我可以使用 重现此情况Pydicom
。我第一次尝试使用Path(out_mp4_filename).write_bytes(ds.PixelData)
(有关完整详细信息,请参阅上面的代码示例);但是,我最终得到的是一个无法播放的文件。然后,我比较了结果的十六进制转储dcmdump
和结果Pydicom
:
$ hd ./dcmdump.mp4 | head
00000000 00 00 00 20 66 74 79 70 69 73 6f 6d 00 00 02 00 |... ftypisom....|
00000010 69 73 6f 6d 69 73 6f 32 61 76 63 31 6d 70 34 31 |isomiso2avc1mp41|
00000020 00 00 00 08 66 72 65 65 00 ce 97 1d 6d 64 61 74 |....free....mdat|
...
$ hd ./pydicom.mp4 | head
00000000 fe ff 00 e0 00 00 00 00 fe ff 00 e0 3e bc ce 00 |............>...|
00000010 00 00 00 20 66 74 79 70 69 73 6f 6d 00 00 02 00 |... ftypisom....|
00000020 69 73 6f 6d 69 73 6f 32 61 76 63 31 6d 70 34 31 |isomiso2avc1mp41|
...
从这里我注意到我的Pydicom
导出包含 16 个额外的前导字节。一旦我通过 删除它们Path(out_mp4_filename).write_bytes(ds.PixelData[16:])
,我就可以得到与 完全相同的可播放视频导出dcmdump
。
因此,我的问题是:这 16 个额外的字节来自哪里,它们的含义是什么,我是否可以安全地删除它们?
您之所以看到这些字节,是因为像素数据被封装了。使用dcmdump可以清楚地显示这一点:
如果您检查剥离的前导字节,您会发现它们包含相应的分隔符标记,如转储输出中所示。您还可以看到其中包含 2 个项目,其中第一个是空的 - 这些是您使用 dcmtk 获得的。
要获取封装的内容,您可以
encaps.defragment_data
在 pydicom 2.x 中使用,它会返回一个数据块中包含的所有片段(在 pydicom 3 中,接口将更改为一次产生一个片段):请注意,通常情况下,片段是多帧数据的一部分(最常见的情况是每帧一个片段),您可能需要单独处理它们。在 MPEG4 的情况下,只有一个包含视频数据的连续数据流,合并可能被分割成的任何片段是处理这种情况的正确方法。