简体   繁体   English

如何使用Matlab在bw图像中平方“矩形”的角

[英]How to square the corners of a “rectangle” in a bw image with matlab

I have images of rectangles or deformed rectangles with rounded corners, like this: 我有带有圆角的矩形或变形矩形的图像,如下所示: 在此处输入图片说明

or this: 或这个:

在此处输入图片说明

is there a way to make the corners squared with matlab? 有没有一种方法可以使角与Matlab平方?

And then how can i get the coordinates of those new corners? 然后我如何获得这些新角的坐标?

Thank you 谢谢

Explanation 说明

This problem is similar to the following question . 此问题类似于以下问题 My answer will be somehow similar to my answer there, with the relevant modifications. 我的答案将在某种程度上类似于我的答案,并进行相应的修改。

we want to find the parallelogram corners which fits the most to the given shape. 我们想找到最适合给定形状的平行四边形角。 The solution can be found by optimization, as follows: 可以通过优化找到解决方案,如下所示:

  1. find an initial guess for the 4 corners of the shape. 找到形状的四个角的初始猜测。 This can be done by finding the boundary points with the highest curvature, and use kmean clustering to cluster them into 4 groups. 这可以通过找到曲率最高的边界点并使用kmean聚类将其分为4组来完成。

  2. create a parallelogram given these 4 corners, by drawing a line between each pair of corresponding corners. 通过在每对对应的角之间绘制一条线,在给定这四个角的情况下创建平行四边形。

  3. find the corners which optimize the Jaccard coefficient of the boundary image and the generated parallelogram map. 找到优化边界图像的Jaccard系数和生成的平行四边形图的角。

The optimization will done locally on each corner, in order to spare time. 优化工作将在每个角落进行,以节省时间。

Results 结果

Initial corner guess (corners are marked in blue) 初始拐角猜测(角标记为蓝色)

在此处输入图片说明

final results: 最终结果:

在此处输入图片说明

Code

main script 主脚本

%reads image and binarize it
I = rgb2gray(imread('eA4ci.jpg')) > 50;

%finds boundry of largerst connected component
boundries = bwboundaries(I,8);
numPixels = cellfun(@length,boundries);
[~,idx] = max(numPixels);
B = boundries{idx};

%finds best 4 corners
[ corners ] = optimizeCorners(B);

%generate line mask given these corners, fills the result
linesMask = drawLines(size(I),corners,corners([2:4,1],:));
rectMask = imfill(linesMask,'holes');

%remove biggest CC from image, adds linesMask instead
CC = bwconncomp(I,8);
numPixels = cellfun(@numel,CC.PixelIdxList);
[~,idx] = max(numPixels);
res = I;
res(CC.PixelIdxList{idx}) = 0;
res = res | rectMask;

optimize corners function: 优化弯道功能:

function [ corners] = optimizeCorners(xy)
%finds the corners which fits the most for this set of points

Y = xy(:,1);
X = xy(:,2);

%initial corners guess
corners = getInitialCornersGuess(xy);
boundriesIm = zeros(max(Y)+20,max(X)+20);
boundriesIm(sub2ind(size(boundriesIm),xy(:,1),xy(:,2))) = 1;

%R represents the search radius
R = 7;

%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;

        for yy=currentCorner(1)-R:currentCorner(1)+R
            for xx=currentCorner(2)-R:currentCorner(2)+R

                cornersToEvaluate(ii,:) = [yy,xx];
                res = calcEnergy(boundriesIm,cornersToEvaluate);
                if res > bestRes
                    bestRes = res;
                    bestCorner = [yy,xx];
                end
            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

get initial corners function: 获取初始角点功能:

function corners = getInitialCornersGuess(boundryPnts)
%calculates an initial guess for the 4 corners

%finds corners by performing kmeans on largest curvature pixels
[curvatureArr] = calcCurvature(boundryPnts, 5);
highCurv = boundryPnts(curvatureArr>0.3,:);
[~,C] = kmeans([highCurv(:,1),highCurv(:,2)],4);

%sorts the corners from top to bottom - preprocessing stage
C = int16(C);
corners = zeros(size(C));

%top left corners
topLeftInd = find(sum(C,2)==min(sum(C,2)));
corners(1,:) = C(topLeftInd,:);
%bottom right corners
bottomRightInd  = find(sum(C,2)==max(sum(C,2))); 
corners(3,:) = C(bottomRightInd,:);
%top right and bottom left corners
C([topLeftInd,bottomRightInd],:) = [];
topRightInd = find(C(:,2)==max(C(:,2)));
corners(4,:) = C(topRightInd,:);
bottomLeftInd = find(C(:,2)==min(C(:,2)));
corners(2,:) = C(bottomLeftInd,:);



end



function [curvatureArr] = calcCurvature(xy, halfWinSize)
%calculate the curvature of a list of points (xy) given a window size

%curvature calculation
curvatureArr = zeros(size(xy,1),1);
for t=1:halfWinSize
    y = xy(t:halfWinSize:end,1);
    x = xy(t:halfWinSize:end,2);
    dx  = gradient(x);
    ddx = gradient(dx);
    dy  = gradient(y);
    ddy = gradient(dy);
    num   = abs(dx .* ddy - ddx .* dy)  + 0.000001;
    denom = dx .* dx + dy .* dy + 0.000001;
    denom = sqrt(denom);
    denom = denom .* denom .* denom;
    curvature = num ./ denom;

    %normalizing
    if(max(curvature) > 0)
        curvature = curvature / max(curvature);
    end

    curvatureArr(t:halfWinSize:end) = curvature;

end

end

draw lines function: 画线功能:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM