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

В этом примере показано, как создать маркированное заблокированное изображение, состоящее из категориальных меток.

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

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

bim = blockedImage('tumor_091R.tif');

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

pixelExtent = bim.Size(1,:)./(bim.WorldEnd(1,:) - bim.WorldStart(1,:));

Загрузка данных меток

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

Загрузите данные метки для заблокированного изображения. Этот пример использует измененную версию меток «tumor_091.tif» изображения из CAMELYON16 набора данных. Исходные метки хранятся в формате XML. Измененные метки повторно дискретизируются и сохраняются как MAT файла.

roiPoints = load('labelledROIs.mat')
roiPoints = struct with fields:
       cancerRegions: {[344×2 double]  [53×2 double]  [539×2 double]  [247×2 double]  [37×2 double]  [161×2 double]}
    nonCancerRegions: {[46×2 double]}

Создайте полигональные объекты информации только для чтения, которые хранят координаты опухолевых контуров и нормальных контуров ткани.

tumorPolys = cellfun(@(position) images.roi.Polygon( ...
    'Position',position,'Visible','on','Color','r'), ...
    roiPoints.cancerRegions);
normalPolys = cellfun(@(position) images.roi.Polygon( ...
    'Position',position,'Visible','on','Color','g'), ...
    roiPoints.nonCancerRegions);

Представление меток как объектов информация только для чтения

Отобразите изображение, наложенное аннотированными ROIs. ROI имеют ту же систему координат, что и изображение, поэтому изменение уровней разрешения отображаемого изображения все еще точно отображает ROI.

figure
h = bigimageshow(bim);
set(tumorPolys,'Parent',gca);
set(normalPolys,'Parent',gca);
title(['Resolution Level:' num2str(h.ResolutionLevel)]);

Изменение масштаба до одного информация только для чтения.

xlim([3940 4290])
ylim([2680 3010])
title(['Resolution Level:' num2str(h.ResolutionLevel)]);

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

Создайте маску на самом грубом уровне разрешения для окрашенной области, которая включает как опухоль, так и нормальную ткань. Маска 1 (true) для пикселей, чье значение полутонового цвета меньше 130. Заполните небольшие отверстия в маске, выполнив морфологическое закрытие с помощью bwmorph функция.

tissueMask = apply(bim, ...
    @(bs)bwmorph(rgb2gray(bs.Data)<130,'close'),"Level",3);
bigimageshow(tissueMask);

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

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

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

blockSize = [512 512]; 
destination = []; % Save the result 'in memory'
sizeOfLabeled = bim.Size(1,1:2); % Labelled image is MxN (2D)
labelIDs = [0,1,2];
labelClasses = ["Background","Normal","Tumor"];
initialvalue = categorical(NaN, labelIDs, labelClasses);
bLabeled = blockedImage(destination,sizeOfLabeled,blockSize,initialvalue,...
    'WorldStart', bim.WorldStart(1,1:2),...
    'WorldEnd', bim.WorldEnd(1,1:2),...
    'Mode','w')
bLabeled = 
  blockedImage with properties:

   Read only properties
             Source: []
            Adapter: [1×1 images.blocked.InMemory]
               Size: [5000 5358]
       SizeInBlocks: [10 11]
    ClassUnderlying: "categorical"
          BlockSize: [512 512]

   Settable properties
       InitialValue: <undefined>

Цикл через каждое выходное заблокированное изображение, по одному блоку за раз. Определите метку каждого блока, затем установите пиксельные данные блока соответственно.

Чтобы определить метку каждого блока, начните с маски всей ткани. Пиксельные значения 0 в маске соответствует фону, который соответствует идентификатору пиксельной метки класса 'Background'. Пиксельные значения 1 в маске соответствуют всем тканям, что соответствует идентификатору пиксельной метки класса 'Normal'. Преобразуйте многоугольные координаты опухолевой ткани в маску при помощи poly2mask , затем замените эти пиксели на идентификатор пиксельной метки класса 'Tumor', 2.

Если у вас есть Parallel Computing Toolbox™, то можно запустить цикл параллельно, заменив for оператор со parfor оператор.

for cInd =  1:bLabeled.SizeInBlocks(2)
    for rInd = 1:bLabeled.SizeInBlocks(1)
        blockSub = [rInd, cInd];
        blockStart = bLabeled.blocksub2sub(blockSub);
        blockEnd = blockStart + bLabeled.BlockSize - 1;
        % Clamp to image end
        blockEnd = min(blockEnd, bLabeled.Size);
        
        % Read the corresponding region from the tissue mask. Since the
        % mask is at a different level, convert coordinates to world and
        % back.
        blockStartEndInWorld = bLabeled.sub2world([blockStart; blockEnd]);
        blockStartEndMaskSub = tissueMask.world2sub(blockStartEndInWorld);
        maskBlock = getRegion(tissueMask, blockStartEndMaskSub(1,:), blockStartEndMaskSub(2,:));
        
        % Scale up the mask region
        maskBlock = imresize(maskBlock, [blockEnd-blockStart+1]);
        
        % Find the pixel coordinates of healthy tissue then convert the
        % polygon coordinates to a mask.
        roiBlock = false(size(maskBlock));
        xyStart = fliplr(blockStart);
        for ind = 1:numel(roiPoints.cancerRegions)
            vertices = roiPoints.cancerRegions{ind};
            % Transform coordinates to local block pixel locations
            vertices = (vertices-xyStart);
            isTumor = poly2mask(vertices(:,1),vertices(:,2), ...
                size(roiBlock,1), size(roiBlock,2));
            roiBlock = roiBlock|isTumor;
        end
        
        % Some healthy tissue ROIs are enclosed within a tumor ROI. Find
        % the pixel coordinates of healthy tissue then convert the polygon
        % coordinates to a mask.
        for ind = 1:numel(roiPoints.nonCancerRegions)
            vertices = roiPoints.nonCancerRegions{ind};
            % Transform coordinates to local block pixel locations
            vertices = (vertices-xyStart);
            isHealthy = poly2mask(vertices(:,1),vertices(:,2), ...
                size(roiBlock,1), size(roiBlock,2));
            roiBlock = roiBlock & ~isHealthy;
        end         
        
        % Set the value of pixels in tumor regions as the corresponding
        % pixel label ID, |2|.
        blockNumeric = uint8(maskBlock);
        blockNumeric(roiBlock) = 2;
        
        % Create a categorical image from the block data.
        blockCategorical = categorical(blockNumeric,...
            labelIDs, labelClasses);
        
        % Set the block of the categorical blocked image as the categorical
        % block image.
        setBlock(bLabeled, blockSub ,blockCategorical);
        
    end
end

bLabeled.Mode = 'r';

Отображение наложения меток и исходных данных

Отобразите данные изображения, а затем отобразите маркированные данные изображения в тех же осях. Три метки (нормальная, опухоль и фон) появляются в трех разных цветах. Сделать метки частично прозрачными, чтобы можно было различать содержимое изображения под ними.

figure
hbim = bigimageshow(bim);
hla = axes;
hbl  = bigimageshow(bLabeled,'Parent',hla);
hbl.AlphaData = 0.7;
hla.Visible = 'off';

Изменение масштаба значения ROI. Увеличьте прозрачность меток, чтобы можно было более четко различать содержимое изображений под ними.

linkaxes(findall(gcf,'Type','axes'));

xlim([3940 4290])
ylim([2680 3010])
hbl.AlphaData = 0.5;

Сохранить метки для использования позже

Для большинства наборов данных можно создать метки один раз, а затем повторно использовать метки для нескольких сеансов обучения. Маркированное заблокированное изображение, bLabeled, поддерживается временными файлами, которые не существуют в сеансах MATLAB ®. Чтобы повторно использовать метки в другом сеансе MATLAB, напишите bLabeled в постоянное место.

imageDir = 'Labels';
if exist(imageDir,'dir')
    rmdir('Labels','s');
end
labelDir = fullfile(imageDir,'labelled');
write(bLabeled,labelDir);

В новой сессии MATLAB можно перезагрузить маркированное заблокированное изображение, создав новую blockedImage объект. При загрузке маркированного заблокированного изображения необходимо также указать 'Classes', 'PixelLabelIDs', и 'UndefinedID'.

bLabeled = blockedImage(labelDir);

См. также

| |

Похожие темы