Это часть 3 применения глубокого обучения на рентгеновских изображениях. Здесь основное внимание будет уделено просмотру и анализу рентгеновских изображений с помощью Python.

Теперь, когда мы увидели, как трудно неподготовленному специалисту интерпретировать рентгеновские изображения, давайте рассмотрим несколько методов просмотра и анализа изображений, их гистограмм, а также метод объединения изображений и меток с помощью программирования на Python. .

Набор данных изображения:

Набор данных изображений (рентген грудной клетки) был получен от Kaggle. Датасет доступен по следующей ссылке — https://www.kaggle.com/paultimothymooney/chest-xray-pneumonia/data

О наборе данных — прямая цитата из задачи Kaggle — набор данных организован в 3 папки (train, test, val) и содержит подпапки для каждой категории изображений (пневмония/норма). Имеется 5863 рентгеновских изображения (JPEG) и 2 категории (пневмония/норма). Рентгенограммы грудной клетки (передне-задние) были отобраны из ретроспективных когорт педиатрических пациентов в возрасте от одного до пяти лет из Женского и детского медицинского центра Гуанчжоу, Гуанчжоу. Все рентгенограммы органов грудной клетки выполнялись в рамках рутинной клинической помощи пациентам. Для анализа рентгенограмм грудной клетки все рентгенограммы грудной клетки первоначально подвергались скринингу для контроля качества путем удаления всех низкокачественных или неразборчивых сканов. Диагнозы для изображений были затем оценены двумя врачами-экспертами, прежде чем они были одобрены для обучения системы искусственного интеллекта. Чтобы учесть любые ошибки оценки, набор оценок также был проверен третьим экспертом.

Как ясно указано в содержании, всего в задаче доступно 5863 изображения, которые были разделены на 2 класса: пневмония и норма, а затем разделены на наборы для обучения/тестирования и проверки. Чтобы еще больше усложнить задачу, мы разделили данные на три класса: нормальный, бактериальная пневмония и вирусная пневмония. В этой части мы сосредоточимся только на изображениях — загрузим их с помощью Python, проанализируем различные важные аспекты изображения с точки зрения медицинской визуализации и загрузим изображения и метки вместе. Давайте погрузимся прямо в это.

Импорт необходимых библиотек

#importing all the necessary libraries

import numpy as np                     
import matplotlib.pyplot as plt
import os
import cv2 as cv
import random

Numpy — Numpy — одна из наиболее часто используемых библиотек в Python. Он используется для операций с многомерными массивами и матрицами и выполнения высокоуровневых математических функций для работы с этими массивами.

Matplotlib — библиотека для создания статических и анимированных визуализаций на python.

os — модуль, встроенный в python. Он предоставляет функции для взаимодействия с операционной системой.

cv2 — OpenCV (библиотека компьютерного зрения с открытым исходным кодом) — очень важная библиотека, в основном используемая для компьютерного зрения. Другими подобными библиотеками являются SimpleITK и Pillow (библиотека изображений Python).

random — модуль, генерирующий псевдослучайные числа.

Исследование одного изображения из набора данных:

#load a single image from the bacteria folder

def load_image(path):
    for img in os.listdir(bacteria_path):
        print('Image name =',img)
        image = cv.imread(os.path.join(bacteria_path, img))
        break
        
    return image

Как упоминалось ранее, изображения из набора данных были разделены на три класса. 1-нормальный, 2-бактериальный (бактериальная пневмония), 3-вирусный (вирусная пневмония).

Приведенный выше фрагмент кода создает функцию load_image, которая будет использоваться для загрузки одного изображения из обучающих наборов, папки Bacteria. os.listdir используется для вывода списка всех файлов, присутствующих в этом каталоге. В этом случае его можно использовать для доступа ко всем изображениям, присутствующим в папке Bacteria. Далее он напечатает имя изображения. Наконец, для чтения изображения используется библиотека OpenCV.

Break- здесь необходим, чтобы доступ был только к первому изображению, иначе функция будет перебирать все изображения, находящиеся внутри папки Bacteria.

# Investigate a single image

bacteria_path = 'H:/All Files/Kaggle/chest_xray/train/2_BACTERIA/'

image = load_image(bacteria_path)
plt.imshow(image, cmap='gray')
plt.colorbar()
plt.title('Raw Chest X Ray Image')
print(f"The dimensions are {image.shape[0]} pixels height and {image.shape[1]} pixels width")
print(f"The maximum pixel value is {image.max():.4f}")
print(f"The minimum pixel value is {image.min():.4f}")
print(f"The mean value of the pixels is {image.mean():.4f}")
print(f"The standard deviation is {image.std():.4f}")

вывод-

В этом фрагменте кода сначала определяется путь к изображениям. Затем первое изображение из папки загружается в переменную image, вызывая функцию load_image. Затем изображение просматривается с помощью matplotlib.imshow. После этого распечатываются размеры изображения, максимальное значение пикселя и минимальное значение пикселя в полосе оттенков серого. Также рассчитываются среднее значение и стандартное отклонение пикселей изображения.

Далее мы строим гистограмму всех пикселей изображения. Гистограмма – это графическое отображение данных с использованием столбцов разной высоты.

# plot a histogram
plt.hist(image.ravel(),256,[0,256]) 
plt.show()

Вывод-

Matplotlib.hist используется для построения гистограммы. Поскольку изображение в основном темное, мы видим огромное скопление пикселей в нулевой позиции полосы оттенков серого.

Это некоторые основные функции, которые можно выполнять с изображениями с помощью OpenCV и matplotlib. В последующих частях мы увидим больше применений OpenCV.

Совместная загрузка изображений и меток и изменение размера изображений

# loading the path of the train images

path = 'H:/All Files/Kaggle/chest_xray/train/'
train = os.listdir(path)

Путь обучающего набора определен, а каталоги по пути сохраняются в «поезде». В данном случае есть три папки: 1_Normal, 2_Bacteria и 3_Virus.

folders=[]
folders = [f for f in sorted(os.listdir(path))]
print(folders)

вывод-

[‘1_НОРМАЛЬНОЕ’, ‘2_БАКТЕРИИ’, ‘3_ВИРУС’]

Создаем пустой список — папки. Затем переберите путь, используя os.listdir, отсортируйте и сохраните имена папок в списке — «папки».

labels = folders
print (f'The labels are {labels}')

# setting the size of images that we want

image_size = 256
print(f'All images to be resized into {image_size}*{image_size} pixels')

вывод-

Имена папок устанавливаются в качестве меток для изображений, а размер изображения выбран равным 256*256. То есть все изображения будут изменены в размере 256*256. Если мы пройдемся по набору данных, мы увидим, что все изображения имеют разные размеры, и для подачи изображений в сверточную нейронную сеть (CNN) необходимо изменить размер изображений до тех же размеров.

# defining a function to load images and labels together
# this function will also resize the images

def load_train(path):
    
    images = []
    
    for label in labels:
        direc = os.path.join(path, label)
        class_num = labels.index(label)
        
        for image in os.listdir(direc):
            image_read = cv.imread(os.path.join(direc,image),cv.IMREAD_GRAYSCALE)
            image_resized = cv.resize(image_read,(image_size,image_size))
            images.append([image_resized,class_num])
            
    return np.array(images)

Здесь мы определяем функцию для загрузки всех изображений в соответствии с именами меток, изменяем их размер до 256*256 пикселей и возвращаем массивы изображений.

Создается пустой список для сохранения всех изображений. Затем запускается цикл for для извлечения всех изображений из всех трех папок. os.path.join используется для объединения путей из каталогов. cv.IMREAD_GRAYSCALE преобразует все изображения в формат оттенков серого. cv.resize используется для изменения размера изображения до 256*256 пикселей. «.append» используется для добавления всех изображений в список, который, наконец, преобразуется в массив и возвращается с помощью оператора return.

#load all the training images to train_images

train_images = load_train(path)

print(f'Shape of the training images = {train_images.shape}')

output- Форма обучающих изображений = (5208, 2)

Затем вызывается функция load_train, и все обучающие изображения сохраняются в виде массива в train_images. Форма обучающих изображений (5208,2)

#loading the images and labels seperately in X and y, to be used later for training
X = []
y = []

for feature, label in train_images:
    X.append(feature)
    y.append(label)
    
print (f'Length of X = {len(X)}')
print (f'Length of y = {len(y)}')

вывод -

Изображения и метки должны быть разделены для обучения нейронной сети, и это делается путем перебора изображений train_images и извлечения изображений и соответствующих им меток.

# checking the number of images of each class

a = 0
b = 0
c = 0

for label in y:
    if label == 0:
        a += 1
    if label == 1:
        b += 1
    if label == 2:
        c += 1
        
print (f'Number of Normal images = {a}')
print (f'Number of Bacteria images = {b}')
print (f'Number of Virus images = {c}')

# plotting the data

x_pos = [i for i, _ in enumerate(labels)]
numbers = [a,b,c]
plt.bar(x_pos,numbers,color = 'green')
plt.xlabel("Labels")
plt.ylabel("No. of images")
plt.title("Images for each label")

plt.xticks(x_pos, labels)

plt.show()

вывод-

Для проверки количества изображений в каждом классе был запущен цикл for. Затем результаты отображаются с использованием matplotlib.bar, который используется для создания гистограмм.

Из данных видно, что существует большая разница в количестве изображений, принадлежащих каждой метке. Если сеть обучается именно с таким количеством изображений, она может быть смещена в сторону класса с наибольшим количеством меток. Это известно как проблема дисбаланса классов. Следовательно, необходимо, чтобы каждый класс имел одинаковое количество изображений, о чем мы поговорим в следующей части.

# Displays images 
# Extract 9 random images
print('Display Random Images')

# Adjust the size of your images
plt.figure(figsize=(20,10))

for i in range(9):
    num = random.randint(0,len(X)-1)
    plt.subplot(3, 3, i + 1)
    
    plt.imshow(X[num],cmap='gray')
    plt.axis('off')
    
# Adjust subplot parameters to give specified padding
plt.tight_layout()

Наконец, мы используем модуль random для генерации девяти случайных изображений из обучающего набора, а затем используем matplotlib для построения этих изображений.

Это конец этой части. Как мы видим, для анализа медицинских изображений в первую очередь очень важно правильно понять набор данных, в данном случае рентгеновские изображения. В следующей части мы рассмотрим проблему дисбаланса классов и другие операции с использованием matplotlib и OpenCV.

Использованная литература:

  1. Набор данных получен от: Кермани, Даниэль; Чжан, Кан; Голдбаум, Майкл (2018 г.), «Маркированная оптическая когерентная томография (ОКТ) и рентгенограммы органов грудной клетки для классификации», Mendeley Data, v2http://dx.doi.org/10.17632/rscbjbr9sj.
  2. Выявление медицинских диагнозов и излечимых заболеваний с помощью глубокого обучения на основе изображений (2018 г.), автор: Дэниел С. Кермани, Майкл Голдбаум, Вэньцзя Кай, Каролина К.С. , Фанбин Ян, Джастин Донг, Маде К. Прасадха, Жаклин Пей, Магдалина Ю.Л. Тинг, Цзе Чжу, Кристина Ли, Сьерра Хьюетт и др., Публикация: Издатель Cell: Elsevier.