В этом примере показано, как классифицировать пиксели изображения с помощью системы нечеткого вывода (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
Для сегментации цвета создайте 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)
Белые пиксели частично удаляются из пограничного и шарового сегментов. Зеленый сегмент также неправильно включает пиксели от мяча. Поэтому процесс классификации требует другого атрибута пикселя, который может идентифицировать различие между травяным полем и мячом.
Чтобы различить поле и мяч, используйте серые данные о градиенте изображения, чтобы идентифицировать текстуры поля и мяча.
Извлеките репрезентативное подызображение для мяча и преобразуйте зеленое, белое и шариковое подызображения в полутоновые.
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
Нормированные градиенты для мяча и травяного поля имеют различные шаблоны. Чтобы узнать эти шаблоны, создайте 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)
Обученная 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
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)
Чтобы улучшить эффективность нечеткого классификатора, можно:
Используйте больше обучающих данных.
Изучение цветовых шаблонов на несколько пикселей вместо изучения отдельного пиксельного цвета.
Увеличьте длину вектора градиентной функции, другими словами, используйте значения градиента более чем на три последовательных пикселя.
Добавьте больше 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
fistree
| getTunableSettings
| sugfis
| tunefis