Files
ai-med-edu/seminars/Тема 1.1/segm2.ipynb
T

1685 lines
68 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 10197,
"status": "ok",
"timestamp": 1733327907192,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "s5gldFUP1Ta9",
"outputId": "0f3abd7a-48e9-4166-9d9f-9ee6ff65c32e"
},
"outputs": [],
"source": [
"import requests\n",
"import json\n",
"\n",
"# Пример запроса к TCIA API, предполагающий JSON формат\n",
"url = \"https://services.cancerimagingarchive.net/services/v3/TCIA/query/getSeries?Collection=TCGA-BRCA&format=json\"\n",
"response = requests.get(url)\n",
"\n",
"# Проверка ответа\n",
"if response.status_code == 200:\n",
" print(\"Данные получены успешно\")\n",
"\n",
" # Преобразование ответа в JSON\n",
" try:\n",
" data = response.json()\n",
" if data:\n",
" print(json.dumps(data, indent=4)) # Печать данных в формате JSON с отступами\n",
"\n",
" # Обработка данных\n",
" for item in data:\n",
" series_instance_uid = item.get('SeriesInstanceUID', 'N/A')\n",
" modality = item.get('Modality', 'N/A')\n",
" protocol_name = item.get('ProtocolName', 'N/A')\n",
" body_part_examined = item.get('BodyPartExamined', 'N/A')\n",
"\n",
" # Печать извлеченной информации\n",
" print(f\"SeriesInstanceUID: {series_instance_uid}\")\n",
" print(f\"Modality: {modality}\")\n",
" print(f\"ProtocolName: {protocol_name}\")\n",
" print(f\"BodyPartExamined: {body_part_examined}\")\n",
" print('-' * 30)\n",
" else:\n",
" print(\"Нет данных для отображения.\")\n",
" except json.JSONDecodeError:\n",
" print(\"Ошибка преобразования ответа в JSON.\")\n",
"else:\n",
" print(f\"Ошибка получения данных. Статус код: {response.status_code}\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1EMLEteH2PP8"
},
"source": [
"получение изображений"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 8511,
"status": "ok",
"timestamp": 1733327923136,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "_jqz40802ScS",
"outputId": "f36da207-d5e2-4753-ca64-3c38c52bbc61"
},
"outputs": [],
"source": [
"import os\n",
"import requests\n",
"\n",
"# Пример использования SeriesInstanceUID\n",
"series_instance_uid = \"1.3.6.1.4.1.14519.5.2.1.6450.4002.265963154110062013582166845425\" # Пример идентификатора\n",
"\n",
"# URL для загрузки изображений\n",
"url = f\"https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID={series_instance_uid}\"\n",
"response = requests.get(url, stream=True)\n",
"\n",
"# Путь для сохранения ZIP-файла\n",
"output_path = \"/content/images.zip\"\n",
"\n",
"# Создание необходимых папок, если их нет\n",
"folder_path = os.path.dirname(output_path)\n",
"os.makedirs(folder_path, exist_ok=True)\n",
"\n",
"# Проверка ответа и сохранение изображения\n",
"if response.status_code == 200:\n",
" print(f\"Сохранение файла в {output_path}\")\n",
" with open(output_path, \"wb\") as file:\n",
" for chunk in response.iter_content(chunk_size=128):\n",
" file.write(chunk)\n",
" print(f\"Изображения успешно загружены и сохранены как {output_path}\")\n",
"else:\n",
" print(\"Ошибка при загрузке изображений\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 487,
"status": "ok",
"timestamp": 1733327927800,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "5T9WU8e32ZwO",
"outputId": "8607816e-7b09-45e6-f2ee-028195091358"
},
"outputs": [],
"source": [
"import zipfile\n",
"\n",
"# Распаковка загруженного ZIP-файла\n",
"with zipfile.ZipFile(\"images.zip\", 'r') as zip_ref:\n",
" zip_ref.extractall(\"images\") # Папка для распакованных изображений\n",
"print(\"Файлы успешно распакованы\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 9944,
"status": "ok",
"timestamp": 1733327954427,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "wDnQciCD2nK7",
"outputId": "114de64d-1dad-4e0f-fc25-6eb2f6f2be3c"
},
"outputs": [],
"source": [
"!pip install pydicom"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 5672,
"status": "ok",
"timestamp": 1733327939856,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "fy7iue6r-qLe",
"outputId": "90f7405d-77ba-42cb-bcd1-daba88d8e46b"
},
"outputs": [],
"source": [
"pip install scikit-image"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "mHUiH_ra73lm"
},
"source": [
"Вывод 20 случайных изображений серии"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "XLX5F2QA73ku"
},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000,
"output_embedded_package_id": "1bVzJQoS5a20xhtxUvdmWXcv0JVIyOj1_"
},
"executionInfo": {
"elapsed": 6961,
"status": "ok",
"timestamp": 1733161002828,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "ZG1Ab2X-3b3W",
"outputId": "c8912e6e-d792-4147-ef1b-767e8c181ae3"
},
"outputs": [],
"source": [
"import os\n",
"import random\n",
"import pydicom\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Папка с распакованными изображениями\n",
"dicom_folder = \"images\"\n",
"\n",
"# Сбор всех DICOM-файлов в папке\n",
"dicom_files = [os.path.join(dicom_folder, filename) for filename in os.listdir(dicom_folder) if filename.endswith(\".dcm\")]\n",
"\n",
"# Проверка, что в папке достаточно файлов для выбора 20\n",
"num_files_to_show = min(20, len(dicom_files))\n",
"\n",
"# Выбор случайных файлов из списка случайным образом\n",
"random_files = random.sample(dicom_files, num_files_to_show)\n",
"\n",
"# Визуализация выбранных изображений\n",
"for dicom_path in random_files:\n",
" dicom_data = pydicom.dcmread(dicom_path)\n",
"\n",
" # Получение массива пикселей изображения\n",
" image = dicom_data.pixel_array\n",
"\n",
" # Визуализация изображения\n",
" filename = os.path.basename(dicom_path)\n",
" plt.imshow(image, cmap=\"gray\")\n",
" plt.title(f\"Файл: {filename}\\nПациент ID: {dicom_data.PatientID}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "S33pbEOx3b2k"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "2tugza_l6CgF"
},
"source": [
"После выбора изображениq, применим к нему обработку"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 878
},
"executionInfo": {
"elapsed": 23682,
"status": "ok",
"timestamp": 1733136739686,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "u0rx2vLS6oYm",
"outputId": "41fee910-4786-4c12-eeea-3a7b55ba6282"
},
"outputs": [],
"source": [
"import os\n",
"import random\n",
"import pydicom\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"import numpy as np\n",
"import skimage.restoration as restoration\n",
"\n",
"# Папка с распакованными изображениями\n",
"dicom_folder = \"images\"\n",
"\n",
"# Сбор всех DICOM-файлов в папке\n",
"dicom_files = [filename for filename in os.listdir(dicom_folder) if filename.endswith(\".dcm\")]\n",
"\n",
"# Запрос у пользователя названий файлов для отображения\n",
"file_names = input(\"Введите названия файлов изображений через запятую: \").split(\",\")\n",
"file_names = [name.strip() for name in file_names]\n",
"\n",
"# Поиск указанных файлов в папке\n",
"selected_files = []\n",
"for filename in file_names:\n",
" found_files = [os.path.join(dicom_folder, f) for f in dicom_files if filename in f]\n",
" selected_files.extend(found_files)\n",
"\n",
"# Визуализация выбранных изображений\n",
"for dicom_path in selected_files:\n",
" if os.path.exists(dicom_path):\n",
" dicom_data = pydicom.dcmread(dicom_path)\n",
"\n",
" # Получение массива пикселей изображения\n",
" image = dicom_data.pixel_array\n",
"\n",
" # Визуализация изображения\n",
" filename = os.path.basename(dicom_path)\n",
" plt.imshow(image, cmap=\"gray\")\n",
" plt.title(f\"Файл: {filename}\\nПациент ID: {dicom_data.PatientID}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n",
"\n",
"# Применение адаптивного медианного фильтра для улучшения качества изображений перед сегментацией\n",
"for dicom_path in selected_files:\n",
" if os.path.exists(dicom_path):\n",
" dicom_data = pydicom.dcmread(dicom_path)\n",
" image = dicom_data.pixel_array\n",
"\n",
" # Преобразование изображения в формат uint8, если это необходимо\n",
" if image.dtype != np.uint8:\n",
" image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)\n",
"\n",
" # Применение адаптивного медианного фильтра для сглаживания шума\n",
" filtered_image = restoration.denoise_bilateral(image, sigma_color=0.01, sigma_spatial=11, channel_axis=None)\n",
"\n",
" # Преобразование фильтрованного изображения обратно в формат uint8\n",
" filtered_image = (filtered_image * 255).astype(np.uint8)\n",
"\n",
" # Визуализация фильтрованного изображения\n",
" filename = os.path.basename(dicom_path)\n",
" plt.imshow(filtered_image, cmap=\"gray\")\n",
" plt.title(f\"Фильтрованное изображение: {filename}\")\n",
" plt.axis(\"off\")\n",
" plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "LzHtNa0oAWzx"
},
"source": [
"**watershed**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"executionInfo": {
"elapsed": 23251,
"status": "ok",
"timestamp": 1733161357153,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "_W5paV7yAaKX",
"outputId": "f9eb183c-24a7-4187-a8ab-7e82f1072fd9"
},
"outputs": [],
"source": [
"import os\n",
"import random\n",
"import pydicom\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"import numpy as np\n",
"import skimage.restoration as restoration\n",
"\n",
"# Папка с распакованными изображениями\n",
"dicom_folder = \"images\"\n",
"\n",
"# Сбор всех DICOM-файлов в папке\n",
"dicom_files = [filename for filename in os.listdir(dicom_folder) if filename.endswith(\".dcm\")]\n",
"\n",
"# Запрос у пользователя названий файлов для отображения\n",
"file_names = input(\"Введите названия файлов изображений через запятую: \").split(\",\")\n",
"file_names = [name.strip() for name in file_names]\n",
"\n",
"# Поиск указанных файлов в папке\n",
"selected_files = []\n",
"for filename in file_names:\n",
" found_files = [os.path.join(dicom_folder, f) for f in dicom_files if filename in f]\n",
" selected_files.extend(found_files)\n",
"\n",
"# Визуализация выбранных изображений\n",
"for dicom_path in selected_files:\n",
" if os.path.exists(dicom_path):\n",
" dicom_data = pydicom.dcmread(dicom_path)\n",
"\n",
" # Получение массива пикселей изображения\n",
" image = dicom_data.pixel_array\n",
"\n",
" # Обрезка верхней 1/3 изображения\n",
" height = image.shape[0]\n",
" cropped_image = image[height // 3:, :]\n",
"\n",
" # Применение адаптивного выравнивания гистограммы (CLAHE)\n",
" clahe = cv2.createCLAHE(clipLimit=0.5, tileGridSize=(3, 3))\n",
" cropped_image = clahe.apply(cropped_image.astype(np.uint8))\n",
"\n",
" # Визуализация обрезанного изображения\n",
" filename = os.path.basename(dicom_path)\n",
" plt.imshow(cropped_image, cmap=\"gray\")\n",
" plt.title(f\"Обрезанное изображение: {filename}\\nПациент ID: {dicom_data.PatientID}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n",
"\n",
"# Применение адаптивного медианного фильтра для улучшения качества изображений перед сегментацией\n",
"for dicom_path in selected_files:\n",
" if os.path.exists(dicom_path):\n",
" dicom_data = pydicom.dcmread(dicom_path)\n",
" image = dicom_data.pixel_array\n",
"\n",
" # Обрезка верхней 1/3 изображения\n",
" height = image.shape[0]\n",
" cropped_image = image[height // 3:, :]\n",
"\n",
" # Преобразование изображения в формат uint8, если это необходимо\n",
" if cropped_image.dtype != np.uint8:\n",
" cropped_image = cv2.normalize(cropped_image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)\n",
"\n",
" # Применение адаптивного медианного фильтра для сглаживания шума\n",
" filtered_image = restoration.denoise_bilateral(cropped_image, sigma_color=0.05, sigma_spatial=5, channel_axis=None)\n",
"\n",
" # Преобразование фильтрованного изображения обратно в формат uint8\n",
" filtered_image = (filtered_image * 255).astype(np.uint8)\n",
"\n",
" # Применение алгоритма водораздела для сегментации изображения\n",
" # Создание маски для водораздела\n",
" _, binary_image = cv2.threshold(filtered_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)\n",
" distance_transform = cv2.distanceTransform(binary_image, cv2.DIST_L2, 5)\n",
" _, sure_fg = cv2.threshold(distance_transform, 0.9 * distance_transform.max(), 255, 0)\n",
" sure_fg = np.uint8(sure_fg)\n",
" unknown = cv2.subtract(binary_image, sure_fg)\n",
"\n",
" # Маркировка объектов\n",
" num_markers, markers = cv2.connectedComponents(sure_fg)\n",
" markers = markers + 1\n",
" markers[unknown == 255] = 0\n",
"\n",
" # Применение водораздела\n",
" markers = cv2.watershed(cv2.cvtColor(filtered_image, cv2.COLOR_GRAY2BGR), markers)\n",
" segmented_image = np.zeros_like(filtered_image)\n",
" segmented_image[markers == -1] = 255\n",
"\n",
" # Наложение сегментированного изображения на исходное с зелеными границами\n",
" original_image_bgr = cv2.cvtColor(cropped_image, cv2.COLOR_GRAY2BGR)\n",
" original_image_bgr[markers == -1] = [0, 255, 0] # Установка зеленого цвета для границ\n",
"\n",
" # Визуализация наложенного изображения\n",
" filename = os.path.basename(dicom_path)\n",
" plt.imshow(cv2.cvtColor(original_image_bgr, cv2.COLOR_BGR2RGB))\n",
" plt.title(f\"Сегментированное изображение с наложением (водораздел): {filename}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "bbDf5ciOYHfS"
},
"source": [
"thresholding"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"executionInfo": {
"elapsed": 8619,
"status": "ok",
"timestamp": 1733161943856,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "7YbBnF0fYLNw",
"outputId": "29ed2b7a-1627-456a-dd32-86d0c4b06538"
},
"outputs": [],
"source": [
"import os\n",
"import random\n",
"import pydicom\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"import numpy as np\n",
"\n",
"# Папка с распакованными изображениями\n",
"dicom_folder = \"images\"\n",
"\n",
"# Сбор всех DICOM-файлов в папке\n",
"dicom_files = [filename for filename in os.listdir(dicom_folder) if filename.endswith(\".dcm\")]\n",
"\n",
"# Запрос у пользователя названий файлов для отображения\n",
"file_names = input(\"Введите названия файлов изображений через запятую: \").split(\",\")\n",
"file_names = [name.strip() for name in file_names]\n",
"\n",
"# Поиск указанных файлов в папке\n",
"selected_files = []\n",
"for filename in file_names:\n",
" found_files = [os.path.join(dicom_folder, f) for f in dicom_files if filename in f]\n",
" selected_files.extend(found_files)\n",
"\n",
"# Визуализация выбранных изображений\n",
"for dicom_path in selected_files:\n",
" if os.path.exists(dicom_path):\n",
" dicom_data = pydicom.dcmread(dicom_path)\n",
"\n",
" # Получение массива пикселей изображения\n",
" image = dicom_data.pixel_array\n",
"\n",
" # Визуализация изображения\n",
" filename = os.path.basename(dicom_path)\n",
" plt.imshow(image, cmap=\"gray\")\n",
" plt.title(f\"Файл: {filename}\\nПациент ID: {dicom_data.PatientID}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n",
"\n",
"# Применение обработки изображений перед сегментацией\n",
"for dicom_path in selected_files:\n",
" if os.path.exists(dicom_path):\n",
" dicom_data = pydicom.dcmread(dicom_path)\n",
" image = dicom_data.pixel_array\n",
"\n",
" # Обрезка верхней трети изображения\n",
" height, width = image.shape\n",
" cropped_image = image[height // 3: , :]\n",
"\n",
" # Преобразование изображения в формат uint8, если это необходимо\n",
" if cropped_image.dtype != np.uint8:\n",
" cropped_image = cv2.normalize(cropped_image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)\n",
"\n",
" # Применение адаптивного выравнивания гистограммы для повышения контрастности\n",
" clahe = cv2.createCLAHE(clipLimit=1.5, tileGridSize=(8, 8))\n",
" enhanced_image = clahe.apply(cropped_image)\n",
"\n",
" # Визуализация улучшенного изображения\n",
" filename = os.path.basename(dicom_path)\n",
" plt.imshow(enhanced_image, cmap=\"gray\")\n",
" plt.title(f\"Улучшенное изображение: {filename}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n",
"\n",
" # Применение пороговой сегментации\n",
" threshold_value = 100 # Порог можно изменять в зависимости от задачи\n",
" _, thresholded_image = cv2.threshold(enhanced_image, threshold_value, 255, cv2.THRESH_BINARY)\n",
"\n",
" # Визуализация пороговой сегментации\n",
" plt.imshow(thresholded_image, cmap=\"gray\")\n",
" plt.title(f\"Пороговая сегментация: {filename}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n",
"\n",
" # Наложение сегментированного изображения на исходное с зеленой линией\n",
" contours, _ = cv2.findContours(thresholded_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n",
" overlay_image = cv2.cvtColor(cropped_image, cv2.COLOR_GRAY2BGR)\n",
" cv2.drawContours(overlay_image, contours, -1, (0, 255, 0), 1)\n",
"\n",
" # Визуализация наложенного изображения\n",
" plt.imshow(cv2.cvtColor(overlay_image, cv2.COLOR_BGR2RGB))\n",
" plt.title(f\"Наложенное изображение: {filename}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "F5PIzY6Y7fXU"
},
"source": [
"FuzzyCmeans"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 3985,
"status": "ok",
"timestamp": 1733236827403,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "DPAimyHw8dSq",
"outputId": "c8edd6bd-9fe7-4595-b7b6-2152cfeda19c"
},
"outputs": [],
"source": [
"pip install fuzzy-c-means"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8RAcDcRi-ZlV"
},
"outputs": [],
"source": [
"pip install tabulate>=0.9.0"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ak9OshsrOLrl"
},
"source": [
"Обработка изображения - многослойная декомпозиция. Сегментация с Fuzzy C means"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"executionInfo": {
"elapsed": 5336,
"status": "ok",
"timestamp": 1733162965578,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "IhGYJoriAXP_",
"outputId": "0ac944eb-efe4-4516-e084-7a8adfccc256"
},
"outputs": [],
"source": [
"import cv2\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from scipy.special import expit\n",
"from fcmeans import FCM # Для Fuzzy C-means\n",
"\n",
"# Загрузка изображения\n",
"image_path = \"/content/8.png\" # Укажите путь к вашему изображению\n",
"input_image = cv2.imread(image_path)\n",
"if input_image is None:\n",
" raise FileNotFoundError(f\"Не удалось загрузить изображение по указанному пути: {image_path}\")\n",
"\n",
"# Функция для отображения изображения\n",
"def show_image(image, title):\n",
" plt.figure(figsize=(10, 10))\n",
" plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))\n",
" plt.title(title)\n",
" plt.axis('off')\n",
" plt.show()\n",
"\n",
"# Функция для разложения изображения на базовый слой и детали\n",
"def multiscale_decomposition(image, kernel_size=5):\n",
" base_layer = cv2.GaussianBlur(image, (kernel_size, kernel_size), 0)\n",
" detail_layer_1 = cv2.subtract(image, base_layer)\n",
" detail_layer_2 = cv2.subtract(base_layer, cv2.GaussianBlur(base_layer, (kernel_size, kernel_size), 0))\n",
" return base_layer, detail_layer_1, detail_layer_2\n",
"\n",
"# Функция для применения сигмоиды к каждому пикселю\n",
"def sigmoid(x, a=1):\n",
" return expit(a * x)\n",
"\n",
"# Функция для применения тонового улучшения на основе трехуровневой декомпозиции\n",
"def multiscale_tone_enhancement(image, delta_0=1.1, delta_1=2.5, delta_2=2.2, alpha=0.5):\n",
" # Разложение изображения на базовый слой и два слоя детализации\n",
" base_layer, detail_layer_1, detail_layer_2 = multiscale_decomposition(image, kernel_size=5)\n",
"\n",
" # Среднее значение яркости для каждого канала\n",
" mu = np.mean(base_layer, axis=(0, 1))\n",
"\n",
" # Применение S-симгмоиды для управления усилением деталей\n",
" S = lambda x: sigmoid((x - mu) / 255.0, a=alpha)\n",
"\n",
" # Усиление базового слоя и слоев детализации\n",
" enhanced_image = base_layer + delta_0 * (base_layer - mu) + \\\n",
" 0.9 * S(detail_layer_1) * (delta_1 * detail_layer_1) + \\\n",
" 0.9 * S(detail_layer_2) * (delta_2 * detail_layer_2)\n",
"\n",
" # Клиппинг результата в допустимый диапазон [0, 255]\n",
" enhanced_image = np.clip(enhanced_image, 0, 255).astype(np.uint8)\n",
" return enhanced_image\n",
"\n",
"# Применение тонового улучшения\n",
"enhanced_image = multiscale_tone_enhancement(input_image)\n",
"\n",
"# Преобразование изображения в градации серого для FCM\n",
"gray_image = cv2.cvtColor(enhanced_image, cv2.COLOR_BGR2GRAY)\n",
"\n",
"# Преобразование изображения в формат, подходящий для FCM\n",
"reshaped_image = gray_image.flatten().astype(np.float64) / 255.0\n",
"\n",
"# Применение Fuzzy C-means\n",
"num_clusters = 5 # Задайте количество кластеров\n",
"fcm = FCM(n_clusters=num_clusters)\n",
"fcm.fit(reshaped_image.reshape(-1, 1))\n",
"cluster_labels = fcm.u.argmax(axis=1) # Метки кластеров\n",
"\n",
"# Преобразование кластеров в форму изображения\n",
"segmented_image = cluster_labels.reshape(gray_image.shape)\n",
"\n",
"# Отображение результатов\n",
"show_image(input_image, 'Original Image')\n",
"show_image(enhanced_image, 'Enhanced Image')\n",
"plt.figure(figsize=(10, 10))\n",
"plt.imshow(segmented_image, cmap=\"jet\")\n",
"plt.title(\"Fuzzy C-means Segmentation\")\n",
"plt.axis('off')\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "v30wSTf2z2KX"
},
"source": [
"Метод активных контуров - змеек"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 3699,
"status": "ok",
"timestamp": 1733327984318,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "8w6lib4r14jZ",
"outputId": "8e5c5470-d875-4f42-8d53-2751fb295d8e"
},
"outputs": [],
"source": [
"pip install scipy"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"executionInfo": {
"elapsed": 5058,
"status": "ok",
"timestamp": 1733330809629,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "8JoBvPgwdlM1",
"outputId": "1fa592ef-8270-4b25-c99f-2fe69110a350"
},
"outputs": [],
"source": [
"import os\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"import numpy as np\n",
"from skimage.segmentation import active_contour\n",
"from scipy.spatial import distance\n",
"\n",
"# Функция для применения адаптивного медианного фильтра\n",
"def adaptive_median_filter(image, max_kernel_size=5):\n",
" filtered_image = image.copy()\n",
" height, width = image.shape\n",
"\n",
" for i in range(height):\n",
" for j in range(width):\n",
" kernel_size = 3 # Начальный размер ядра\n",
" while kernel_size <= max_kernel_size:\n",
" # Получаем область с заданным размером ядра\n",
" half_size = kernel_size // 2\n",
" x_start = max(j - half_size, 0)\n",
" x_end = min(j + half_size + 1, width)\n",
" y_start = max(i - half_size, 0)\n",
" y_end = min(i + half_size + 1, height)\n",
"\n",
" region = image[y_start:y_end, x_start:x_end]\n",
" median_value = np.median(region)\n",
"\n",
" # Если медианное значение близко к текущему пикселю, увеличиваем размер ядра\n",
" if abs(median_value - image[i, j]) < 10: # Порог можно настроить\n",
" break\n",
" kernel_size += 2 # Увеличиваем размер ядра, проверяя на большее\n",
" filtered_image[i, j] = median_value\n",
"\n",
" return filtered_image\n",
"\n",
"# Функция для объединения пересекающихся контуров\n",
"def merge_contours(contours, min_distance=10):\n",
" merged_contours = []\n",
"\n",
" while contours:\n",
" contour = contours.pop(0)\n",
" merged = False\n",
" for i, existing_contour in enumerate(merged_contours):\n",
" # Проверяем, пересекаются ли контуры (минимальное расстояние между точками)\n",
" if any(distance.euclidean(point, existing_point) < min_distance for point in contour for existing_point in existing_contour):\n",
" # Если контуры пересекаются, объединяем их\n",
" merged_contours[i] = np.vstack((existing_contour, contour))\n",
" merged = True\n",
" break\n",
" if not merged:\n",
" merged_contours.append(contour)\n",
"\n",
" return merged_contours\n",
"\n",
"# Загрузка изображения (например, PNG)\n",
"image_path = \"/content/9.png\" # Укажите путь к вашему изображению\n",
"input_image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n",
"\n",
"if input_image is None:\n",
" raise FileNotFoundError(f\"Не удалось загрузить изображение по указанному пути: {image_path}\")\n",
"\n",
"# Обрезка верхней трети изображения (три восьмых сверху)\n",
"cropped_image = input_image\n",
"\n",
"# Преобразование изображения в формат uint8, если это необходимо\n",
"if cropped_image.dtype != np.uint8:\n",
" cropped_image = cv2.normalize(cropped_image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)\n",
"\n",
"# Применение адаптивного медианного фильтра\n",
"adaptive_filtered = adaptive_median_filter(cropped_image)\n",
"\n",
"# Визуализация результата CLAHE\n",
"plt.figure(figsize=(6, 6))\n",
"plt.imshow(adaptive_filtered, cmap=\"gray\")\n",
"plt.axis(\"off\")\n",
"plt.show()\n",
"\n",
"# Инвертирование изображения перед сегментацией\n",
"inverted_image = np.invert(adaptive_filtered)\n",
"\n",
"# Применение пороговой сегментации для выделения светлых участков на инвертированном изображении\n",
"gray_threshold = np.percentile(inverted_image, 90) # Порог для серых участков, 70-й перцентиль\n",
"binary_image = inverted_image > gray_threshold # Выделяем светлые участки\n",
"\n",
"# Визуализация результата пороговой сегментации\n",
"plt.figure(figsize=(6, 6))\n",
"plt.imshow(binary_image, cmap=\"gray\")\n",
"plt.title(\"Результат пороговой сегментации (светлые участки на инвертированном изображении)\")\n",
"plt.axis(\"off\")\n",
"plt.show()\n",
"\n",
"# Найдем контуры светлых областей на бинаризованном изображении\n",
"contours, _ = cv2.findContours(binary_image.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n",
"\n",
"# Отсортируем контуры по площади и выберем 2 самых крупных\n",
"contours = sorted(contours, key=cv2.contourArea, reverse=True)[:1] # Выбираем только 2 контуры\n",
"\n",
"# Генерация начальных точек для активных контуров\n",
"init_points = []\n",
"for contour in contours:\n",
" # Найдем центры контуров\n",
" M = cv2.moments(contour)\n",
" if M['m00'] != 0:\n",
" cx = int(M['m10'] / M['m00'])\n",
" cy = int(M['m01'] / M['m00'])\n",
" init_points.append((cy, cx))\n",
"\n",
"# Инициализация контуров с центрами\n",
"init_contours = []\n",
"for point in init_points:\n",
" y, x = point\n",
" s = np.linspace(0, 2 * np.pi, 400)\n",
" r = y + 90 * np.sin(s)\n",
" c = x + 90 * np.cos(s)\n",
" init = np.array([r, c]).T\n",
" init_contours.append(init)\n",
"\n",
"# Применение метода активных контуров\n",
"fig, ax = plt.subplots()\n",
"ax.imshow(inverted_image, cmap=\"gray\") # Выводим контуры на исходном изображении\n",
"\n",
"# Объединяем пересекающиеся контуры\n",
"merged_contours = merge_contours(init_contours, min_distance=1)\n",
"\n",
"# Отображаем объединенные контуры\n",
"for init in merged_contours:\n",
" snake = active_contour(inverted_image, init, alpha=0.05, beta=0.1, gamma=0.001) # Параметры активного контура\n",
" snake[:, 0] = np.clip(snake[:, 0], 0, inverted_image.shape[0] - 1) # ограничиваем по оси Y\n",
" snake[:, 1] = np.clip(snake[:, 1], 0, inverted_image.shape[1] - 1) # ограничиваем по оси X\n",
"\n",
" # Проверяем, чтобы контуры не были в темных областях\n",
" contour_values = inverted_image[tuple(snake.astype(int).T)]\n",
"\n",
" # Если средняя яркость вдоль контура больше порога, рисуем контур\n",
" if np.mean(contour_values) >105: # Порог для яркости, можно настроить\n",
" ax.plot(snake[:, 1], snake[:, 0], '-r', lw=2)\n",
"\n",
"ax.set_title(f\"Объединенные активные контуры: {os.path.basename(image_path)}\")\n",
"ax.axis(\"off\")\n",
"plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"background_save": true
},
"id": "eKwxXTinna1u"
},
"outputs": [],
"source": [
"import os\n",
"import pydicom\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"import numpy as np\n",
"from skimage.segmentation import active_contour\n",
"from scipy.spatial import distance\n",
"from skimage.morphology import disk\n",
"\n",
"# Папка с распакованными изображениями\n",
"dicom_folder = \"images\"\n",
"\n",
"# Сбор всех DICOM-файлов в папке\n",
"dicom_files = [filename for filename in os.listdir(dicom_folder) if filename.endswith(\".dcm\")]\n",
"\n",
"# Запрос у пользователя названий файлов для отображения\n",
"file_names = input(\"Введите названия файлов изображений через запятую: \").split(\",\")\n",
"file_names = [name.strip() for name in file_names]\n",
"\n",
"# Поиск указанных файлов в папке\n",
"selected_files = []\n",
"for filename in file_names:\n",
" found_files = [os.path.join(dicom_folder, f) for f in dicom_files if filename in f]\n",
" selected_files.extend(found_files)\n",
"\n",
"# Функция для применения адаптивного медианного фильтра\n",
"def adaptive_median_filter(image, max_kernel_size=15):\n",
" filtered_image = image.copy()\n",
" height, width = image.shape\n",
"\n",
" for i in range(height):\n",
" for j in range(width):\n",
" kernel_size = 3 # Начальный размер ядра\n",
" while kernel_size <= max_kernel_size:\n",
" # Получаем область с заданным размером ядра\n",
" half_size = kernel_size // 2\n",
" x_start = max(j - half_size, 0)\n",
" x_end = min(j + half_size + 1, width)\n",
" y_start = max(i - half_size, 0)\n",
" y_end = min(i + half_size + 1, height)\n",
"\n",
" region = image[y_start:y_end, x_start:x_end]\n",
" median_value = np.median(region)\n",
"\n",
" # Если медианное значение близко к текущему пикселю, увеличиваем размер ядра\n",
" if abs(median_value - image[i, j]) < 10: # Порог можно настроить\n",
" break\n",
" kernel_size += 2 # Увеличиваем размер ядра, проверяя на большее\n",
" filtered_image[i, j] = median_value\n",
"\n",
" return filtered_image\n",
"\n",
"# Функция для объединения пересекающихся контуров\n",
"def merge_contours(contours, min_distance=10):\n",
" merged_contours = []\n",
"\n",
" while contours:\n",
" contour = contours.pop(0)\n",
" merged = False\n",
" for i, existing_contour in enumerate(merged_contours):\n",
" # Проверяем, пересекаются ли контуры (минимальное расстояние между точками)\n",
" if any(distance.euclidean(point, existing_point) < min_distance for point in contour for existing_point in existing_contour):\n",
" # Если контуры пересекаются, объединяем их\n",
" merged_contours[i] = np.vstack((existing_contour, contour))\n",
" merged = True\n",
" break\n",
" if not merged:\n",
" merged_contours.append(contour)\n",
"\n",
" return merged_contours\n",
"\n",
"# Обработка каждого выбранного DICOM файла\n",
"for dicom_path in selected_files:\n",
" if os.path.exists(dicom_path):\n",
" dicom_data = pydicom.dcmread(dicom_path)\n",
" image = dicom_data.pixel_array\n",
"\n",
" # Обрезка верхней трети изображения (три восьмых сверху)\n",
" height, width = image.shape\n",
" cropped_image = image[int(height * 3 / 8):, :]\n",
"\n",
" # Преобразование изображения в формат uint8, если это необходимо\n",
" if cropped_image.dtype != np.uint8:\n",
" cropped_image = cv2.normalize(cropped_image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)\n",
"\n",
" # Применение фильтра для увеличения яркости (CLAHE)\n",
" #clahe = cv2.createCLAHE(clipLimit=5.0, tileGridSize=(1, 1))\n",
" enhanced_image = cropped_image\n",
"\n",
" # Визуализация результата CLAHE\n",
" plt.figure(figsize=(6, 6))\n",
" plt.imshow(enhanced_image, cmap=\"gray\")\n",
" # plt.title(\"После CLAHE (выравнивание гистограммы)\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n",
"\n",
" # Применение пороговой сегментации для выделения светлых участков\n",
" gray_threshold = np.percentile(enhanced_image, 90) # Порог для серых участков, 75-й перцентиль\n",
" binary_image = enhanced_image > gray_threshold # Выделяем светлые участки\n",
"\n",
" # Инвертируем бинарное изображение, чтобы контуры были на светлых областях\n",
" # binary_image = np.invert(binary_image)\n",
"\n",
" # Визуализация результата пороговой сегментации\n",
" plt.figure(figsize=(6, 6))\n",
" plt.imshow(binary_image, cmap=\"gray\")\n",
" plt.title(\"Результат пороговой сегментации (светлые участки)\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n",
"\n",
" # Найдем контуры светлых областей\n",
" contours, _ = cv2.findContours(binary_image.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n",
"\n",
" # Отсортируем контуры по площади и выберем 3 самых больших\n",
" contours = sorted(contours, key=cv2.contourArea, reverse=True)[:2]\n",
"\n",
" # Генерация начальных точек для активных контуров\n",
" init_points = []\n",
" for contour in contours:\n",
" # Найдем центры контуров\n",
" M = cv2.moments(contour)\n",
" if M['m00'] != 0:\n",
" cx = int(M['m10'] / M['m00'])\n",
" cy = int(M['m01'] / M['m00'])\n",
" init_points.append((cy, cx))\n",
"\n",
" # Инициализация контуров с центрами\n",
" init_contours = []\n",
" for point in init_points:\n",
" y, x = point\n",
" s = np.linspace(0, 2 * np.pi, 400)\n",
" r = y + 90 * np.sin(s)\n",
" c = x + 90 * np.cos(s)\n",
" init = np.array([r, c]).T\n",
" init_contours.append(init)\n",
"\n",
" # Применение метода активных контуров\n",
" fig, ax = plt.subplots()\n",
" ax.imshow(enhanced_image, cmap=\"gray\")\n",
"\n",
" # Объединяем пересекающиеся контуры\n",
" merged_contours = merge_contours(init_contours, min_distance=10)\n",
"\n",
" # Отображаем объединенные контуры\n",
" for init in merged_contours:\n",
" snake = active_contour(enhanced_image, init, alpha=0.1, beta=0.002, gamma=0.001)\n",
" snake[:, 0] = np.clip(snake[:, 0], 0, enhanced_image.shape[0] - 1) # ограничиваем по оси Y\n",
" snake[:, 1] = np.clip(snake[:, 1], 0, enhanced_image.shape[1] - 1) # ограничиваем по оси X\n",
"\n",
" # Теперь проверяем, чтобы контуры не были в темных областях\n",
" contour_values = enhanced_image[tuple(snake.astype(int).T)]\n",
"\n",
" # Если средняя яркость вдоль контура меньше порога, не рисуем контур\n",
" if np.mean(contour_values) > 0: # Порог для яркости, можно настроить\n",
" ax.plot(snake[:, 1], snake[:, 0], '-r', lw=2)\n",
"\n",
" ax.set_title(f\"Объединенные активные контуры: {os.path.basename(dicom_path)}\")\n",
" ax.axis(\"off\")\n",
" plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "5GL9iwgn-4pr"
},
"source": [
"Графы\n",
"Графическая визуализация"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"executionInfo": {
"elapsed": 854,
"status": "ok",
"timestamp": 1733306605637,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "fN7ANg0jHxHX",
"outputId": "88a89cb6-2da4-4ea2-c4e5-25f1f07e28f5"
},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import networkx as nx\n",
"\n",
"# Создаем простое изображение как матрицу интенсивностей\n",
"image = np.array([\n",
" [10, 10, 20, 20],\n",
" [10, 10, 20, 20],\n",
" [30, 30, 40, 40],\n",
" [30, 30, 40, 40]\n",
"])\n",
"\n",
"# Визуализируем изображение и матрицу интенсивностей\n",
"fig, ax = plt.subplots(1, 2, figsize=(10, 5))\n",
"ax[0].imshow(image, cmap='gray')\n",
"ax[0].set_title('Исходное изображение')\n",
"ax[0].axis('off')\n",
"\n",
"# Отображаем матрицу интенсивностей на втором графике\n",
"for i in range(image.shape[0]):\n",
" for j in range(image.shape[1]):\n",
" ax[1].text(j, i, str(image[i, j]), ha='center', va='center', color='black')\n",
"ax[1].imshow(image, cmap='gray', alpha=0.5)\n",
"ax[1].set_title('Матрица интенсивностей')\n",
"ax[1].axis('off')\n",
"\n",
"plt.show()\n",
"\n",
"# Создаем граф из изображения\n",
"rows, cols = image.shape\n",
"graph = nx.grid_2d_graph(rows, cols)\n",
"\n",
"# Добавляем веса ребрам графа на основе разницы интенсивностей\n",
"for i in range(rows):\n",
" for j in range(cols):\n",
" if i < rows - 1:\n",
" weight = np.abs(image[i, j] - image[i + 1, j])\n",
" graph.add_edge((i, j), (i + 1, j), weight=weight)\n",
" if j < cols - 1:\n",
" weight = np.abs(image[i, j] - image[i, j + 1])\n",
" graph.add_edge((i, j), (i, j + 1), weight=weight)\n",
"\n",
"# Визуализируем граф\n",
"pos = {(i, j): (j, -i) for i, j in graph.nodes()}\n",
"weights = [graph[u][v]['weight'] for u, v in graph.edges()]\n",
"\n",
"plt.figure(figsize=(8, 8))\n",
"nx.draw(graph, pos, with_labels=True, node_size=500, font_size=8, width=weights, edge_color=weights, edge_cmap=plt.cm.Blues)\n",
"plt.title('Графовое представление изображения')\n",
"plt.show()\n",
"\n",
"# Простая сегментация на основе порога веса\n",
"threshold = 15\n",
"segments = []\n",
"for component in nx.connected_components(graph):\n",
" subgraph = graph.subgraph(component)\n",
" if all(graph[u][v]['weight'] <= threshold for u, v in subgraph.edges()):\n",
" segments.append(component)\n",
"\n",
"# Визуализируем сегменты\n",
"segmented_image = np.zeros_like(image)\n",
"for idx, segment in enumerate(segments, start=1):\n",
" for (i, j) in segment:\n",
" segmented_image[i, j] = 255 - (idx * 50)\n",
"\n",
"plt.figure(figsize=(5, 5))\n",
"plt.imshow(segmented_image, cmap='gray')\n",
"plt.title('Сегментированное изображение')\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "KAHyPKy5I6Bi"
},
"source": [
"Сегментация графовым методом минимального разреза"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 10,
"status": "ok",
"timestamp": 1733324307973,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "sc91Ebh4U63z",
"outputId": "1da952f0-a375-4dec-e59e-7c61d8f6063a"
},
"outputs": [],
"source": [
"pip install pygraph\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 445
},
"executionInfo": {
"elapsed": 15633,
"status": "ok",
"timestamp": 1733312122850,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "o5E7GVLNbUwn",
"outputId": "a44d3093-4f09-44a2-b462-130d1a5c283c"
},
"outputs": [],
"source": [
"import os\n",
"import pydicom\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"import numpy as np\n",
"import networkx as nx\n",
"\n",
"# Пример графовой сегментации (графовый минимум разреза)\n",
"def graph_cut_segmentation(image, threshold=100, max_weight=100):\n",
" # Преобразуем изображение в бинарное\n",
" ret, binary_image = cv2.threshold(image, threshold, 255, cv2.THRESH_BINARY)\n",
"\n",
" # Получаем размеры изображения\n",
" rows, cols = binary_image.shape\n",
"\n",
" # Создаем граф\n",
" G = nx.grid_2d_graph(rows, cols)\n",
"\n",
" # Присваиваем веса рёбрам, которые отражают разницу в яркости пикселей\n",
" for i in range(rows):\n",
" for j in range(cols):\n",
" if i < rows - 1: # Вертикальные рёбра\n",
" weight = np.abs(int(binary_image[i, j]) - int(binary_image[i + 1, j]))\n",
" weight = max(1, min(weight, max_weight)) # Ограничиваем минимальный вес на 1, максимальный на max_weight\n",
" G.add_edge((i, j), (i + 1, j), weight=weight)\n",
"\n",
" if j < cols - 1: # Горизонтальные рёбра\n",
" weight = np.abs(int(binary_image[i, j]) - int(binary_image[i, j + 1]))\n",
" weight = max(1, min(weight, max_weight)) # Ограничиваем минимальный вес на 1, максимальный на max_weight\n",
" G.add_edge((i, j), (i, j + 1), weight=weight)\n",
"\n",
" # Определяем источник и сток (например, верхний левый и нижний правый углы)\n",
" source = (0, 0)\n",
" sink = (rows - 1, cols - 1)\n",
"\n",
" try:\n",
" # Выполняем минимальный разрез\n",
" cut_value, partition = nx.minimum_cut(G, source, sink)\n",
" reachable, non_reachable = partition\n",
"\n",
" # Сегментированное изображение\n",
" segmented_image = np.zeros_like(binary_image)\n",
"\n",
" for (i, j) in reachable:\n",
" segmented_image[i, j] = 255\n",
"\n",
" for (i, j) in non_reachable:\n",
" segmented_image[i, j] = 0\n",
"\n",
" return segmented_image\n",
"\n",
" except nx.NetworkXUnbounded:\n",
" print(\"Ошибка: Найден путь с бесконечной пропускной способностью. Проверьте веса рёбер.\")\n",
" return None\n",
"\n",
"\n",
"# Папка с распакованными изображениями\n",
"dicom_folder = \"images\"\n",
"\n",
"# Сбор всех DICOM-файлов в папке\n",
"dicom_files = [filename for filename in os.listdir(dicom_folder) if filename.endswith(\".dcm\")]\n",
"\n",
"# Запрос у пользователя названий файлов для отображения\n",
"file_names = input(\"Введите названия файлов изображений через запятую: \").split(\",\")\n",
"file_names = [name.strip() for name in file_names]\n",
"\n",
"# Поиск указанных файлов в папке\n",
"selected_files = []\n",
"for filename in file_names:\n",
" found_files = [os.path.join(dicom_folder, f) for f in dicom_files if filename in f]\n",
" selected_files.extend(found_files)\n",
"\n",
"# Обработка и сегментация изображений\n",
"for dicom_path in selected_files:\n",
" if os.path.exists(dicom_path):\n",
" dicom_data = pydicom.dcmread(dicom_path)\n",
" image = dicom_data.pixel_array\n",
"\n",
" # Обрезка верхних 40% изображения (оставляем нижние 60%)\n",
" height = image.shape[0]\n",
" cropped_image = image[height // 3:, :] # Обрезаем верхнюю 40%\n",
"\n",
" # Проверка размера после обрезки\n",
" print(f\"Размер обрезанного изображения: {cropped_image.shape}\")\n",
"\n",
" # Визуализация обрезанного изображения\n",
" plt.imshow(cropped_image, cmap=\"gray\")\n",
" plt.title(f\"Обрезанное изображение: {os.path.basename(dicom_path)}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n",
"\n",
" # Преобразование изображения в формат uint8, если это необходимо\n",
" if cropped_image.dtype != np.uint8:\n",
" cropped_image = cv2.normalize(cropped_image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)\n",
"\n",
" # Применение адаптивного медианного фильтра для сглаживания шума\n",
" filtered_image = cv2.fastNlMeansDenoising(cropped_image, None, 10, 7, 21)\n",
"\n",
" # Преобразование фильтрованного изображения обратно в формат uint8\n",
" filtered_image = (filtered_image * 255).astype(np.uint8)\n",
"\n",
" # Применение графового метода сегментации\n",
" segmented_image = graph_cut_segmentation(filtered_image, threshold=70, max_weight=50)\n",
"\n",
" # Если сегментация прошла успешно, выводим результат\n",
" if segmented_image is not None:\n",
" plt.imshow(segmented_image, cmap=\"gray\")\n",
" plt.title(f\"Графовая сегментация (минимальный разрез): {os.path.basename(dicom_path)}\")\n",
" plt.axis(\"off\")\n",
" plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 6224,
"status": "ok",
"timestamp": 1733315226216,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "pGwk8fcqlD3r",
"outputId": "b3708797-66c3-4e59-a308-1e4a88384f43"
},
"outputs": [],
"source": [
"!pip install cupy-cuda11x\n",
"!pip install scikit-learn\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"executionInfo": {
"elapsed": 1006,
"status": "ok",
"timestamp": 1733332484067,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "C74LMrzI8UqN",
"outputId": "d3199a01-db0b-4b30-bca3-901671ffe662"
},
"outputs": [],
"source": [
"\n",
"import cv2\n",
"import matplotlib.pyplot as plt\n",
"from skimage import segmentation, color\n",
"import numpy as np\n",
"\n",
"# Путь к изображению на Google Диске\n",
"image_path = '/content/7.png'\n",
"\n",
"# Загружаем изображение с помощью OpenCV\n",
"image = cv2.imread(image_path)\n",
"\n",
"# OpenCV загружает изображение в формате BGR, но для отображения используем RGB\n",
"image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
"\n",
"# Отображаем оригинальное изображение\n",
"plt.imshow(image_rgb)\n",
"plt.axis('off')\n",
"plt.title('Original Image')\n",
"plt.show()\n",
"\n",
"# Преобразуем изображение в формат для сегментации (float)\n",
"image_float = np.float32(image_rgb) / 255.0\n",
"\n",
"# Применяем алгоритм Felzenszwalb-Huttenlocher для сегментации\n",
"segments = segmentation.felzenszwalb(image_float, scale=500, sigma=0.05, min_size=50)\n",
"\n",
"# Отображаем результаты сегментации\n",
"fig, ax = plt.subplots(1, 2, figsize=(12, 6))\n",
"\n",
"# Оригинальное изображение\n",
"ax[0].imshow(image_rgb)\n",
"ax[0].set_title('Original Image')\n",
"ax[0].axis('off')\n",
"\n",
"# Сегментированное изображение\n",
"ax[1].imshow(segments)\n",
"ax[1].set_title('Segmented Image (Felzenszwalb-Huttenlocher)')\n",
"ax[1].axis('off')\n",
"\n",
"plt.show()\n",
"\n",
"# Применяем цветовую карту для сегментации\n",
"segmented_image = color.label2rgb(segments, image_rgb, kind='avg')\n",
"\n",
"# Отображаем цветную сегментацию\n",
"plt.imshow(segmented_image)\n",
"plt.title('Segmented Image with Colors')\n",
"plt.axis('off')\n",
"plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"executionInfo": {
"elapsed": 17015,
"status": "ok",
"timestamp": 1733324373410,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "T3cG-ndWKv5Y",
"outputId": "383d61ee-48ff-45c6-fba8-a3e0bcc791be"
},
"outputs": [],
"source": [
"pip install scikit-learn"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"executionInfo": {
"elapsed": 91492,
"status": "ok",
"timestamp": 1733332390246,
"user": {
"displayName": "E Shuvalova",
"userId": "09074408506229732964"
},
"user_tz": -180
},
"id": "UzQwZH60LtnN",
"outputId": "2f4f9891-7041-4fe2-ef50-25716eca6724"
},
"outputs": [],
"source": [
"import cv2\n",
"import matplotlib.pyplot as plt\n",
"from skimage import segmentation, color\n",
"import numpy as np\n",
"from sklearn.cluster import SpectralClustering\n",
"from skimage import img_as_float\n",
"from sklearn.neighbors import kneighbors_graph\n",
"\n",
"# Путь к изображению на Google Диске\n",
"image_path = '/content/7.png'\n",
"\n",
"# Загружаем изображение с помощью OpenCV\n",
"image = cv2.imread(image_path)\n",
"\n",
"# OpenCV загружает изображение в формате BGR, но для отображения используем RGB\n",
"image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
"\n",
"# Отображаем оригинальное изображение\n",
"plt.imshow(image_rgb)\n",
"plt.axis('off')\n",
"plt.title('Original Image')\n",
"plt.show()\n",
"\n",
"# Преобразуем изображение в формат для сегментации (float)\n",
"image_float = np.float32(image_rgb) / 255.0\n",
"\n",
"# **Метод 1: Felzenszwalb-Huttenlocher**\n",
"segments_fz = segmentation.felzenszwalb(image_float, scale=200, sigma=0.05, min_size=150)\n",
"\n",
"# **Метод 2: Graph Cut (Quickshift)**\n",
"segments_quickshift = segmentation.quickshift(image_float, kernel_size=3, max_dist=6, ratio=0.9)\n",
"\n",
"# **Метод 3: Spectral Clustering**\n",
"# Преобразуем изображение в граф с соседями\n",
"image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n",
"graph = kneighbors_graph(image_gray.reshape(-1, 1), n_neighbors=10, mode='distance', include_self=False)\n",
"graph = 0.5 * (graph + graph.T) # Симметризация графа\n",
"\n",
"# Применяем спектральную кластеризацию\n",
"sc = SpectralClustering(n_clusters=5, affinity='precomputed', n_init=10)\n",
"segments_spectral = sc.fit_predict(graph.toarray()).reshape(image_gray.shape)\n",
"\n",
"# Отображаем результаты сегментации\n",
"fig, ax = plt.subplots(1, 4, figsize=(16, 6))\n",
"\n",
"# Оригинальное изображение\n",
"ax[0].imshow(image_rgb)\n",
"ax[0].set_title('Original Image')\n",
"ax[0].axis('off')\n",
"\n",
"# Felzenszwalb-Huttenlocher\n",
"ax[1].imshow(segments_fz)\n",
"ax[1].set_title('Felzenszwalb-Huttenlocher')\n",
"ax[1].axis('off')\n",
"\n",
"# Graph Cut (Quickshift)\n",
"ax[2].imshow(segments_quickshift)\n",
"ax[2].set_title('Graph Cut (Quickshift)')\n",
"ax[2].axis('off')\n",
"\n",
"# Spectral Clustering\n",
"ax[3].imshow(segments_spectral)\n",
"ax[3].set_title('Spectral Clustering')\n",
"ax[3].axis('off')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"# Применяем цветовую карту для сегментации\n",
"segmented_image_fz = color.label2rgb(segments_fz, image_rgb, kind='avg')\n",
"segmented_image_quickshift = color.label2rgb(segments_quickshift, image_rgb, kind='avg')\n",
"segmented_image_spectral = color.label2rgb(segments_spectral, image_rgb, kind='avg')\n",
"\n",
"# Отображаем цветные сегментации\n",
"fig, ax = plt.subplots(1, 3, figsize=(18, 6))\n",
"\n",
"# Felzenszwalb-Huttenlocher\n",
"ax[0].imshow(segmented_image_fz)\n",
"ax[0].set_title('Segmented Image (Felzenszwalb-Huttenlocher)')\n",
"ax[0].axis('off')\n",
"\n",
"# Graph Cut (Quickshift)\n",
"ax[1].imshow(segmented_image_quickshift)\n",
"ax[1].set_title('Segmented Image (Graph Cut - Quickshift)')\n",
"ax[1].axis('off')\n",
"\n",
"# Spectral Clustering\n",
"ax[2].imshow(segmented_image_spectral)\n",
"ax[2].set_title('Segmented Image (Spectral Clustering)')\n",
"ax[2].axis('off')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()\n"
]
}
],
"metadata": {
"colab": {
"authorship_tag": "ABX9TyNqotXgUNNGNY+IQjZNQBRs",
"name": "",
"version": ""
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}