Классификация больших мультирезолюционных изображений с помощью blockedImage и глубокое обучение

В этом примере показано, как классифицировать мультиразрешение целых изображения (WSIs), которые не помещаются в памяти, используя Inception-v3 глубокую нейронную сеть.

Единственным окончательным способом диагностики рака молочной железы является исследование выборок тканей, собранных при биопсии или хирургии. Выборки обычно готовят с окрашиванием гематоксилином и эозином (H&E) для повышения контрастности структур в ткани. Традиционно патологоанатомы исследуют ткани на стеклянных слайдах под микроскопом, чтобы обнаружить опухолевую ткань. Диагностика занимает время, поскольку патологоанатомы должны тщательно осмотреть целый слайд при близком увеличении. Кроме того, патологоанатомы могут не замечать мелких опухолей. Методы глубокого обучения направлены на автоматизацию обнаружения опухолевой ткани, экономию времени и улучшение скорости обнаружения небольших опухолей.

Методы глубокого обучения для классификации опухолей полагаются на цифровую патологию, при которой скольжения всей ткани визуализируются и оцифровываются. Получившиеся WSI имеют чрезвычайно высокое разрешение. WSI часто хранятся в файле мультиразрешения, чтобы облегчить отображение, навигацию и обработку изображений.

Чтение WSI является проблемой, потому что изображения не могут быть загружены как единое целое в память и, следовательно, требуют неядерных методов обработки изображений. Вы можете хранить и обрабатывать этот тип большого мультирезолюционного изображения при помощи blockedImage (Image Processing Toolbox) объекты. Можно извлечь пакеты данных из blockedImage объекты, использующие blockedImageDatastore (Image Processing Toolbox) объекты.

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

Загрузка обучающих данных

В этом примере используются WSI из Camelyon16 задачи [1]. Данные этой проблемы содержат в общей сложности 400 WSI лимфатических узлов из двух независимых источников, разделенных на 270 обучающих изображений и 130 тестовых изображений. WSI хранятся как файлы TIF в обрезанном формате с 11-уровневой структурой пирамиды.

Обучающие данные состоят из 159 WSI нормальных лимфатических узлов и 111 WSI лимфатических узлов с опухолью и здоровой тканью. Обычно опухолевая ткань является небольшой частью здоровой ткани. Основные истины контуров поражения сопровождают изображения опухоли.

Размер каждого обучающего файла составляет приблизительно 2 ГБ. Если вы не хотите загружать обучающие данные или обучать сеть, перейдите непосредственно в раздел Train или Download the Network в этом примере.

Создайте директорию для хранения обучающих данных.

trainingImageDir = fullfile(tempdir,'Camelyon16','training');
if ~exist(trainingImageDir,'dir')
    mkdir(trainingImageDir);
    mkdir(fullfile(trainingImageDir,'normal'));
    mkdir(fullfile(trainingImageDir,'tumor'));
    mkdir(fullfile(trainingImageDir,'lesion_annotations'));
end

trainNormalDataDir = fullfile(trainingImageDir,'normal');
trainTumorDataDir = fullfile(trainingImageDir,'tumor');
trainTumorAnnotationDir = fullfile(trainingImageDir,'lesion_annotations');

Чтобы загрузить обучающие данные, перейдите на веб-сайт Camelyon17 и щелкните первую ссылку «CAMELYON16 data set». Откройте директорию «обучение», а затем выполните следующие действия.

  • Загрузите файл «lesion_annotations.zip». Извлеките файлы в директорию, заданный trainTumorAnnotationDir переменная.

  • Откройте «нормальную » директорию. Загрузите изображения в директорию, заданный trainNormalDataDir переменная.

  • Откройте директорию «опухоль». Загрузите изображения в директорию, заданный trainTumorDataDir переменная.

Укажите количество обучающих изображений. Обратите внимание, что одно из обучающих изображений нормальной ткани, 'normal _ 144.tif', имеет метаданные, которые не могут быть считаны blockedImage объект. Этот пример использует оставшиеся 158 файлов обучения.

numNormalFiles = 158;
numTumorFiles = 111;

Визуализация обучающих данных

Чтобы лучше изучить обучающие данные, отобразите одно обучающее изображение. Поскольку загрузка всего изображения в память в самом высоком разрешении невозможна, вы не можете использовать традиционные функции отображения изображений, такие как imshow. Чтобы отобразить и обработать данные изображения, используйте blockedImage (Image Processing Toolbox) объект.

Создайте blockedImage объект из обучающего изображения опухоли.

tumorFileName = fullfile(trainTumorDataDir,'tumor_001.tif');
tumorImage = blockedImage(tumorFileName);

Осмотрите размерности blockedImage на каждом уровне разрешения. Уровень 1 имеет больше всего пикселей и является лучшим уровнем разрешения. Уровень 10 имеет наименьшее количество пикселей и является самым грубым уровнем разрешения. Соотношение сторон не является последовательным, что указывает на то, что уровни не все охватывают одну и ту же мировую площадь.

levelSizeInfo = table((1:length(tumorImage.Size))', ...
    tumorImage.Size(:,1), ...
    tumorImage.Size(:,2), ...
    tumorImage.Size(:,1)./tumorImage.Size(:,2), ...
    'VariableNames',["Resolution Level" "Image Width" "Image Height" "Aspect Ratio"])
levelSizeInfo=11×4 table
    Resolution Level    Image Width    Image Height    Aspect Ratio
    ________________    ___________    ____________    ____________

            1           2.2118e+05        97792           2.2618   
            2           1.1059e+05        49152             2.25   
            3                55296        24576             2.25   
            4                27648        12288             2.25   
            5                13824         6144             2.25   
            6                 7168         3072           2.3333   
            7                 1577         3629          0.43455   
            8                 3584         1536           2.3333   
            9                 2048         1024                2   
           10                 1024          512                2   
           11                  512          512                1   

Отобразите blockedImage на уровне грубого разрешения при помощи bigimageshow (Image Processing Toolbox) функция. Верните указатель на bigimageshow объект. Для настройки отображения можно использовать указатель. Изображение содержит много пустого белого пространства. Ткань занимает лишь небольшой фрагмент изображения.

h = bigimageshow(tumorImage,'ResolutionLevel',8);

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

xlim([29471,29763]);
ylim([117450,118110]);

Для получения дополнительной информации измените уровень разрешения на более мелкий.

h.ResolutionLevel = 1;

Создание масок

Вы можете уменьшить количество расчета, обрабатывая только видимые области (ROIs). Используйте маску для определения ROIs. Маска является логическим изображением, в котором true пиксели представляют информация только для чтения.

Чтобы дополнительно уменьшить количество расчетов, создайте маски на уровне грубого разрешения, который может быть полностью обработан в памяти, а не на базисе. Если пространственная привязка уровня грубого разрешения совпадает с пространственной привязкой более мелких уровней разрешения, то местоположения на грубом уровне соответствуют местоположениям на более мелких уровнях. В этом случае можно использовать грубую маску, чтобы выбрать, какие блоки обрабатывать на более мелких уровнях. Для получения дополнительной информации смотрите Настройка пространственных ссылок для заблокированных изображений (Image Processing Toolbox) и Эффективно обрабатывать заблокированные изображения с помощью маски (Image Processing Toolbox).

Задает уровень разрешения для создания маски. Этот пример использует уровень разрешения 7, который является грубым и помещается в памяти. Обратите внимание, что blockedImage объект автоматически сортирует уровни в мультиразрешение изображении от мельчайших до грубейших на основе количества пикселей на каждом уровне. Несколько Camelyon16 файлов изображений содержат маску промежуточного разрешения. Этот пример игнорирует маску при определении и считывании седьмого уровня данных изображения.

resolutionLevel = 7;

Создание масок для нормальных изображений

На нормальных изображениях информация только для чтения состоит из здоровой ткани. Цвет здоровой ткани отличается от цвета фона, поэтому используйте порог цвета, чтобы сегментировать изображение и создать информация только для чтения. Цветовое пространство L * a * b * обеспечивает лучшее цветоделение для сегментации. Преобразуйте изображение в цветовое пространство L * a * b *, затем пороговите канал a *, чтобы создать тканевую маску.

Можно использовать функцию helper createMaskForNormalTissue чтобы создать маски с помощью порога цвета. Эта вспомогательная функция присоединена к примеру как вспомогательный файл.

Вспомогательная функция выполняет эти операции на каждом обучающем изображении нормальной ткани:

  • Создайте blockedImage объект из файла изображений TIF.

  • Установите пространственные ссылки на все уровни разрешения из метаданных изображения.

  • Получите изображение на уровне грубого разрешения.

  • Преобразуйте грубое изображение в цветовое пространство L * a * b *, затем извлеките канал a *.

  • Создайте бинарное изображение путем порога изображения с помощью метода Otsu, который минимизирует внутриклассовое отклонение между черным и белым пикселями.

  • Создайте одно разрешение blockedImage объект из маски и установите пространственную ссылку маски так, чтобы она совпадала с пространственной привязкой входного изображения.

  • Напишите маску blockedImage в память. Только blockedImage объект находится в памяти. Отдельные блоки изображений, соответствующие логическому изображению маски, находятся во временной директории. Запись в директорию сохраняет пользовательские пространственные ссылки, что гарантирует, что обычные изображения и соответствующие им маскировочные изображения имеют одинаковые пространственные ссылки.

trainNormalMaskDir = fullfile(trainNormalDataDir,['normal_mask_level' num2str(resolutionLevel)]);
createMaskForNormalTissue(trainNormalDataDir,trainNormalMaskDir,resolutionLevel)

Теперь, когда и обычные изображения, и маски находятся на диске, создайте blockedImage объекты для управления данными с помощью вспомогательной функции createBlockedImageAndMaskArrays. Эта функция создает массив blockedImage объекты из нормальных изображений и соответствующий массив blockedImage объекты из изображений обычной маски. Функция helper присоединена к примеру как вспомогательный файл.

[normalImages,normalMasks] = createBlockedImageAndMaskArrays(trainNormalDataDir,trainNormalMaskDir);

Выберите выборку обычного изображения и маски. Подтвердите, что пространственные границы мира маски совпадают с границами изображения на самом высоком уровне разрешения. Пространственные границы мира заданы WorldStart и WorldEnd свойства.

idx = 2;
[normalImages(idx).WorldStart normalImages(idx).WorldEnd]
ans = 11×6
105 ×

         0         0    0.0000    2.2118    0.9779    0.0000
         0         0    0.0000    2.2118    0.9830    0.0000
         0         0    0.0000    2.2118    0.9830    0.0000
         0         0    0.0000    2.2118    0.9830    0.0000
         0         0    0.0000    2.2118    0.9830    0.0000
         0         0    0.0000    2.2938    0.9830    0.0000
    0.0000    0.0000    0.0000    2.2118    0.9779    0.0000
         0         0    0.0000    2.2938    0.9830    0.0000
         0         0    0.0000    2.6214    1.3107    0.0000
         0         0    0.0000    2.6214    1.3107    0.0000
      ⋮

[normalMasks(idx).WorldStart normalMasks(idx).WorldEnd]
ans = 1×4

           0           0      221184       97792

Проверьте, что маска содержит правильные ROI и пространственные ссылки. Отобразите образец изображения при помощи bigimageshow функция. Получите оси, содержащие отображение.

figure
hNormal = bigimageshow(normalImages(idx));
hNormalAxes = hNormal.Parent;

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

hMaskAxes = axes;
hMask = bigimageshow(normalMasks(idx),'Parent',hMaskAxes, ...
    'Interpolation','nearest','AlphaData',0.5);
hMaskAxes.Visible = 'off';

Соедините оси изображения с осями маски. При масштабировании и панорамировании обе оси обновляются идентично.

linkaxes([hNormalAxes,hMaskAxes]);

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

xlim([45000 80000]);
ylim([130000 165000]);

Создайте маски для изображений опухоли

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

Можно использовать функцию helper createMaskForTumorTissue чтобы создать маску с помощью ROIs. Эта вспомогательная функция присоединена к примеру как вспомогательный файл.

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

  • Создайте blockedImage объект из файла изображений TIF.

  • Установите пространственные ссылки из метаданных изображения.

  • Прочитайте соответствующие аннотации поражения в XML- файлах и преобразуйте аннотации в многоугольники (Polygon (Image Processing Toolbox) объекты).

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

  • Создайте выход логическую маску blockedImage объект на более грубом уровне разрешения. Запишите изображение маски на блок-за- базис при помощи setBlock функция.

  • Напишите маску blockedImage объект в директорию в памяти. Только blockedImage объект находится в памяти. Отдельные блоки изображений, соответствующие логическому изображению маски, находятся во временной директории. Запись в директорию сохраняет пользовательскую пространственную ссылку, которая гарантирует, что опухолевые изображения и соответствующие им масковые изображения имеют одинаковую пространственную ссылку.

trainTumorMaskDir = fullfile(trainTumorDataDir,['tumor_mask_level' num2str(resolutionLevel)]);
createMaskForTumorTissue(trainTumorDataDir,trainTumorAnnotationDir, ...
    trainTumorMaskDir,resolutionLevel);

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

[tumorImages,tumorMasks] = createBlockedImageAndMaskArrays(trainTumorDataDir,trainTumorMaskDir);

Выберите образец изображения опухоли и маски. Подтвердите, что пространственные границы мира маски совпадают с границами изображения на самом высоком уровне разрешения. Пространственные границы мира заданы XWorldLimits и YWorldLimits свойства.

idx = 5;
[tumorImages(idx).WorldStart tumorImages(idx).WorldEnd]
ans = 11×6
105 ×

         0         0    0.0000    2.1965    0.9779    0.0000
         0         0    0.0000    2.2016    0.9830    0.0000
         0         0    0.0000    2.2118    0.9830    0.0000
         0         0    0.0000    2.2118    0.9830    0.0000
         0         0    0.0000    2.2118    0.9830    0.0000
         0         0    0.0000    2.2938    0.9830    0.0000
    0.0000    0.0000    0.0000    2.1965    0.9779    0.0000
         0         0    0.0000    2.2938    0.9830    0.0000
         0         0    0.0000    2.6214    1.3107    0.0000
         0         0    0.0000    2.6214    1.3107    0.0000
      ⋮

[tumorMasks(idx).WorldStart tumorMasks(idx).WorldEnd]
ans = 1×4

           0           0      219648       97792

Проверьте, что маска содержит правильные ROI и пространственные ссылки. Отобразите образец изображения при помощи bigimageshow функция. Получите оси, содержащие отображение.

figure
hTumor = bigimageshow(tumorImages(idx));
hTumorAxes = hTumor.Parent;

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

hMaskAxes = axes;
hMask = bigimageshow(tumorMasks(idx),'Parent',hMaskAxes, ...
    'Interpolation','nearest','AlphaData',0.5);
hMaskAxes.Visible = 'off';

Соедините оси изображения с осями маски. При масштабировании и панорамировании обе оси обновляются идентично.

linkaxes([hTumorAxes,hMaskAxes]);

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

xlim([45000 65000]);
ylim([130000 150000]);

Создайте заблокированные хранилища изображений для обучения и валидации

Чтобы извлечь закрашенные фигуры обучающих данных из blockedImage объекты, используйте blockedImageDatastore (Image Processing Toolbox). Этот datastore считывает закрашенные фигуры blockedImage данные на одном уровне разрешения.

Цветовой дисбаланс и классовый дисбаланс в необработанных обучающих закрашенных фигурах могут потенциально смещать сеть. Цветовой дисбаланс является результатом неоднородного окрашивания ткани. Классовый дисбаланс возникает из-за неравного количества опухоли и нормальной ткани в данных. Чтобы исправить эти дисбалансы, можно предварительно обработать и увеличить datastore.

В этом примере показано, как создать blockedImageDatastore который извлекает опухоль и нормальные закрашенные фигуры для обучения сети. Пример также показывает, как предварительно обработать и увеличить хранилища данных, чтобы избежать смещения сети.

Выберите местоположение нормальных тканевых Закрашенных фигур, чтобы считать

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

normalValnIdx = randi(numNormalFiles,[1 2]);
normalTrainIdx = setdiff(1:numNormalFiles,normalValnIdx);

Размер закрашенной фигуры невелик по сравнению с размером функций на изображении. По умолчанию a blockedImageDatastore извлекает закрашенные фигуры без перекрытия и без зазора, что генерирует огромное количество обучающих закрашенных фигур. Можно уменьшить объем обучающих данных, задав подмножество закрашенных фигур. Задайте координаты закрашенных фигур с помощью selectBlockLocations (Image Processing Toolbox) функция. Добавьте погрешность между выборочными закрашенными фигурами для обучения с помощью BlockOffsets аргумент имя-значение. Задайте смещение, больше, чем размер закрашенной фигуры. Увеличьте порог включения от значения по умолчанию 0,5, чтобы сеть обучалась на относительно однородных закрашенных фигурах.

patchSize = [299,299,3];
normalStrideFactor = 10;
blsNormalData = selectBlockLocations(normalImages(normalTrainIdx), ...
    "BlockSize",patchSize(1:2),"BlockOffsets",patchSize(1:2)*normalStrideFactor, ...
    "Masks",normalMasks(normalTrainIdx),"InclusionThreshold",0.75,"ExcludeIncompleteBlocks",true);

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

blsNormalDataVal = selectBlockLocations(normalImages(normalValnIdx), ...
    "BlockSize",patchSize(1:2), ...
    "Masks",normalMasks(normalValnIdx),"InclusionThreshold",0.75,"ExcludeIncompleteBlocks",true);

Создайте хранилища данных для нормальных изображений

Создайте хранилища данных dsNormalData и dsNormalDataVal которые считывают закрашенные фигуры изображений от нормальных изображений на самом высоком уровне разрешения для обучения и валидации, соответственно. Задайте координаты закрашенных фигур с помощью BlockLocationSet аргумент пары "имя-значение".

dsNormalData = blockedImageDatastore(normalImages(normalTrainIdx), ...
    "BlockLocationSet",blsNormalData);
dsNormalDataVal = blockedImageDatastore(normalImages(normalValnIdx), ...
    "BlockLocationSet",blsNormalDataVal);

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

imagesToPreview = zeros([patchSize 10],'uint8');
for n = 1:10
    im = read(dsNormalData);
    imagesToPreview(:,:,:,n) = im{1};
end
figure
montage(imagesToPreview,'Size',[2 5],'BorderSize',10,'BackgroundColor','k');

title("Training Patches of Normal Tissue")

Выберите местоположение Закрашенных фигур опухолевой ткани, чтобы считать

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

tumorValIdx = randi(numTumorFiles,[1 2]);
tumorTrainIdx = setdiff(1:numTumorFiles,tumorValIdx);

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

tumorStrideFactor = 3;
blsTumorData = selectBlockLocations(tumorImages(tumorTrainIdx), ...
    "BlockSize",patchSize(1:2),"BlockOffsets",patchSize(1:2)*tumorStrideFactor, ...
    "Masks",tumorMasks(tumorTrainIdx),"InclusionThreshold",0.75,"ExcludeIncompleteBlocks",true);

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

blsTumorDataVal = selectBlockLocations(tumorImages(tumorValIdx), ...
    "BlockSize",patchSize(1:2), ...
    "Masks",tumorMasks(tumorValIdx),"InclusionThreshold",0.75,"ExcludeIncompleteBlocks",true);

Создайте хранилища данных для изображений опухоли

Создайте blockedImageDatastore из обучающих изображений опухоли и масок. Хранилища данных dsTumorData и dsTumorDataVal считывайте закрашенные фигуры с изображений опухоли на самом высоком уровне разрешения для обучения и валидации, соответственно.

dsTumorData = blockedImageDatastore(tumorImages(tumorTrainIdx), ...
    "BlockLocationSet",blsTumorData);
dsTumorDataVal = blockedImageDatastore(tumorImages(tumorValIdx), ...
    "BlockLocationSet",blsTumorDataVal);

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

imagesToPreview = zeros([patchSize 10],'uint8');
for n = 1:10
    im = read(dsTumorData);
    imagesToPreview(:,:,:,n) = im{1};
end
montage(imagesToPreview,'Size',[2 5],'BorderSize',10,'BackgroundColor','k');
title("Training Patches of Tumor Tissue")

Нормализация цветов и увеличение обучающих данных

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

Чтобы предотвратить изменчивость цвета, этот пример предварительно обрабатывает данные стандартными методами нормализации окрашивания. Примените нормализацию и увеличение пятна при помощи transform функция с пользовательскими операциями предварительной обработки, заданными функцией helper augmentAndLabelCamelyon16. Эта функция присоединена к примеру как вспомогательный файл.

The augmentAndLabelCamelyon16 функция выполняет следующие операции:

  • Нормализуйте окрашивание при помощи normalizeStaining.m функция [4]. Нормализацию окрашивания осуществляют методом Маченко, который разделяет цветовые каналы H&E цветом деконволюции с помощью фиксированной матрицы и затем воссоздает нормализованные изображения с индивидуальным исправленным смешиванием. Функция возвращает нормированное изображение, а также изображения H & E.

  • Добавьте цветовой джиттер при помощи jitterColorHSV (Image Processing Toolbox) функция. Цветовой джиттер изменяет цвет каждой закрашенной фигуры, возмущая контрастность изображения, оттенок, насыщение и яркость. Дрожание цвета выполняется в цветовом пространстве HSV, чтобы избежать нежелательных программных продуктов цвета в изображении RGB.

  • Применить случайные комбинации поворотов на 90 степени и вертикального и горизонтального отражения. Рандомизированные аффинные преобразования делают сеть агностической к ориентации входных данных изображения.

  • Пометьте закрашенную фигуру следующим 'normal' или 'tumor'.

Каждая закрашенная фигура изображения генерирует пять дополненных и маркированные закрашенные фигуры: окрашенно-нормализованный закрашенная фигура, окрашенно-нормализованный закрашенная фигура с цветным дрожанием, окрашенно-нормализованный закрашенная фигура с цветным дрожанием и случайным аффинным преобразованием, гематоксилиновое изображение со случайным аффинным преобразованием и эозиновое изображение со случайным аффинным преобразованием.

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

dsLabeledNormalData = transform(dsNormalData, ...
    @(x,info)augmentAndLabelCamelyon16(x,info,'normal'),'IncludeInfo',true);
dsLabeledNormalDataVal = transform(dsNormalDataVal, ...
    @(x,info)augmentAndLabelCamelyon16(x,info,'normal'),'IncludeInfo',true);

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

dsLabeledTumorData = transform(dsTumorData, ...
    @(x,info)augmentAndLabelCamelyon16(x,info,'tumor'),'IncludeInfo',true);
dsLabeledTumorDataVal = transform(dsTumorDataVal, ...
    @(x,info)augmentAndLabelCamelyon16(x,info,'tumor'),'IncludeInfo',true);

Балансировка опухоли и нормальных классов

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

Чтобы предотвратить дисбаланс классов, этот пример задает пользовательский datastore, называемый randomSamplingDatastore который случайным образом выбирает нормальные и опухолевые обучающие закрашенные фигуры сбалансированным образом. Скрипт для определения этого пользовательского datastore присоединен к примеру как вспомогательный файл. Для получения дополнительной информации см. Раздел «Разработка пользовательского Datastore».

Создайте пользовательскую randomSamplingDatastore из нормальных и опухолевых обучающих хранилищ данных. datastore случайной выборки dsTrain предоставляет мини-пакеты обучающих данных в сеть при каждой итерации эпохи.

dsTrain = randomSamplingDatastore(dsLabeledTumorData,dsLabeledNormalData);

Чтобы ограничить количество закрашенных фигур, используемых во время валидации, этот пример задает пользовательский datastore, называемое validationDatastore который возвращает пять закрашенных фигур валидации из каждого класса. Скрипт для определения этого пользовательского datastore присоединен к примеру как вспомогательный файл.

Создайте пользовательскую validationDatastore из хранилищ данных нормальной и опухолевой валидации.

numValidationPatchesPerClass = 5;
dsVal = validationDatastore(dsLabeledTumorDataVal, ...
    dsLabeledNormalDataVal,numValidationPatchesPerClass);

Настройка Inception-v3 слоев сети

Этот пример использует Inception-v3 сеть, сверточную нейронную сеть, которая обучена более чем на миллионе изображений из базы данных ImageNet [3]. Сеть имеет глубину 48 слоев и может классифицировать изображения в 1000 категорий объектов, таких как клавиатура, мышь, карандаш и многие животные. Сеть ожидает размер входа изображения 299 на 299 с 3 каналами.

The inceptionv3 функция возвращает предварительно обученную Inception-v3 сеть. Inception-v3 требуется модель Deep Learning Toolbox™ для пакета поддержки Inception-v3 Network. Если этот пакет поддержки не установлен, то функция предоставляет ссылку на загрузку.

net = inceptionv3;

Замена конечных слоев

Сверточные слои сети извлекают изображение, функции последний выучиваемый слой и конечный слой классификации используют для классификации входа изображения. Эти два слоя содержат информацию о том, как объединить функции, которые сеть извлекает в вероятности класса, значение потерь и предсказанные метки. Чтобы переобучить предварительно обученную сеть для классификации новых изображений, замените эти два слоя новыми слоями, адаптированными к новому набору данных. Для получения дополнительной информации смотрите Обучите нейронную сеть для глубокого обучения для классификации новых изображений.

Извлеките график слоев из обученной сети.

lgraph = layerGraph(net);

Найдите имена двух слоев, которые нужно заменить с помощью вспомогательной функции findLayersToReplace. Эта функция присоединена к примеру как вспомогательный файл. В Inception-v3 эти два слоя названы 'predictions' и 'ClassificationLayer_predictions'.

[learnableLayer,classLayer] = findLayersToReplace(lgraph)
learnableLayer = 
  FullyConnectedLayer with properties:

          Name: 'predictions'

   Hyperparameters
     InputSize: 2048
    OutputSize: 1000

   Learnable Parameters
       Weights: [1000×2048 single]
          Bias: [1000×1 single]

  Show all properties

classLayer = 
  ClassificationOutputLayer with properties:

            Name: 'ClassificationLayer_predictions'
         Classes: [1000×1 categorical]
    ClassWeights: 'none'
      OutputSize: 1000

   Hyperparameters
    LossFunction: 'crossentropyex'

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

numClasses = 2;
newLearnableLayer = fullyConnectedLayer(numClasses,'Name','predictions');
lgraph = replaceLayer(lgraph,learnableLayer.Name,newLearnableLayer);

Создайте новый слой классификации для двух классов. Замените исходный слой окончательной классификации новым слоем.

newClassLayer = classificationLayer('Name','ClassificationLayer_predictions');
lgraph = replaceLayer(lgraph,classLayer.Name,newClassLayer);

Настройка опций обучения

Обучите сеть с помощью rmsprop решатель оптимизации. Этот решатель автоматически настраивает скорость и импульс обучения для более быстрого сходимости. Задайте другие установки гиперпараметров при помощи trainingOptions функция. Уменьшите MaxEpochs в небольшом количестве, потому что большой объем обучающих данных позволяет сети достичь сходимости раньше.

checkpointsDir = fullfile(trainingImageDir,'checkpoints');
if ~exist(checkpointsDir,'dir')
    mkdir(checkpointsDir);
end

options = trainingOptions('rmsprop', ...
    'InitialLearnRate',1e-5, ...
    'SquaredGradientDecayFactor',0.99, ...
    'MaxEpochs',3, ...
    'MiniBatchSize',32, ...
    'Plots','training-progress', ...
    'CheckpointPath',checkpointsDir, ...
    'ValidationData',dsVal, ...
    'ExecutionEnvironment','auto', ...
    'Shuffle','every-epoch');

Обучите или загрузите сеть

По умолчанию пример загружает предварительно обученную версию обученной Inception-v3 сети с помощью функции helper downloadTrainedCamelyonNet. Функция helper присоединена к примеру как вспомогательный файл. Предварительно обученная сеть позволяет запускать весь пример, не дожидаясь завершения обучения.

Чтобы обучить сеть, установите doTraining переменная в следующем коде, для true. Обучите сеть с помощью trainNetwork функция.

Обучите на графическом процессоре, если он доступен. Для использования GPU требуется Parallel Computing Toolbox™ и графический процессор с поддержкой CUDA ® NVIDIA ®. Для получения дополнительной информации смотрите Поддержку GPU by Release (Parallel Computing Toolbox). Обучение занимает около 20 часов на NVIDIA Titan X.

doTraining = false;
if doTraining
    trainedNet = trainNetwork(dsTrain,lgraph,options);
    modelDateTime = string(datetime('now','Format',"yyyy-MM-dd-HH-mm-ss"));
    save(strcat("trainedCamelyonNet-",modelDateTime,".mat"),'trainedNet');
else
    trainedCamelyonNet_url = 'https://www.mathworks.com/supportfiles/vision/data/trainedCamelyonNet.mat';
    netDir = fullfile(tempdir,'Camelyon16');
    downloadTrainedCamelyonNet(trainedCamelyonNet_url,netDir);
    load(fullfile(netDir,'trainedCamelyonNet.mat'));
end
Pretrained Inception-v3 network for Cameylon16 data set already exists.

Загрузка и предварительная обработка тестовых данных

Набор Camelyon16 тестовых данных состоит из 130 WSI. Эти изображения имеют как нормальную, так и опухолевую ткань. Этот пример использует два тестовых изображения из Camelyon16 тестовых данных. Размер каждого файла составляет приблизительно 2 ГБ.

Создайте директорию для хранения тестовых данных.

testingImageDir = fullfile(tempdir,'Camelyon16','testing');
if ~exist(testingImageDir,'dir')
    mkdir(testingImageDir);
    mkdir(fullfile(testingImageDir,'images'));
    mkdir(fullfile(testingImageDir,'lesion_annotations'));
end

testDataDir = fullfile(testingImageDir,'images');
testTumorAnnotationDir = fullfile(testingImageDir,'lesion_annotations');

Чтобы загрузить тестовые данные, перейдите на веб-сайт Camelyon17 и щелкните первую ссылку «CAMELYON16 data set». Откройте директорию « проверку», а затем выполните следующие действия.

  • Загрузите файл «lesion_annotations.zip». Извлечь все файлы в директорию, заданный testTumorAnnotationDir переменная.

  • Откройте директорию « изображения». Загрузите первые два файла, «test_001.tif» и «test_002.tif.» Переместите файлы в директорию, заданный testDataDir переменная.

Укажите количество тестовых изображений.

numTestFiles = 2;

Создайте маски для тестовых изображений

Тестовые изображения содержат смесь нормальных и опухолевых изображений. Чтобы уменьшить количество расчетов во время классификации, задайте ROIs путем создания масок.

Задает уровень разрешения для создания маски. Этот пример использует уровень разрешения 7, который является грубым и помещается в памяти.

resolutionLevel = 7;

Создайте маски для областей, содержащих ткани. Можно использовать функцию helper createMaskForNormalTissue чтобы создать маски с помощью порога цвета. Эта вспомогательная функция присоединена к примеру как вспомогательный файл. Для получения дополнительной информации об этой вспомогательной функции см. Раздел «Создание масок для нормальных изображений».

testTissueMaskDir = fullfile(testDataDir,['test_tissuemask_level' num2str(resolutionLevel)]);
createMaskForNormalTissue(testDataDir,testTissueMaskDir,resolutionLevel);

Создайте маски для изображений, которые содержат опухолевую ткань. Пропустите изображения, которые не содержат опухолевую ткань. Можно использовать функцию helper createMaskForTumorTissue создание масок с использованием объектов информация только для чтения. Эта вспомогательная функция присоединена к примеру как вспомогательный файл. Для получения дополнительной информации об этой вспомогательной функции см. Раздел «Создание масок для изображений опухоли».

testTumorMaskDir = fullfile(testDataDir,['test_tumormask_level' num2str(resolutionLevel)]);
createMaskForTumorTissue(testDataDir,testTumorAnnotationDir,testTumorMaskDir,resolutionLevel);

Классификация тестовых данных и создание тепловых карт

Каждое тестовое изображение имеет две маски, одну, указывающую на нормальную ткань, и одну, указывающую на опухолевую ткань. Создание blockedImage объекты для управления тестовыми данными и масками с помощью функции helper createBlockedImageAndMaskArrays. Функция helper присоединена к примеру как вспомогательный файл.

[testImages,testTissueMasks] = createBlockedImageAndMaskArrays(testDataDir,testTissueMaskDir);
[~,testTumorMasks] = createBlockedImageAndMaskArrays(testDataDir,testTumorMaskDir);

Используйте обученную Inception-v3 сеть для идентификации опухолевых закрашенных фигур на тестовых изображениях, testImages. Классифицируйте тестовые изображения по блокам базиса при помощи apply (Image Processing Toolbox) с пользовательским конвейером обработки, заданным функцией helper tumorProbabilityHeatMap. Эта вспомогательная функция присоединена к примеру как вспомогательный файл. Чтобы уменьшить количество необходимых расчетов, укажите тканевую маску testTissueMask так что apply функция обрабатывает только закрашенные фигуры, которые содержат ткани. Задайте 'UseParallel' Аргумент пары "имя-значение" как логическое значение, возвращаемое canUseGPU. Если поддерживаемый графический процессор доступен для расчетов, то apply функция оценивает блоки параллельно.

The tumorProbabilityHeatMap функция выполняет эти операции над каждым тканевым блоком:

  • Вычислите счет вероятности опухоли при помощи predict функция.

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

The apply функция сшивает тепловую карту каждого блока в одну тепловую карту для тестового изображения. Тепловая карта показывает, где сеть обнаруживает области, содержащие опухоли.

Чтобы визуализировать тепловую карту, наложите тепловую карту на оригинальное изображение и установите 'AlphaData' прозрачности свойство как тканевая маска. Оверлей показывает, насколько хорошо опухоль локализована на изображении. Области с высокой вероятностью опухолей отображаются с красными пикселями. Области с низкой вероятностью опухолей отображаются в виде синих пикселей.

outputHeatmapsDir = fullfile(testingImageDir,'heatmaps');
if ~exist(outputHeatmapsDir,'dir')
    mkdir(outputHeatmapsDir);
end

patchSize = [299,299,3];

for idx = 1:numTestFiles
    bls = selectBlockLocations(testImages(idx),'BlockSize',patchSize(1:2),'Mask',testTissueMasks(idx),...
        'InclusionThreshold',0,'Levels',1);
    testHeatMaps(idx) = apply(testImages(idx),@(x)tumorProbabilityHeatMap(x,trainedNet), ...
        'Level',1,'BlockLocationSet',bls,'UseParallel',canUseGPU,'OutputLocation',outputHeatmapsDir);

    figure
    hTest = bigimageshow(testImages(idx));
    hTestAxes = hTest.Parent;
    hTestAxes.Visible = 'off';

    hMaskAxes = axes;
    hMask = bigimageshow(testHeatMaps(idx),'Parent',hMaskAxes, ...
        "Interpolation","nearest","AlphaData",testTissueMasks(idx));
    colormap(jet(255));
    hMaskAxes.Visible = 'off';

    linkaxes([hTestAxes,hMaskAxes]);
    title(['Tumor Heatmap of Test Image ',num2str(idx)]);
end

Ссылки

[1] Ehteshami B. B., et al. «Диагностическая оценка алгоритмов глубокого обучения для обнаружения метастазов в лимфатических узлах у женщин с раком молочной железы». Журнал Американской медицинской ассоциации. Том 318, № 22, 2017, с. 2199-2210. doi: 10.1001/jama.2017.14585

[2] Szegedy, C., V. Vanhoucke, S. Ioffe, J. Shlens, and Z. Wojna. «Переосмысление архитектуры создания компьютерного зрения». В работе Конференции IEEE по компьютерному зрению и распознаванию шаблона, 2818-2826. Лас-Вегас, NV: IEEE, 2016.

[3] ImageNet. http://www.image-net.org.

[4] Macenko, M. et al. Метод нормализации гистологических слайдов для количественного анализа. В 2009 году IEEE International Symposium on Biomedical Imaging: From Nano to Macro, 1107-1110. Бостон, Массачусетс: IEEE, 2009.

[5] xml2struct https://www.mathworks.com/matlabcentral/fileexchange/28518-xml2struct.

См. также

| | | (Image Processing Toolbox) | (Image Processing Toolbox) | (Набор Image Processing Toolbox) | (Набор Image Processing Toolbox) | (Набор Image Processing Toolbox)

Похожие темы