В этом примере показано, как классифицировать пиксели изображения с помощью нечеткой системы вывода (FIS). Этот пример требует программного обеспечения Image Processing Toolbox™.
Классификация пикселей является методом обработки изображений, который сегментирует изображение путем классификации каждого пикселя согласно определенным пиксельным атрибутам. Шум и другие источники неопределенности могут усложнить классификацию пикселей. Используя основанный на FIS метод для классификации может помочь обратиться к такой неопределенности.
Этот пример включает следующие этапы.
Настройте FIS, чтобы классифицировать пиксели на основе цвета.
Настройте FIS, чтобы классифицировать пиксели на основе структуры.
Объедините настроенные объекты FIS в иерархическую нечеткую систему для классификации пикселей.
Загрузите данные изображения, которые содержат три видимых сегмента: зеленая трава, белая граница и футбольный мяч.
exData = load('fuzzpixclass');
cImg = exData.cImg;
figure
imshow(cImg)
Этот пример использует нечеткие системы, чтобы сегментировать изображение на три категории путем классификации каждого пикселя как принадлежащий зеленой траве, белой границе или футбольному мячу.
Сегменты изображений включают следующие атрибуты цвета.
Зеленое поле: изменение зеленых и темных теневых пикселей
Белая граница: белые, светло-зеленые, и темные теневые пиксели
Футбольный мяч: пиксели белого и темного цвета
Поскольку количество темных пикселей незначительно по сравнению с зелеными и белыми пикселями, можно создать один нечеткий классификатор, чтобы различать зеленые и белые пиксели. Можно обучить классификаторы с демонстрационными зелеными и белыми пикселями, поскольку ни один из сегментов не включает атрибут уникального цвета.
Извлеките представительные подызображения из зеленого поля и белых сегментов границы как обучающие данные. Каждое подызображение включает изменения пиксельного цвета.
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')
Создайте 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)
Белые пиксели частично удалены из сегментов мяча и границы. Зеленый сегмент также неправильно включает пиксели от мяча. Поэтому процесс классификации требует другого пиксельного атрибута, который может идентифицировать различие между полем травы и мячом.
Чтобы различать поле и мяч, используйте серые данные о градиенте изображений, чтобы идентифицировать структуры поля и мяча.
Извлеките представительное подызображение для мяча и преобразуйте зеленый, белый цвет, и подызображения мяча к шкале полутонов.
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)
И зеленые и белые сегменты травы имеют подобные значения градиента, которые отличаются, чем те из сегмента мяча. Поэтому используйте только зеленый и данные о градиенте сегмента мяча, чтобы обучить нечеткий классификатор структуры.
Создайте 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)
Обученные сегменты 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
imshow(whiteBorder)
xlabel('White border')
Просмотрите пиксели футбольного мяча.
figure
imshow(soccerBall)
xlabel('Soccer ball')
Сегменты изображений содержат неправильные классификации. Можно удалить многие неправильно классифицированные пиксели последующей обработкой результаты с помощью алгоритмов шумоподавления, таких как морфологические операции (imdilate
, imerode
, imopen
, imclose
). Например, используйте морфологическую операцию закрытия, чтобы уменьшать шум в сегментированном изображении зеленого поля.
greenFieldLowNoise = getSegmentedImageClose(reshape(y(:,1),[imgRow,imgCol]),cImg); figure imshow(greenFieldLowNoise)
Чтобы улучшать нечеткую производительность классификатора, вы можете:
Используйте больше обучающих данных.
Изучите цветовые шаблоны нескольких пикселей вместо того, чтобы изучить отдельный пиксельный цвет.
Увеличьте длину характеристического вектора градиента, другими словами, значений градиента использования больше чем трех последовательных пикселей.
Добавьте больше 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
tunefis
| getTunableSettings
| sugfis
| fistree