Как вы видите на рисунках ниже, в некоторых из результатов моей сегментации (сегментация, сделанная методом преобразования водораздела) осталось несколько остатков. Я хочу как-то обрезать изображения так, чтобы остались только прямоугольники. Эта операция основана только на форме прямоугольника и не относится к уровню интенсивности.Оставшиеся фрагменты сегментов изображений
ответ
Решение Объяснение
я предлагаю следующий подход:
генерировать первоначальное предположение для 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 (взятый из следующего answer, по @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), прежде чем выполнять этот подход для устранения небольших артефактов.
Возможно запустить алгоритм с несколькими исходными догадками и выбрать лучший.
Обратите внимание, что это решение не оценивает наилучший возможный прямоугольник - он оценивает лучшие четырехугольники. Причина в том, что входные изображения не являются прямоугольниками (линии не параллельны).
Я думаю, что это интересный вопрос! если у вас нет четкой идеи, дайте мне подсказку, поэтому, возможно, я смогу использовать вашу идею, чтобы найти полное решение. – Woeitg
Непонятно. Является ли левое изображение источником? Если нет, вы можете показать исходное изображение и объяснить, как вы выполняете сегментацию. Потому что это может быть связано с вашей проблемой. – kebs
А также покажите фрагмент кода того, что у вас есть. Связано это с Opencv? Если да, добавьте тег. – kebs