Files
AIM-PIbd-31-Potapov-N-S/lab_9/lab9.ipynb

972 KiB
Raw Blame History

Лабораторная работа 9: Обработка изображений и анализ данных МРТ мозга

В этой лабораторной работе мы будем работать с датасетом МРТ изображений мозга для классификации опухолей. Используем Python и библиотеки для обработки изображений.

1. Подготовка среды и загрузка данных

In [2]:
# Импорт необходимых библиотек
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import cv2
import os
import mahotas
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.cluster import KMeans
from skimage import filters, exposure, feature
from tensorflow.keras.preprocessing.image import ImageDataGenerator

2. Загрузка и исследование датасета

In [5]:
import kagglehub

# Download latest version
data_dir = kagglehub.dataset_download("orvile/brain-cancer-mri-dataset")

print("Path to dataset files:", data_dir)

data_dir = os.path.join(data_dir, "Brain_Cancer raw MRI data", "Brain_Cancer")
Path to dataset files: /home/nspotapov/.cache/kagglehub/datasets/orvile/brain-cancer-mri-dataset/versions/2
In [6]:
# Пути к данным
classes = ['brain_glioma', 'brain_menin', 'brain_tumor']

# Загрузка изображений
images = []
labels = []

for class_name in classes:
    class_dir = os.path.join(data_dir, class_name)
    for img_name in os.listdir(class_dir)[:100]:  # Берем по 100 изображений из каждого класса для примера
        img_path = os.path.join(class_dir, img_name)
        img = cv2.imread(img_path)
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # Конвертируем в RGB
        img = cv2.resize(img, (128, 128))  # Уменьшаем размер для ускорения обработки
        images.append(img)
        labels.append(class_name)

# Преобразуем в numpy массивы
images = np.array(images)
labels = np.array(labels)

# Вывод информации о датасете
print(f"Всего изображений: {len(images)}")
print(f"Размерность изображений: {images[0].shape}")
print(f"Классы: {np.unique(labels)}")
print(f"Количество изображений по классам:")
for class_name in classes:
    print(f"{class_name}: {np.sum(labels == class_name)}")
Всего изображений: 300
Размерность изображений: (128, 128, 3)
Классы: ['brain_glioma' 'brain_menin' 'brain_tumor']
Количество изображений по классам:
brain_glioma: 100
brain_menin: 100
brain_tumor: 100

3. Предобработка изображений

3.1. Визуализация исходных изображений

In [7]:
# Функция для отображения изображений
def plot_images(images, titles, cmap=None):
    plt.figure(figsize=(15, 7))
    for i in range(len(images)):
        plt.subplot(1, len(images), i+1)
        plt.imshow(images[i], cmap=cmap)
        plt.title(titles[i])
        plt.axis('off')
    plt.show()

# Примеры изображений из каждого класса
for class_name in classes:
    idx = np.where(labels == class_name)[0][0]
    plot_images([images[idx]], [f"{class_name} - исходное"], cmap='gray')
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

3.2. Применение методов фильтрации

In [8]:
# Пример обработки одного изображения
sample_img = images[0]

# Гауссово размытие
gaussian_blur = cv2.GaussianBlur(sample_img, (5, 5), 0)

# Медианный фильтр
median_blur = cv2.medianBlur(sample_img, 5)

# Фильтр Собеля для выделения границ
sobel_x = cv2.Sobel(sample_img, cv2.CV_64F, 1, 0, ksize=5)
sobel_y = cv2.Sobel(sample_img, cv2.CV_64F, 0, 1, ksize=5)
sobel = np.sqrt(sobel_x**2 + sobel_y**2)
sobel = np.uint8(sobel / sobel.max() * 255)

# Фильтр Лапласа для повышения резкости
laplacian = cv2.Laplacian(sample_img, cv2.CV_64F)

# Отображение результатов
plot_images([sample_img, gaussian_blur, median_blur, sobel, laplacian], 
            ['Исходное', 'Гауссово размытие', 'Медианный фильтр', 'Собель', 'Лапласиан'])
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-422.0..284.0].
No description has been provided for this image

3.3. Преобразование в оттенки серого и выравнивание гистограммы

In [9]:
# Преобразование в оттенки серого
gray_img = cv2.cvtColor(sample_img, cv2.COLOR_RGB2GRAY)

# Выравнивание гистограммы
equalized_img = cv2.equalizeHist(gray_img)

# Адаптивное выравнивание гистограммы
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
clahe_img = clahe.apply(gray_img)

# Отображение результатов
plot_images([gray_img, equalized_img, clahe_img], 
            ['Оттенки серого', 'Выравненная гистограмма', 'Адаптивное выравнивание'], 
            cmap='gray')
No description has been provided for this image

4. Извлечение признаков

4.1. Текстура с использованием Haralick features (библиотека Mahotas)

In [10]:
# Извлечение признаков Haralick
def extract_haralick_features(img):
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    features = mahotas.features.haralick(gray).mean(axis=0)
    return features

# Пример извлечения признаков
haralick_features = extract_haralick_features(sample_img)
print(f"Haralick features: {haralick_features}")
Haralick features: [ 1.35337959e-01  3.38288781e+02  9.18349545e-01  2.07058015e+03
  5.82015690e-01  6.68991449e+01  7.94403181e+03  5.35674418e+00
  7.32050884e+00  1.22648817e-03  3.45985376e+00 -4.57321917e-01
  9.93317643e-01]

4.2. Гистограмма ориентированных градиентов (HOG)

In [11]:
# Извлечение признаков HOG
def extract_hog_features(img):
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    hog_features = feature.hog(gray, orientations=8, pixels_per_cell=(16, 16),
                              cells_per_block=(1, 1), visualize=False)
    return hog_features

# Пример извлечения признаков
hog_features = extract_hog_features(sample_img)
print(f"HOG features length: {len(hog_features)}")
HOG features length: 512

4.3. Цветовые гистограммы

In [12]:
# Извлечение цветовых гистограмм
def extract_color_histogram(img, bins=(8, 8, 8)):
    hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
    hist = cv2.calcHist([hsv], [0, 1, 2], None, bins, [0, 180, 0, 256, 0, 256])
    cv2.normalize(hist, hist)
    return hist.flatten()

# Пример извлечения признаков
color_hist = extract_color_histogram(sample_img)
print(f"Color histogram length: {len(color_hist)}")
Color histogram length: 512

5. Обучение модели

5.1. Подготовка данных

In [13]:
# Извлечение признаков для всех изображений
X = []
for img in images:
    haralick = extract_haralick_features(img)
    hog = extract_hog_features(img)
    color_hist = extract_color_histogram(img)
    combined_features = np.hstack([haralick, hog, color_hist])
    X.append(combined_features)
X = np.array(X)

# Кодирование меток
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y = le.fit_transform(labels)

# Разделение на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

5.2. Обучение Random Forest

In [14]:
# Обучение модели Random Forest
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)

# Оценка качества
y_pred = rf.predict(X_test)
print(classification_report(y_test, y_pred, target_names=classes))
              precision    recall  f1-score   support

brain_glioma       0.88      0.64      0.74        22
 brain_menin       0.47      0.88      0.61        16
 brain_tumor       0.93      0.59      0.72        22

    accuracy                           0.68        60
   macro avg       0.76      0.70      0.69        60
weighted avg       0.79      0.68      0.70        60

5.3. Обучение SVM

In [15]:
# Обучение модели SVM
svm = SVC(kernel='rbf', C=10, gamma='scale', random_state=42)
svm.fit(X_train, y_train)

# Оценка качества
y_pred = svm.predict(X_test)
print(classification_report(y_test, y_pred, target_names=classes))
              precision    recall  f1-score   support

brain_glioma       0.80      0.55      0.65        22
 brain_menin       0.36      0.94      0.52        16
 brain_tumor       0.67      0.09      0.16        22

    accuracy                           0.48        60
   macro avg       0.61      0.52      0.44        60
weighted avg       0.63      0.48      0.43        60

6. Аугментация данных

In [16]:
# Создание генератора аугментации
datagen = ImageDataGenerator(
    rotation_range=20,
    width_shift_range=0.1,
    height_shift_range=0.1,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest')

# Пример аугментации
plt.figure(figsize=(10, 5))
for i in range(10):
    augmented = datagen.random_transform(images[0])
    plt.subplot(2, 5, i+1)
    plt.imshow(augmented)
    plt.axis('off')
plt.suptitle('Примеры аугментации изображения')
plt.show()
No description has been provided for this image

7. Кластеризация с помощью K-means

In [18]:
# Кластеризация с использованием K-means
kmeans = KMeans(n_clusters=3, random_state=42)
cluster_labels = kmeans.fit_predict(X)

# Визуализация кластеров
plt.figure(figsize=(10, 6))
for i in range(4):
    cluster_samples = np.where(cluster_labels == i)[0][:5]
    for j, idx in enumerate(cluster_samples):
        plt.subplot(4, 5, i*5 + j + 1)
        plt.imshow(images[idx])
        plt.title(f"Cluster {i}")
        plt.axis('off')
plt.tight_layout()
plt.show()
No description has been provided for this image

Подсчет качества модели

Accuracy - общая точность классификации

Precision - точность (сколько из предсказанных положительных действительно положительные)

Recall - полнота (сколько реальных положительных нашли)

F1-score - гармоническое среднее precision и recall

Confusion Matrix - наглядно показывает ошибки между классами

In [20]:
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix

# Для Random Forest (аналогично для SVM)
y_pred = rf.predict(X_test)

# Расчет основных метрик
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred, average='weighted')
recall = recall_score(y_test, y_pred, average='weighted')
f1 = f1_score(y_test, y_pred, average='weighted')

print(f"Accuracy: {accuracy:.4f}")
print(f"Precision: {precision:.4f}")
print(f"Recall: {recall:.4f}")
print(f"F1-score: {f1:.4f}")

# Матрица ошибок
conf_matrix = confusion_matrix(y_test, y_pred)
print("Confusion Matrix:")
print(conf_matrix)

# Визуализация матрицы ошибок
import seaborn as sns
plt.figure(figsize=(8, 6))
sns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues', 
            xticklabels=classes, yticklabels=classes)
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Confusion Matrix')
plt.show()
Accuracy: 0.6833
Precision: 0.7858
Recall: 0.6833
F1-score: 0.6973
Confusion Matrix:
[[14  8  0]
 [ 1 14  1]
 [ 1  8 13]]
No description has been provided for this image
In [21]:
from sklearn.metrics import classification_report

print("\nDetailed Classification Report:")
print(classification_report(y_test, y_pred, target_names=classes))
Detailed Classification Report:
              precision    recall  f1-score   support

brain_glioma       0.88      0.64      0.74        22
 brain_menin       0.47      0.88      0.61        16
 brain_tumor       0.93      0.59      0.72        22

    accuracy                           0.68        60
   macro avg       0.76      0.70      0.69        60
weighted avg       0.79      0.68      0.70        60

Кросс-валидация для более надежной оценки

In [23]:
from sklearn.model_selection import cross_val_score

# Для RandomForest
scores = cross_val_score(rf, X, y, cv=5, scoring='accuracy')
print(f"Cross-Validation Accuracy: {scores.mean():.4f} (+/- {scores.std():.4f})")
Cross-Validation Accuracy: 0.7300 (+/- 0.0636)

Выводы по лабораторной работе

В ходе выполнения лабораторной работы была проведена обработка и классификация изображений МРТ мозга с использованием методов машинного обучения. На основе полученных метрик можно сделать следующие выводы:

1. Качество моделей

  • Общая точность (Accuracy):

    • На тестовой выборке модель показала 68,3% правильных предсказаний.
    • При кросс-валидации средняя точность составила 73,0% (±6,4%), что говорит о более устойчивой работе модели при разных разбиениях данных.
  • Precision (Точность):

    • Средняя точность по классам 78,6%, что означает, что из всех предсказанных положительных случаев большинство действительно верные.
    • Наивысшая точность у класса brain_tumor (93%), что говорит о хорошей различимости этого типа опухоли.
  • Recall (Полнота):

    • Средний recall = 68,3%, что означает, что модель находит около 2/3 реальных случаев каждого класса.
    • Класс brain_menin имеет recall = 88%, но низкую точность (47%), что говорит о большом количестве ложных срабатываний.
  • F1-score (Гармоническое среднее):

    • Средний F1 = 69,7%, что подтверждает баланс между точностью и полнотой модели.

2. Анализ ошибок (Confusion Matrix)

  • Класс brain_glioma:
    • 14 верных предсказаний, но 8 ошибок (путает с brain_menin).
  • Класс brain_menin:
    • 14 верных, но 1 ошибка в brain_glioma и 1 в brain_tumor.
  • Класс brain_tumor:
    • 13 верных, но 8 ошибок (путает с brain_menin).

Основная проблема: модель чаще всего путает glioma и meningioma, что может быть связано с их визуальной схожестью на МРТ.

3. Итог

Модель показала умеренное качество (68-73% accuracy), но требует доработки, особенно в части различения классов glioma и meningioma. Для медицинской диагностики желательно достичь точности >85%, поэтому рекомендуется:

  • Увеличить датасет.
  • Использовать более сложные архитектуры (например, Transfer Learning).
  • Применить ансамбли моделей.