Find the corners of a polygon represented by a region mask

前端 未结 5 1631
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-09 13:01

BW = poly2mask(x, y, m, n) computes a binary region of interest (ROI) mask, BW, from an ROI polygon, represented by the vectors x and y. Th

5条回答
  •  忘掉有多难
    2020-12-09 13:39

    If you have the Image Processing Toolbox, there is a function called cornermetric which can implement a Harris corner detector or Shi and Tomasi's minimum eigenvalue method. This function has been present since version 6.2 of the Image Processing Toolbox (MATLAB version R2008b).

    Using this function, I came up with a slightly different approach from the other answers. The solution below is based on the idea that a circular area centered at each "true" corner point will overlap the polygon by a smaller amount than a circular area centered over an erroneous corner point that is actually on the edge. This solution can also handle cases where multiple points are detected at the same corner...

    The first step is to load the data:

    rawImage = imread('oxyjj.png');
    rawImage = rgb2gray(rawImage(7:473, 9:688, :));  % Remove the gray border
    subplot(2, 2, 1);
    imshow(rawImage);
    title('Raw image');
    

    Next, compute the corner metric using cornermetric. Note that I am masking the corner metric by the original polygon, so that we are looking for corner points that are inside the polygon (i.e. trying to find the corner pixels of the polygon). imregionalmax is then used to find the local maxima. Since you can have clusters of greater than 1 pixel with the same corner metric, I then add noise to the maxima and recompute so that I only get 1 pixel in each maximal region. Each maximal region is then labeled using bwlabel:

    cornerImage = cornermetric(rawImage).*(rawImage > 0);
    maxImage = imregionalmax(cornerImage);
    noise = rand(nnz(maxImage), 1);
    cornerImage(maxImage) = cornerImage(maxImage)+noise;
    maxImage = imregionalmax(cornerImage);
    labeledImage = bwlabel(maxImage);
    

    The labeled regions are then dilated (using imdilate) with a disk-shaped structuring element (created using strel):

    diskSize = 5;
    dilatedImage = imdilate(labeledImage, strel('disk', diskSize));
    subplot(2, 2, 2);
    imshow(dilatedImage);
    title('Dilated corner points');
    

    Now that the labeled corner regions have been dilated, they will partially overlap the original polygon. Regions on an edge of the polygon will have about 50% overlap, while regions that are on a corner will have about 25% overlap. The function regionprops can be used to find the areas of overlap for each labeled region, and the 4 regions that have the least amount of overlap can thus be considered as the true corners:

    maskImage = dilatedImage.*(rawImage > 0);       % Overlap with the polygon
    stats = regionprops(maskImage, 'Area');         % Compute the areas
    [sortedValues, index] = sort([stats.Area]);     % Sort in ascending order
    cornerLabels = index(1:4);                      % The 4 smallest region labels
    maskImage = ismember(maskImage, cornerLabels);  % Mask of the 4 smallest regions
    subplot(2, 2, 3);
    imshow(maskImage);
    title('Regions of minimal overlap');
    

    And we can now get the pixel coordinates of the corners using find and ismember:

    [r, c] = find(ismember(labeledImage, cornerLabels));
    subplot(2, 2, 4);
    imshow(rawImage);
    hold on;
    plot(c, r, 'r+', 'MarkerSize', 16, 'LineWidth', 2);
    title('Corner points');
    

    And here's a test with a diamond shaped region:

提交回复
热议问题