BW = poly2mask(x, y, m, n)计算一个   关注区域(ROI)面具的二元区域,   BW,从ROI多边形,表示   由矢量x和y。 BW的大小   为m乘n。

     

poly2mask设置像素BW   是多边形内部(X,Y)到1   并设置多边形之外的像素   0

<强>问题: 鉴于这样的凸四边形的二元掩模BW,这将是确定的四个角落的最有效的方法是什么?

如,

“实施例”

<强>最好的解决方案到目前为止: 使用edge找到边界线,霍夫变换,找到4行的边缘图像中,然后找到这4条线的交点,或使用一个角点检测边缘图像上。看似复杂,我不禁感到有一个简单的解决方案在那里。

顺便说一句,convhull并不总是返回4点(也许有人可以建议qhull选项,以防止):返回沿边缘的几个点以及

修改 荷银的回答似乎很优雅和高效。但是,可能有多个“角落”在每一个真正的角落,因为山峰不是唯一的。我可以基于集群他们的θ和平均“角落”围绕一个真正的角落,但主要问题是使用order(1:10)的。

足够10考虑到所有的角落或在真正的角落将这种排除“角落”?

有帮助吗?

解决方案

这是有点类似于 @AndyL 建议。不过我用极坐标,而不是切边界签名。

请注意,我通过提取边缘,得到了边界,然后将其转换为签名启动。最后,我们发现,是从最远的重心边界上的点,这些点构成中发现的角落。 (可替换地,我们也可以检测峰值在拐角处的签名)。

下面是一个完整的实现:

I = imread('oxyjj.png');
if ndims(I)==3
    I = rgb2gray(I);
end
subplot(221), imshow(I), title('org')

%%# Process Image
%# edge detection
BW = edge(I, 'sobel');
subplot(222), imshow(BW), title('edge')

%# dilation-erosion
se = strel('disk', 2);
BW = imdilate(BW,se);
BW = imerode(BW,se);
subplot(223), imshow(BW), title('dilation-erosion')

%# fill holes
BW = imfill(BW, 'holes');
subplot(224), imshow(BW), title('fill')

%# get boundary
B = bwboundaries(BW, 8, 'noholes');
B = B{1};

%%# boudary signature
%# convert boundary from cartesian to ploar coordinates
objB = bsxfun(@minus, B, mean(B));
[theta, rho] = cart2pol(objB(:,2), objB(:,1));

%# find corners
%#corners = find( diff(diff(rho)>0) < 0 );     %# find peaks
[~,order] = sort(rho, 'descend');
corners = order(1:10);

%# plot boundary signature + corners
figure, plot(theta, rho, '.'), hold on
plot(theta(corners), rho(corners), 'ro'), hold off
xlim([-pi pi]), title('Boundary Signature'), xlabel('\theta'), ylabel('\rho')

%# plot image + corners
figure, imshow(BW), hold on
plot(B(corners,2), B(corners,1), 's', 'MarkerSize',10, 'MarkerFaceColor','r')
hold off, title('Corners')

“screenshot1” “screenshot2”


修改 在回答雅各的评论,我要解释一下,我第一次尝试找到使用第一/第二衍生签名的峰值,但最终采取最远的N-点。 10只是一个特设的价值,就难以一概而论(我试过服用4相同弯道数量,但它并没有涵盖所有的人)。我认为他们汇聚到删除重复的想法是值得研究的。

据我所见,与第一方法的问题是,如果你不考虑rho考虑情节θ,你会得到不同的形状(不一样的峰值),由于速度由我们跟踪边界是不同的,依赖于曲率。如果我们能弄清楚如何的正常化的这个效果,我们可以得到利用衍生品更准确的结果。

其他提示

如果你有图像处理工具箱时,有一个被调用的函数的 cornermetric 能够实现Harris角检测器或施和Tomasi的的最小特征值的方法。由于图像处理工具箱(MATLAB版本R2008b)。6.2版本此功能已经存在

使用这个功能,我想出了从其他答案稍有不同的方法。下面的解决方案是基于这样的思想:在每个“真”角落点为中心的圆形区域将通过比集中于一个错误的角点,实际上是在边缘的圆形区域较小量重叠多边形。该解决方案还可以处理,其中在相同的角检测到多个点的情况下...

在第一个步骤是加载数据:

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');

“在这里输入的图像描述”

和这里用金刚石形区域的测试:

“在这里输入的图像描述”

我喜欢由与边界工作来解决这个问题,因为它减少了这种从2D问题一维问题。

从图像处理工具包使用bwtraceboundary()提取的边界上的点的列表。然后边界转换成一系列切向量(有许多方法可以做到这一点,一个办法是subrtact的 沿着从ith点的边界i+deltath点)。一旦你有载体列表,以相邻向量的点积。四点与最小的点产品是您的角落!

如果你希望你的算法与顶点的abritrary数量的多边形工作,那么只需搜索属于中间点积低于标准偏差的一定数量的点产品。

我决定使用 Harris角检测(这里的一个更正式的说明),以获得角落。这可以实现如下:

%% Constants
Window = 3;
Sigma = 2;
K = 0.05;
nCorners = 4;

%% Derivative masks
dx = [-1 0 1; -1 0 1; -1 0 1];
dy = dx';   %SO code color fix '

%% Find the image gradient
% Mask is the binary image of the quadrilateral
Ix = conv2(double(Mask),dx,'same');   
Iy = conv2(double(Mask),dy,'same');

%% Use a gaussian windowing function and compute the rest
Gaussian = fspecial('gaussian',Window,Sigma);
Ix2 = conv2(Ix.^2,  Gaussian, 'same');  
Iy2 = conv2(Iy.^2,  Gaussian, 'same');
Ixy = conv2(Ix.*Iy, Gaussian, 'same');    

%% Find the corners
CornerStrength = (Ix2.*Iy2 - Ixy.^2) - K*(Ix2 + Iy2).^2;
[val ind] = sort(CornerStrength(:),'descend');    
[Ci Cj] = ind2sub(size(CornerStrength),ind(1:nCorners));

%% Display
imshow(Mask,[]);
hold on;
plot(Cj,Ci,'r*');

下面,与由于其平滑的强度变化的高斯窗函数的多个角部的问题。下面,是用hot颜色表的拐角的放大版本。

“角落”

下面是使用Ruby的示例和 HornetsEye 。基本上,该程序创建的量化索贝尔梯度方向的直方图找到主导方向。如果发现四种主要的取向,线装有与相邻线之间的交叉点被假定为投影矩形的角。

#!/usr/bin/env ruby
require 'hornetseye'
include Hornetseye
Q = 36
img = MultiArray.load_ubyte 'http://imgur.com/oxyjj.png'
dx, dy = 8, 6
box = [ dx ... 688, dy ... 473 ]
crop = img[ *box ]
crop.show
s0, s1 = crop.sobel( 0 ), crop.sobel( 1 )
mag = Math.sqrt s0 ** 2 + s1 ** 2
mag.normalise.show
arg = Math.atan2 s1, s0
msk = mag >= 500
arg_q = ( ( arg.mask( msk ) / Math::PI + 1 ) * Q / 2 ).to_int % Q
hist = arg_q.hist_weighted Q, mag.mask( msk )
segments = ( hist >= hist.max / 4 ).components
lines = arg_q.map segments
lines.unmask( msk ).normalise.show
if segments.max == 4
  pos = MultiArray.scomplex *crop.shape
  pos.real = MultiArray.int( *crop.shape ).indgen! % crop.shape[0]
  pos.imag = MultiArray.int( *crop.shape ).indgen! / crop.shape[0]
  weights = lines.hist( 5 ).major 1.0
  centre = lines.hist_weighted( 5, pos.mask( msk ) ) / weights
  vector = pos.mask( msk ) - lines.map( centre )
  orientation = lines.hist_weighted( 5, vector ** 2 ) ** 0.5
  corner = Sequence[ *( 0 ... 4 ).collect do |i|
    i1, i2 = i + 1, ( i + 1 ) % 4 + 1
    l1, a1, l2, a2 = centre[i1], orientation[i1], centre[i2], orientation[i2]
    ( l1 * a1.conj * a2 - l2 * a1 * a2.conj -
      l1.conj * a1 * a2 + l2.conj * a1 * a2 ) /
      ( a1.conj * a2 - a1 * a2.conj )
  end ] 
  result = MultiArray.ubytergb( *img.shape ).fill! 128
  result[ *box ] = crop
  corner.to_a.each do |c|
    result[ c.real.to_i + dx - 1 .. c.real.to_i + dx + 1,
            c.imag.to_i + dy - 1 .. c.imag.to_i + dy + 1 ] = RGB 255, 0, 0
  end
  result.show
end

“图像的角部的估计位置”

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top