Как вы видите на изображениях ниже, в некоторых моих результатах сегментации (сегментация, выполненная методом преобразования водораздела) остались некоторые остатки. Я хочу как-то обрезать изображения, чтобы остались только прямоугольники. Эта операция основана только на форме прямоугольника и не связана с уровнем интенсивности.
обрезка остатков сегментов изображения
Ответы (1)
Объяснение решения
Я предлагаю следующий подход:
создать начальное предположение для 4 углов формы в соответствии с геометрическими свойствами (дополнительные сведения см. в коде ниже).
создайте четырехугольник, учитывая эти 4 угла, нарисовав линию между каждой парой соответствующих углов.
найти углы, которые оптимизируют коэффициент Жаккара граничного изображения и сгенерированной четырехугольной карты.
В целях экономии времени этап оптимизации будет выполняться локально. Мы постараемся заменить каждый угол лучшим из возможных углов в определенном районе. Останавливаем этап оптимизации, если по каждому из 4-х углов нет улучшения.
код
%reads image
gray = rgb2gray(imread('Bqx51.png'));
I = gray>0;
%extract boundries
B = bwboundaries(I,8);
B = B{1};
boundriesImage = zeros(size(I));
boundriesImage(sub2ind(size(I),B(:,1),B(:,2))) = 1;
%finds best 4 corners
[ corners ] = optimizeCorners(B);
%generate line mask
linesMask = drawLines(size(I),corners,corners([2:4,1],:));
%fill holes
rectMask = imfill(linesMask,'holes');
%noise reduction
rectMask = I & rectMask;
rectMask = imopen(rectMask,strel('disk',2));
%calculate result
result = gray;
result(~rectMask) = 0;
%display results
figure,imshow([gray, 255*ones(size(I,1),1),result]);
функция оптимизации угла
function [ corners] = optimizeCorners(pnts)
%OPTIMIZE4PTS Summary of this function goes here
% Detailed explanation goes here
Y = pnts(:,1);
X = pnts(:,2);
corners = getInitialGuess(X,Y);
boundriesIm = zeros(max(Y),max(X));
boundriesIm(sub2ind(size(boundriesIm),pnts(:,1),pnts(:,2))) = 1;
%R represents the search radius
R = 3;
%continue optimizing as long as there is no change in the final result
unchangedIterations = 0;
while unchangedIterations<4
for ii=1:4
%optimize corner ii
currentCorner = corners(ii,:);
bestCorner = currentCorner;
bestRes = calcEnergy(boundriesIm,corners);
cornersToEvaluate = corners;
candidateInds = sum(((repmat(currentCorner,size(X,1),1)-[Y,X]).^2),2)<(R^2);
candidateCorners = [Y(candidateInds),X(candidateInds)];
for jj=length(candidateCorners)
xx = candidateCorners(jj,2);
yy = candidateCorners(jj,1);
cornersToEvaluate(ii,:) = [yy,xx];
res = calcEnergy(boundriesIm,cornersToEvaluate);
if res > bestRes
bestRes = res;
bestCorner = [yy,xx];
end
end
if isequal(bestCorner,currentCorner)
unchangedIterations = unchangedIterations + 1;
else
unchangedIterations = 0;
corners(ii,:) = bestCorner;
end
end
end
end
Рассчитать функцию энергии
function res = calcEnergy(boundriesIm,corners)
%calculates the score of the corners list, given the boundries image.
%the result is acutally the jaccard index of the boundries map and the
%lines map
linesMask = drawLines(size(boundriesIm),corners,corners([2:4,1],:));
res = sum(sum(linesMask&boundriesIm)) / sum(sum(linesMask|boundriesIm));
end
нахождение начального предположения для функции углов
function corners = getInitialGuess(X,Y)
%calculates an initial guess for the 4 corners
corners = zeros(4,2);
%preprocessing stage
minYCoords = find(Y==min(Y));
maxYCoords = find(Y==max(Y));
minXCoords = find(X==min(X));
maxXCoords = find(X==max(X));
%top corners
topRightInd = find(X(minYCoords)==max(X(minYCoords)),1,'last');
topLeftInd = find(Y(minXCoords)==min(Y(minXCoords)),1,'last');
corners(1,:) = [Y(minYCoords(topRightInd)) X((minYCoords(topRightInd)))];
corners(2,:) = [Y(minXCoords(topLeftInd)) X((minXCoords(topLeftInd)))];
%bottom corners
bottomRightInd = find(Y(maxXCoords)==max(Y(maxXCoords)),1,'last');
bottomLeftInd = find(X(minYCoords)==min(X(minYCoords)),1,'last');
corners(4,:) = [Y(maxXCoords(bottomRightInd)) X((maxXCoords(bottomRightInd)))];
corners(3,:) = [Y(maxYCoords(bottomLeftInd)) X((maxYCoords(bottomLeftInd)))];
end
Функция drawLine (взято из следующего ответа от @Suever)
function mask = drawLines(imgSize, P1, P2)
%generates a mask with lines, determine by P1 and P2 points
mask = zeros(imgSize);
P1 = double(P1);
P2 = double(P2);
for ii=1:size(P1,1)
x1 = P1(ii,2); y1 = P1(ii,1);
x2 = P2(ii,2); y2 = P2(ii,1);
% Distance (in pixels) between the two endpoints
nPoints = ceil(sqrt((x2 - x1).^2 + (y2 - y1).^2));
% Determine x and y locations along the line
xvalues = round(linspace(x1, x2, nPoints));
yvalues = round(linspace(y1, y2, nPoints));
% Replace the relevant values within the mask
mask(sub2ind(size(mask), yvalues, xvalues)) = 1;
end
Результаты
первое изображение (до и после):
второе изображение (до и после):
Время выполнения
Elapsed time is 0.033998 seconds.
Возможные улучшения/предложения
Функция энергии может также включать ограничения, которые побуждают параллельные линии иметь одинаковые наклоны (в вашем примере они не имеют одинакового наклона).
Энергетическая функция может включать ограничения, которые способствуют тому, чтобы углы каждого угла были близки к 90 градусам.
этапы шумоподавления (такие как imclose) могут быть выполнены перед выполнением этого подхода для устранения небольших артефактов.
Алгоритм можно запустить с несколькими начальными предположениями и выбрать наилучшее.
Обратите внимание, что это решение не оценивает наилучший возможный прямоугольник — оно оценивает наилучший четырехугольник. Причина в том, что входные изображения не являются прямоугольниками (линии не параллельны).