Если у вас есть Toolbox для обработки изображений , есть функция под названием cornermetric
, которая может реализовать детектор угла Харриса или метод минимального собственного значения Ши и Томази. Эта функция присутствует с версии 6.2 панели инструментов обработки изображений (MATLAB версия R2008b).
Используя эту функцию, я придумал немного другой подход, чем другие ответы. Приведенное ниже решение основано на идее, что круговая область с центром в каждой «истинной» угловой точке будет перекрывать многоугольник на меньшую величину, чем круговая область с центром в ошибочной угловой точке, которая фактически находится на краю. Это решение может также обрабатывать случаи, когда несколько точек обнаруживаются в одном и том же углу ...
Первый шаг - загрузить данные:
rawImage = imread('oxyjj.png');
rawImage = rgb2gray(rawImage(7:473, 9:688, :)); % Remove the gray border
subplot(2, 2, 1);
imshow(rawImage);
title('Raw image');
Затем вычислите угловую метрику, используя cornermetric
. Обратите внимание, что я маскирую угловую метрику исходным многоугольником, так что мы ищем угловые точки, которые внутри многоугольника (т.е. пытаемся найти угловые пиксели многоугольника). imregionalmax
затем используется для поиска локальных максимумов. Поскольку у вас могут быть кластеры размером более 1 пикселя с одной и той же угловой метрикой, я затем добавляю шум к максимумам и заново вычисляю, так что я получаю только 1 пиксель в каждой максимальной области. Каждая максимальная область затем помечается с помощью 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);
Затем отмеченные области расширяются (с использованием imdilate
) с помощью структурирующего элемента в форме диска (созданного с использованием strel
):
diskSize = 5;
dilatedImage = imdilate(labeledImage, strel('disk', diskSize));
subplot(2, 2, 2);
imshow(dilatedImage);
title('Dilated corner points');
Теперь, когда отмеченные угловые области расширены, они будут частично перекрывать исходный многоугольник. Области на краю многоугольника будут перекрываться примерно на 50%, тогда как области, расположенные на углу, будут перекрываться примерно на 25%. Функция regionprops
может использоваться для поиска областей перекрытия для каждой маркированной области, и 4 области, которые имеют наименьшее количество перекрытий, могут, таким образом, рассматриваться как истинные углы:
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');
И теперь мы можем получить пиксельные координаты углов, используя find
и 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');
А вот тест с ромбовидной областью: