В этом примере показано, как классифицировать пикселы изображения с помощью нечеткой системы вывода (FIS). В этом примере требуется программное обеспечение 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
Создайте обучающие данные из репрезентативных цветных субизображений. 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
Нормализованные градиенты для мяча и травяного поля имеют разные закономерности. Чтобы узнать эти шаблоны, создайте FIS Sugeno с тремя входами и одним выходом без правил. Для каждой входной и выходной переменной включите две функции членства по умолчанию (MF).
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.
Для этого сначала создайте сугеновскую FIS с двумя входами и тремя выходами. Первая входная переменная является выходом 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-кратные значения для перекрестной проверки.
Настройка параметров построенного дерева 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