Можно ли прочитать файл DICOM из объекта BytesIO?

Я использую python 3.6 в Windows для извлечения файла DICOM из базы данных в виде строки байтов. Теперь я хотел бы использовать библиотеку Pydicom для чтения содержимого файла. Метод dcmread() принимает файловый объект в качестве основного аргумента, однако следующий фрагмент кода вызывает ошибку при попытке доступа к сохраненным изображениям:

import sqlite3 as sql, io

...
dicom_as_bytes = cursor.fetchone()[0] # read bytes from sqlite3 request
dicom_as_bytes = io.BytesIO(dicom_as_bytes) # convert to file-like format

dcm_file = dcmread(dicom_as_bytes)
images = dcm_file.pixel_array # PermissionError: [Errno 13] Permission denied: 'C:\\Users\\<User>\\AppData\\Local\\Temp\\tmpfhvgc2oo'

С запросом sql сам по себе проблем нет, потому что я смог записать в постоянный файл и прочитать его:

tmp_file = open("tmp", "wb")
tmp_file.write(dicom_as_bytes)
tmp_file.close()

dcm_file = dcmread("tmp")
images = dcm_file.pixel_array # no error

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

Вот pydicom документация по методу dcmread: ссылка< /а>

Вышеупомянутый метод работает. Однако я бы предпочел не создавать такой временный файл в папке проекта. Я также взглянул на библиотеку временных файлов Python, которая, похоже, не работает. у меня тоже по той или иной причине:

import tempfile

tmp_file = tempfile.NamedTemporaryFile()
temp_file.write(dicom_as_bytes)
temp_file.seek(0)

dcm_file = dcmread(temp_file)
images = dcm_file.pixel_array # TypeError: GDCM could not read DICOM image

temp_file.close()

В конце концов, я хотел бы знать, можно ли использовать BytesIO или tempfile для загрузки изображений файла DICOM из sqlite3 байтов данных, точно соответствующих sqlite3.Binary(open("file.dcm", "rb).read()) с "file.dcm" файлом DICOM, хранящим более одного изображения. Я бы предпочел не использовать временный файл явно, потому что у меня не должно быть причин использовать временные файлы (нет нехватки памяти, места для хранения, я также не работаю над межпроцессным взаимодействием или аварийным восстановлением).

Мне интересно, есть ли необходимость как-то кодировать полученные байты перед созданием нового объекта BytesIO или записью в TemporaryFile. Однако это не так, потому что я могу просто записать их прямо в файл с open(filename, mode).write(dicom_bytes) или TemporaryFile().write(dicom_bytes). Просто, с одной стороны, я могу получить доступ к массиву изображений, а с другой — нет (хотя я могу без проблем получить доступ к базовой информации, такой как dcm_file.filename). Возможно, сработает преобразование объекта BytesIO в объект FileIO, хотя я понятия не имею, как это сделать, не создавая новый файл с open.


person SpaceBurger    schedule 18.01.2021    source источник
comment
Какие версии pydicom и GDCM вы используете? Возникла связанная проблема из-за того, что GDCM › v2.8.8 не мог считывать пиксельные данные из памяти.   -  person MrBean Bremen    schedule 18.01.2021
comment
Я только что проверил: я использую pydicom 2.1.2 и gdcm 2.8.4. Должно быть, я скачал его с conda forge.   -  person SpaceBurger    schedule 18.01.2021
comment
Так что это кажется действительно связанным - это может объяснить, почему я не могу читать изображения с экземпляром BytesIO в качестве источника декодирования, но в версии 2.1.2 pydicom это должно быть исправлено с помощью PR 1157. И действительно, когда я пытаюсь получить доступ к данным пикселей, python пытается получить доступ к временному файлу, как описано в исправлении, но не может, и я не понимаю, почему. (PermissionError: [Errno 13] Permission denied...)   -  person SpaceBurger    schedule 18.01.2021
comment
Я предлагаю вам открыть проблему в pydicom, чтобы исследовать это.   -  person MrBean Bremen    schedule 18.01.2021
comment
При попытке воспроизвести ошибку, чтобы сделать MRE для отчета об ошибке, я снова запустил весь процесс, и теперь он работает нормально. Я не знаю, почему, возможно, данные в моей базе данных не были загружены корректно. Спасибо, что нашли время ответить, теперь я закрою эту тему.   -  person SpaceBurger    schedule 18.01.2021


Ответы (2)


Попытка сделать что-то подобное должна работать с pydicom 2.1.2 и gdcm 2.8.4:

from pydicom import dcmread               
from pydicom.data import get_testdata_file
import io, sqlite3 as sql

testdata_filepath = get_testdata_file("MR_small.dcm")
dicom_as_bytes = open(testdata_filepath, "rb")

# to sql, supposing we have one table named "Dicoms" with two columns "name" and "data"
connection = sql.connect("test.sqlite")
cursor = connection.cursor()
cursor.execute("insert into Dicoms values (?, ?);", (dataset_name, sql.Binary(dicom_as_bytes.read())))
connection.commit()
connection.close()
dicom_as_bytes.close()

# from sql
connection = sql.connect("test.sqlite")
cursor = connection.cursor()
cursor.execute("select (data) from Dicoms where name=?;", (dataset_name,))
connection.commit()

res = cursor.fetchone()[0]

connection.close()

dicom_as_bytesio = io.BytesIO(res)
dicom = dcmread(dicom_as_bytesio)
print(dicom.pixel_array)
person SpaceBurger    schedule 18.01.2021

Я использую так же, как @SpaceBurger, только еще один параметр, force

ds = pydicom.dcmread(BytesIO(buffer_memory), force=True)
person Grimmer Kang    schedule 08.05.2021