Классификация пикселей с помощью нечетких систем

В этом примере показано, как классифицировать пиксели изображения с помощью системы нечеткого вывода (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

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

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

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

Обучите FIS

Создайте обучающие данные из репрезентативных подызображений цвета. The 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. The 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

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

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

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

Обучите FIS

Создайте обучающие данные из градиентов зеленых и шаровых областей. The 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.

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

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

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

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.

Чтобы улучшить эффективность нечеткого классификатора, можно:

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

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

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

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

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

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

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

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

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

См. также

| | |

Похожие темы