Смещение 16 байт при экспорте видео MPEG-4 из файла DICOM

Краткая версия: откуда берется 16-байтовое смещение при экспорте видеопотока MPEG-4 из файла DICOM с помощью Pydicom с помощью следующего кода? (И дополнительный вопрос: всегда ли это смещение на 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

Для воспроизводимости можно использовать, например, этот файл DICOM , который я нашел в этом старом обсуждении в группах Google (предупреждение о содержании: видео показывает открытый мозг во время нейрохирургического вмешательства).

Длинная версия

У меня есть несколько файлов DICOM, содержащих хирургические видеопотоки MPEG-4 (UID синтаксиса передачи 1.2.840.10008.1.2.4.102 – MPEG-4 AVC/H.264 High Profile/Level 4.1). Я хотел экспортировать видеопотоки из файлов DICOM для упрощения обработки последующих задач.

Немного погуглив, я нашел следующее обсуждение , предлагающее использование dcmdump из 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 дополнительных байтов, каково их значение и можно ли безопасно просто удалить их?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина, по которой вы видите эти байты, заключается в том, что данные пикселей инкапсулированы. Использование dcmdump ясно показывает это:

(7fe0,0010) OB (PixelSequence #=2)                      # u/l, 1 PixelData
  (fffe,e000) pi (no value available)                     #   0, 1 Item
  (fffe,e000) pi 00\00\00\20\66\74\79\70\69\73\6f\6d\00\00\02\00\69\73\6f\6d\69\73... # 13548606, 1 Item
(fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem

Если вы проверите удаляемые ведущие байты, вы увидите, что они содержат соответствующие теги-разделители, как показано в выводе дампа. Вы также можете увидеть, что там содержатся 2 элемента, первый из них пустой — это те, которые вы получаете с помощью dcmtk.

Чтобы получить инкапсулированное содержимое, вы можете использовать encaps.defragment_data в pydicom 2.x, который возвращает все содержащиеся фрагменты в одном блоке данных (в pydicom 3 интерфейс изменится, чтобы выдавать по одному фрагменту за раз):

    from pydicom import dcmread, encaps

    ds = dcmread"test_720.dcm")
    with open("test_720.mpeg4", "wb") as f:
        f.write(encaps.defragment_data(ds.PixelData))

Обратите внимание, что в целом фрагменты являются частями многокадровых данных (в наиболее распространенном случае — по одному фрагменту на кадр), и вы можете обрабатывать их отдельно. В случае MPEG4 существует только один непрерывный поток данных с видеоданными, и правильным способом решения этой проблемы является объединение любых фрагментов, на которые он может быть разделен.

Большое спасибо! Я не знал об инкапсуляции и фрагментах. Чтобы внести ясность в отношении вашего утверждения: «в вашем случае… один инкапсулированный фрагмент с видеоданными…»: разве в моем случае нет двух фрагментов (0-байтовый и соответствующий) и defragment_data() принимает заботиться о них, соединяя их? Другими словами: два элемента, содержащиеся в выводе dcmdump, — что это, если не фрагменты?

simon 07.08.2024 14:42

Правда, фрагменты срастаются, что во многих случаях может вообще не быть проблемой. Поправлю в ответе, было неряшливо...

MrBean Bremen 07.08.2024 15:42

Еще раз большое спасибо – и за ответ, и за разъяснения! Я не очень хорошо знаком с внутренним устройством DICOM, поэтому очень ценю ваше время и усилия.

simon 07.08.2024 16:03

Другие вопросы по теме