答案 0 :(得分:5)
解决方案说明
我建议采用以下方法:
根据几何属性生成形状的4个角的初始猜测(详见下面的代码)。
通过在每对相应角之间画一条线,在给定这4个角的情况下创建一个四边形。
找到优化边界图像的Jaccard系数和生成的四边形地图的角落。
为了节省时间,优化阶段将在本地完成。我们将尝试用某个社区中可实现的最佳角落替换每个角落。如果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的以下answer)
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)可以在执行此方法之前完成,以消除小的伪影。
可以使用多个初始猜测运行算法并选择最佳算法。
请注意,此解决方案并未估算出最佳矩形 - 它估计最佳四边形。原因是输入图像不是矩形(线条不平行)。