Классифицируйте пиксели Используя нечеткие системы

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

Классификация пикселей является методом обработки изображений, который сегментирует изображение путем классификации каждого пикселя согласно определенным пиксельным атрибутам. Шум и другие источники неопределенности могут усложнить классификацию пикселей. Используя основанный на FIS метод для классификации может помочь обратиться к такой неопределенности.

Этот пример включает следующие этапы.

  1. Настройте FIS, чтобы классифицировать пиксели на основе цвета.

  2. Настройте FIS, чтобы классифицировать пиксели на основе структуры.

  3. Объедините настроенные объекты FIS в иерархическую нечеткую систему для классификации пикселей.

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

exData = load('fuzzpixclass');
cImg = exData.cImg;

figure
imshow(cImg)

Figure contains an axes. The axes contains an object of type image.

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

Изображение сегмента Используя цвет

Сегменты изображений включают следующие атрибуты цвета.

  • Зеленое поле: изменение зеленых и темных теневых пикселей

  • Белая граница: белые, светло-зеленые, и темные теневые пиксели

  • Футбольный мяч: пиксели белого и темного цвета

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

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

grnImg = exData.grnImg;
whtImg = exData.whtImg;

figure
subplot(1,2,1)
imshow(grnImg)
xlabel('Green subimage')
subplot(1,2,2)
imshow(whtImg)
xlabel('White subimage')

Figure contains 2 axes. Axes 1 contains an object of type image. Axes 2 contains an object of type image.

Создайте FIS

Для цветной сегментации создайте Sugeno FIS с одним выходом, с тремя входами без правил. Для каждой переменной ввода и вывода включайте две функции принадлежности по умолчанию (MFS).

colorFISIn = sugfis('NumInputs',3,'NumInputMFs',2, ...
    'NumOutputs',1,'NumOutputMFs',2,'AddRules','none');

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

Обучите FIS

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

[grnSubRow,grnSubCol,grnSubDepth] = size(grnImg);  % Green subimage size
[whtSubRow,whtSubCol,whtSubDepth] = size(whtImg);  % White subimage size
trnX = [...
    getColorInputData(grnImg); ...
    getColorInputData(whtImg) ...
    ];
trnY = [...
    ones(grnSubRow*grnSubCol,1); ... % Output is high (1) for green pixels
    zeros(whtSubRow*whtSubCol,1) ... % Output is low (1) for white pixels
    ];

Входные данные trnX имеет три столбца для пиксельных значений RGB. Выходные данные trnY вектор-столбец, который содержит 1 для каждого зеленого пикселя и 0 для каждого белого пикселя.

Создайте набор опции для изучения правил для colorFISIn. Чтобы уменьшать длительность процесса оптимизации, используйте минимальные значения для параметров перекрестной проверки.

options = tunefisOptions('OptimizationType','learning','KFoldValue',2, ...
    'ValidationTolerance',0.0,'ValidationWindowSize',1);

Если у вас есть программное обеспечение Parallel Computing Toolbox™, можно улучшить скорость настраивающего процесса установкой options.UseParallel к true. Если у вас нет программного обеспечения Parallel Computing Toolbox, установите options.UseParallel к false.

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

rng('default')

Изучите нечеткие правила для colorFISIn использование обучающих данных и опций. Изучение правил с помощью tunefis функция может занять несколько минут. В данном примере можно позволить настроиться установкой runtunefis к true. Загружать предварительно обученные результаты, не запуская tunefis, установите runtunefis к false.

runtunefis = false;

Чтобы изучить новые правила, не настраивая параметры MF ввода и вывода, установите установки параметров на []. Для получения дополнительной информации смотрите tunefis.

if runtunefis
    colorFISOut1 = tunefis(colorFISIn,[],trnX,trnY,options); %#ok<UNRCH>
else
    colorFISOut1 = exData.colorFISOut1;
end

Вычислите среднеквадратическую ошибку (RMSE) для обученного FIS. calculateRMSE функция помощника, которую показывают в конце примера, классифицирует пиксели обучающих данных с помощью обученного FIS и сравнивает результаты с ожидаемыми классификациями пикселей.

fprintf('Training RMSE after learning rules = %.3f MPG\n',...
    calculateRMSE(colorFISOut1,trnX,trnY));
Training RMSE after learning rules = 0.283 MPG

После изучения новых правил настройте параметры MF ввода и вывода. Чтобы получить настройки настраиваемого параметра FIS, используйте getTunableSettings функция.

[in,out] = getTunableSettings(colorFISOut1);

Чтобы настроить существующие значения параметров FIS, не изучая новых правил, установите OptimizationType к 'tuning'.

options.OptimizationType = 'tuning';

Настройте параметры FIS с помощью заданных настраиваемых настроек, обучающих данных, и настроив опции.

if runtunefis
    rng('default')
    colorFISOut = tunefis(colorFISOut1,[in;out],trnX,trnY,options);
    colorFISOut.Name = "colorFISOut";
else
    colorFISOut = exData.colorFISOut;
    
end

Вычислите RMSE для настроенного FIS.

fprintf('Training RMSE after tuning MF parameters = %.3f MPG\n',...
        calculateRMSE(colorFISOut,trnX,trnY));
Training RMSE after tuning MF parameters = 0.228 MPG

Изображение сегмента

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

[imgRow,imgCol,imgDepth] = size(cImg);
red = cImg(:,:,1);
green = cImg(:,:,2);
blue = cImg(:,:,3);
colorInput = [red(:) green(:) blue(:)];

Классифицируйте каждый пиксель с помощью настроенного FIS.

eoptions = evalfisOptions;
eoptions.EmptyOutputFuzzySetMessage = 'none';
eoptions.NoRuleFiredMessage = 'none';
eoptions.OutOfRangeInputValueMessage = 'none';

y = evalfis(colorFISOut,colorInput,eoptions);

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

greenSegment = getSegmentedImage(reshape(y,[imgRow,imgCol]),cImg);

Просмотрите сегментированное изображение. Пиксели, которые FIS, классифицированные как белые, отображают черным цветом. Остающиеся пиксели классифицируются как зеленые.

figure
imshow(greenSegment)

Figure contains an axes. The axes contains an object of type image.

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

Изображение сегмента Используя структуру

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

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

ballImg = exData.ballImg;
grayGrnImg = rgb2gray(grnImg);
grayWhtImg = rgb2gray(whtImg);
grayBallImg = rgb2gray(ballImg);

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

[gX,gY] = imgradientxy(grayGrnImg);
grnGrsTexture = normMat(imgradient(gX,gY));

[gX,gY] = imgradientxy(grayWhtImg);
whtGrsTexture = normMat(imgradient(gX,gY));

[gX,gY] = imgradientxy(grayBallImg);
ballTexture = normMat(imgradient(gX,gY));

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

figure,
subplot(2,3,1)
imshow(grnImg)
subplot(2,3,2)
imshow(whtImg)
subplot(2,3,3)
imshow(ballImg)
subplot(2,3,4)
imshow(grnGrsTexture)
subplot(2,3,5)
imshow(whtGrsTexture)
subplot(2,3,6)
imshow(ballTexture)

Figure contains 6 axes. Axes 1 contains an object of type image. Axes 2 contains an object of type image. Axes 3 contains an object of type image. Axes 4 contains an object of type image. Axes 5 contains an object of type image. Axes 6 contains an object of type image.

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

Создайте FIS

Нормированные градиенты для мяча и поля травы имеют различные шаблоны. Чтобы изучить эти шаблоны, создайте Sugeno FIS с одним выходом, с тремя входами без правил. Для каждой переменной ввода и вывода включайте две функции принадлежности по умолчанию (MFS).

textureFISIn = sugfis('NumInputs',3,'NumInputMFs',2, ...
    'NumOutputs',1,'NumOutputMFs',2,'AddRules','none');

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

Обучите FIS

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

[grsGradRow,grsGradCol] = size(grnGrsTexture);   % Grass texture size
[ballGradRow,ballGradCol] = size(ballTexture);   % Ball texture size
trnX = [...
    getGradientInputData(grnGrsTexture); ... % gradient values of 3 successive pixels
    getGradientInputData(ballTexture) ...    % gradient values of 3 successive pixels
    ];
trnY = [...
    ones(grsGradRow*grsGradCol,1); ...   % Output is high (1) for green texture
    zeros(ballGradRow*ballGradCol,1) ... % Output is low (1) for ball texture
    ];

Входные данные trnX имеет три столбца для значений градиента трех последовательных пикселей. Выходные данные trnY вектор-столбец, который содержит 1, если третий пиксель принадлежит полевой структуре и 0 в противном случае.

Чтобы изучить нечеткие правила, установите OptimizationType к 'learning'.

options.OptimizationType = 'learning';

Обучите textureFISIn изучить правила с помощью обучающих данных.

if runtunefis
    rng('default')
    textureFISOut1 = tunefis(textureFISIn,[],trnX,trnY,options); %#ok<UNRCH>
else
    textureFISOut1 = exData.textureFISOut1;
end
fprintf('Training RMSE after learning rules = %.3f MPG\n',...
    calculateRMSE(textureFISOut1,trnX,trnY));
Training RMSE after learning rules = 0.477 MPG

После изучения новых правил настройте параметры MF ввода и вывода. Чтобы получить настраиваемые параметры FIS, используйте getTunableSettings функция.

[in,out] = getTunableSettings(textureFISOut1);

Чтобы настроить существующие параметры FIS, не изучая новых правил, установите OptimizationType к 'tuning'.

options.OptimizationType = 'tuning';

Настройте параметры FIS с помощью заданных настраиваемых настроек, обучающих данных, и настроив опции.

if runtunefis
    rng('default')
    textureFISOut = tunefis(textureFISOut1,[in;out],trnX,trnY,options);
    textureFISOut.Name = "textureFISOut";
else
    textureFISOut = exData.textureFISOut;
end
fprintf('Training RMSE after tuning MF parameters = %.3f MPG\n',...
    calculateRMSE(textureFISOut,trnX,trnY));
Training RMSE after tuning MF parameters = 0.442 MPG

Изображение сегмента

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

[gX,gY] = imgradientxy(rgb2gray(cImg));
imgTexture = normMat(imgradient(gX,gY));
gradInput = getGradientInputData(imgTexture);

Классифицируйте каждый пиксель с помощью настроенного FIS.

y = evalfis(textureFISOut,gradInput,eoptions);

Сегментируйте изображение с помощью getSegmentedImage функция помощника.

grassField = getSegmentedImage(reshape(y,[imgRow,imgCol]),cImg);

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

figure
imshow(grassField)

Figure contains an axes. The axes contains an object of type image.

Обученные сегменты FIS поле травы и мяч с немногими неправильными пикселями в сегментах.

Изображение сегмента и Используя цвет и Используя структуру

Чтобы классифицировать пиксели и на основе цвета и на основе структуры, можно объединить colorFISOut и textureFISOut использование иерархической нечеткой системы или дерева FIS.

Для этого сначала создайте Sugeno FIS с двумя входными параметрами и тремя выходными параметрами. Первой входной переменной является выход colorFISOut и второй входной переменной является выход textureFISOut. Выходные переменные являются степенью, до которой пиксели принадлежит каждому сегменту изображений: зеленое поле, белая граница и футбольный мяч.

segFIS = sugfis('Name','segFIS','NumInputs',2,'NumInputMFs',2, ...
    'NumOutputs',3,'NumOutputMFs',2,'AddRules','none');

Назовите входные переменные, выходную переменную и MFS.

segFIS.Inputs(1).Name = 'color';
segFIS.Inputs(1).MembershipFunctions(1).Name = 'white';
segFIS.Inputs(1).MembershipFunctions(2).Name = 'green';
segFIS.Inputs(2).Name = 'texture';
segFIS.Inputs(2).MembershipFunctions(1).Name = 'ball';
segFIS.Inputs(2).MembershipFunctions(2).Name = 'grass';
segFIS.Outputs(1).Name = 'greenField';
segFIS.Outputs(1).MembershipFunctions(1).Name = 'low';
segFIS.Outputs(1).MembershipFunctions(2).Name = 'high';
segFIS.Outputs(2).Name = 'whiteBorder';
segFIS.Outputs(2).MembershipFunctions(1).Name = 'low';
segFIS.Outputs(2).MembershipFunctions(2).Name = 'high';
segFIS.Outputs(3).Name = 'soccerBall';
segFIS.Outputs(3).MembershipFunctions(1).Name = 'low';
segFIS.Outputs(3).MembershipFunctions(2).Name = 'high';

Добавьте следующие правила в FIS.

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

  • Если пиксель является белым и имеет структуру травы, устанавливает белую границу выход на высоко.

  • Если пиксель является зеленым и имеет структуру травы и является зеленым полем выход к высоко.

rules = ["texture==ball => greenField=low, whiteBorder=low, soccerBall=high";
         "color==white & texture==grass => greenField=low, whiteBorder=high, soccerBall=low";
         "color==green & texture==grass => greenField=high, whiteBorder=low, soccerBall=low"];
segFIS = addRule(segFIS,rules);

Создайте дерево FIS путем соединения выходных параметров colorFISOut и textureFISOut к входным параметрам segFIS.

fis = [colorFISOut textureFISOut segFIS];
con = [...
    "colorFISOut/output1" "segFIS/color"; ...
    "textureFISOut/output1" "segFIS/texture" ...
    ];
fisT = fistree(fis,con);

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

y = evalfis(fisT,[colorInput gradInput],eoptions);
greenField = getSegmentedImage(reshape(y(:,1),[imgRow,imgCol]),cImg);
whiteBorder = getSegmentedImage(reshape(y(:,2),[imgRow,imgCol]),cImg);
soccerBall = getSegmentedImage(reshape(y(:,3),[imgRow,imgCol]),cImg);

Просмотрите пиксели зеленого поля.

figure
imshow(greenField)
xlabel('Green field')

Figure contains an axes. The axes contains an object of type image.

Просмотрите белые краевые элементы изображения.

figure
imshow(whiteBorder)
xlabel('White border')

Figure contains an axes. The axes contains an object of type image.

Просмотрите пиксели футбольного мяча.

figure
imshow(soccerBall)
xlabel('Soccer ball')

Figure contains an axes. The axes contains an object of type image.

Заключение

Сегменты изображений содержат неправильные классификации. Можно удалить многие неправильно классифицированные пиксели последующей обработкой результаты с помощью алгоритмов шумоподавления, таких как морфологические операции (imdilate, imerode, imopen, imclose). Например, используйте морфологическую операцию закрытия, чтобы уменьшать шум в сегментированном изображении зеленого поля.

greenFieldLowNoise = getSegmentedImageClose(reshape(y(:,1),[imgRow,imgCol]),cImg);
figure
imshow(greenFieldLowNoise)

Figure contains an axes. The axes contains an object of type image.

Чтобы улучшать нечеткую производительность классификатора, вы можете:

  • Используйте больше обучающих данных.

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

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

  • Добавьте больше MFS в FIS для классификации пикселей.

  • Используйте тип 2 FIS.

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

  • Настройте параметры созданного древовидного segFIS FIS.

Локальные функции

function data = getColorInputData(img)
% Create RGB input data from an image for training.

[row,col,depth] = size(img);
data = zeros(row*col,depth);
id = 0;
for i = 1:row
    for j = 1:col
        id = id + 1;
        for k = 1:depth
            data(id,k) = img(i,j,k);
        end
    end
end

end

function [rmse,actY] = calculateRMSE(fis,x,y)
% Calculate root mean squared error for FIS output.

% Specify options for FIS evaluation
persistent evalOptions
if isempty(evalOptions)
    evalOptions = evalfisOptions("EmptyOutputFuzzySetMessage","none", ...
        "NoRuleFiredMessage","none","OutOfRangeInputValueMessage","none");
end

% Evaluate FIS
actY = evalfis(fis,x,evalOptions);

% Calculate RMSE 
del = actY - y;
rmse = sqrt(mean(del.^2));

end

function cImg = getSegmentedImage(y,cImg)
% Segment an image using classifier output by creating a binary image
% using a 0.5 threshold.

id = y >= 0.5;
y(id) = 1;
y(~id) = 0;

cImg(:,:,1) = cImg(:,:,1).*y;
cImg(:,:,2) = cImg(:,:,2).*y;
cImg(:,:,3) = cImg(:,:,3).*y;

end

function y = normMat(x)
% Normalize array elements to the range [0 1].

tmp = x(:);
mn = min(tmp);
mx = max(tmp);
d = (mx-mn);
y = (x-mn);
if d>0
    y = y/d;
end

end

function data = getGradientInputData(x)
% Create gradient input data for training.

x = x(:);
n = 3; % Three successive gradient values.
data = zeros(length(x),n);

% Specify complete input vectors.
for i = n:length(x)
   data(i,:) = x(i-n+1:i)';
end

% Approximate missing elements in the incomplete input vector.
for i = n-1:-1:1
    right = x(1:i)';
    m = n - i;
    left = repmat(right(1),[1 m]);
    data(i,:) = [left right];
end

end

function cImg = getSegmentedImageClose(y,cImg)
% Segment an image using classifier output by creating a binary image
% using a 0.5 threshold.

id = y >= 0.5;
y(id) = 1;
y(~id) = 0;

se = strel('disk',1);
y = imclose(y,se);

cImg(:,:,1) = cImg(:,:,1).*y;
cImg(:,:,2) = cImg(:,:,2).*y;
cImg(:,:,3) = cImg(:,:,3).*y;

end

Смотрите также

| | |

Похожие темы