我想计算“几乎”圆形(或椭圆形)物体的周长。我用两种方法:
第一种方法:
stats = regionprops('table',bw,'Centroid',...
'MajorAxisLength','MinorAxisLength','Perimeter');
perimeter_matlab=stats.Perimeter; %get the perimeter using matlab regionprops
第二种方法:
stats2 = regionprops(L,'Area','Centroid');
for k = 1:length(B)
% obtain (X,Y) boundary coordinates corresponding to label 'k'
boundary = B{k};
%get the perimeter by calculating the each pixel to pixel distance in boundary and add the discret distand together
delta_sq = diff(boundary).^2;
perimeter_pixel= sum(sqrt(sum(delta_sq,2)));
end
结果:
当我使用像900*600
像素这样的矩形对象时,它的周长应为900*2+598*2=2996
但是
perimeter_matlab=2935.7
为什么会出错?
perimeter_pixel = 2996
是正确的。
当我使用半径为50
像素(直径为101
)的圆圈时,其周长应为2*pi*50=314.1593
但是
perimeter_matlab=313.904
接近答案,但是
perimeter_pixel = 332.0488
为什么会出错?
Matlab如何计算perimeter
?
答案 0 :(得分:0)
我不知道MATLAB使用什么算法,但我可以告诉你为什么你的像素到像素距离过高估计了边界长度:因为图像是在规则网格上定义的,你通过将边界串在一起得到的多边形像素不像您尝试测量的连续域圆一样平滑。锯齿状导致多边形边界更长。补偿这种情况的算法往往采用圆形物体,因此最小化圆的误差。然后,该补偿导致低估正方形的边界长度。尽管如此,如果您使用任意角度测量正方形的边界,您最终会使用此补偿进行准确估算。与网格对齐的单个方块恰好是最糟糕的情况。
有关算法和选择的更深入解释,请参阅this blog post。
编辑:
现在我知道MATLAB使用的算法。有一个名为'PerimeterOld'
的属性,它实现了您也尝试过的天真方法。也就是说,它对于水平或垂直步骤使用权重1,对于对角步骤使用sqrt(2)
的权重。您正在使用的名为'Perimeter'
的属性具有您意外发现的行为,使用Vossepoel和Smeulders的算法,如我在上面给出的链接中所描述的那样:
% (Code copy-pasted from regionprops.m
% Copyright 1993-2014 The MathWorks, Inc.
% Provided here as "fair use" for instructional purposes, don't
% use this code, use the equivalent code on my blog instead.)
function perimeter = computePerimeterFromBoundary(B)
delta = diff(B).^2;
if(size(delta,1) > 1)
isCorner = any(diff([delta;delta(1,:)]),2); % Count corners.
isEven = any(~delta,2);
perimeter = sum(isEven)*0.980 + sum(~isEven)*1.406 - sum(isCorner)*0.091;
else
perimeter = 0; % if the number of pixels is 1 or less.
end