Step 1 of 3

Как я уже говорил в файлах DICOM помимо изображения содержатся метаданные. Например: возраст, пол, модальность исследования, ФИО, часть тела и положение тела.

Давайте попробуем исследовать наши метаданные. Начнём с того, что мы уже знаем, с чтениям файла

example = 'stage_2_images/ID_01fe90211.dcm'
imagedata= pydicom.dcmread(example)

Извлечем ID пациента, возраст, пол, модальность, часть тела и рентгенологический вид изображения относительно ориентации объекта.

print("ID:", imagedata.PatientID)
print("Возраст:", imagedata.PatientAge)
print("Пол:", imagedata.PatientSex)
print("Модальность:", imagedata.Modality)
print("Часть тела:", imagedata.BodyPartExamined)
print("Рентгенологический вид изображения относительно ориентации объекта:", imagedata.ViewPosition)

Результат будет следующим:

ID : 
Возраст : 26
Пол : F
Модальность : CR
Часть тела : CHEST
Рентгенологический вид изображения относительно ориентации объекта изображения : PA

Думаю с ID, возрастом и полом (F-Female, M-Male) всё понятно. Разберемся с модальностью. Основные типы (модальности) поддерживаемых стандартом DICOM медицинских изображений представлены ниже:

  • CR — Компьютерная рентгенография (Computed Radiography);
  • CT — Компьютерная томография (Computed Tomography);
  • DX — Цифровая рентгенография (Digital Radiography);
  • MG — Маммография (Mammography).

И многие другие типы исследований.

Часть тела: CHEST - грудная клетка. С полным списком всех аббревиатур частей тела можно ознакомиться тут. Что касается вида изображения относительно ориентации объекта изображения, то для грудной клетки оно может принимать значения соответствующие прямой (передняя и задняя) и боковой (левая или правая) проекции. PA - передняя, AP - задняя.

Еще отдельно мы можем проверить есть ли в DICOM файле изображение и её размер.

if 'PixelData' in imagedata:
    rows = int(imagedata.Rows)
    cols = int(imagedata.Columns)
    print("Размер изображения : {rows:d} x {cols:d}, {size:d} байт".format(
        rows=rows, cols=cols, size=len(imagedata.PixelData)))

Результат - Размер изображения : 1024 x 1024, 158236 байт

А теперь давайте сделаем небольшой обзор данных. Например, посмотрим какое распределения возраста и пола в нашем датасете.

Начнём с распределения возраста. Построим гистограмму.

from glob import glob
import pandas as pd
import seaborn as sns

datalist = sorted(glob("stage_2_images/*.dcm")) # создадим лист содержащий пути ко всем файлам

# Для удобства анализа создадим датафрейм с метаданными
patients = []

for t in datalist:
    data = pydicom.dcmread(t)
    patient = {}
    patient["UID"] = data.SOPInstanceUID
    patient["Age"] = data.PatientAge
    patient["Sex"] = data.PatientSex
    patient["Modality"] = data.Modality
    patient["BodyPart"] = data.BodyPartExamined
    patient["ViewPosition"] = data.ViewPosition
    patients.append(patient)

df_patients = pd.DataFrame(patients, columns=["UID", "Age", "Sex", "Modality", "BodyPart", "ViewPosition"])
df_patients["Age"] = pd.to_numeric(df_patients["Age"])

# Построим гистограмму
sorted_ages = np.sort(df_patients["Age"].values)
plt.style.use('seaborn-whitegrid')
plt.figure(figsize=(15, 5))
plt.hist(sorted_ages[:-2], bins=[i for i in range(100)])
plt.title("Распределение по возрасту", fontsize=18, pad=10)
plt.xlabel("возраст", labelpad=10)
plt.xticks([i*10 for i in range(11)])
plt.ylabel("Количество", labelpad=10)
plt.show()
Распределение пациентов по возрасту
Распределение пациентов по возрасту

А теперь посмотрим на процентное соотношение мужчин и женщин.

plt.figure(figsize=(10, 10))
plt.pie([df_patients[df_patients["Sex"] == "M"].shape[0], df_patients[df_patients["Sex"] == "F"].shape[0]], labels=["М", "Ж"], autopct='%1.1f%%')
plt.show()
Процентное соотношение мужчин и женщин
Процентное соотношение мужчин и женщин



Подробно почитать про все метатеги тут.

Comments

В коде парсинга метаданных есть нехороший момент. Сначала в переменную data кладем список файлов, а затем в цикле читаем туда dicom.

Спасибо за внимательность Подправил

а можно ли из DICOM тега вынести данные по типу: компрессия (thikness) или лучевая нагрузка?

На этапе гистограмм возрастов появляется ошибка: UserWarning: Invalid value for VR UI: 'ID_fff6f183d'. Please see <https://dicom.nema.org/medical/dicom/current/output/html/part05.html#table_6.2-1> for allowed values for each VR. warnings.warn(msg)

По поводу thikness и лучевую нагрузку на практике не нужно было и не встречал*(