我发现该函数使用chain codes对形状的边界进行编码,然后使用以下公式计算周长this way:
perimeter = sum(isEven)*0.980 + sum(~isEven)*1.406 - sum(isCorner)*0.091;
然而,我不知道在某些特殊情况下如何计算这个链代码。
考虑以下示例(MATLAB的周长为10.0150):
1 1 1 1 1
1 1 0 0 1
MATLAB如何定义/计算连接到左侧2x2方格的一条像素宽线周围的周边?
更确切地说:
如果我使用字母表示非零边框像素(在此示例中,所有1都是边框):
a d e f g
b c h
链码可以从a
开始。如果我们顺时针计算它,它会继续c
,e
,f
...这意味着它无法返回a
,否则就必须去在同一个字母上两次(如果有1px宽线连接到其他1px宽线等,则甚至超过两次)。
答案 0 :(得分:2)
获取链码有两个步骤:跟踪边界并将坐标编码为链码。后一步是微不足道的,我不会详细介绍。追踪边界是我认为这个问题的关键。
通常跟踪的是形成边界的对象像素(即,具有至少一个背景邻居)。重要的是,这种情况按顺序发生,仅列出这些像素是不够的。但请注意,边界的这种描述是有偏见的:真实对象大于通过连接对象边界处像素中心形成的多边形。外围计算需要考虑到这一点(正如您链接的博客文章中所讨论的那样)。
此代码略微改编自this blog post。 img
是一个逻辑数组:
% Data for chain code encoding:
directions = [ 1, 0
1,-1
0,-1
-1,-1
-1, 0
-1, 1
0, 1
1, 1];
% Get a start point, any pixel on the boundary is OK:
indx = find(img,1)-1; % 0-based indexing is easier
% Image sizes
sz = [size(img,2),size(img,1)]; % x,y sizes, rather than y,x sizes
% Coordinates for start point
start = [floor(indx/sz(2)),0];
start(2) = indx-(start(1)*sz(2));
% Initialize algorithm
cc = []; % The chain code
coord = start; % Coordinates of the current pixel
dir = 1; % The starting direction
% Loop till full boundary is traced
while 1
newcoord = coord + directions(dir+1,:);
if all(newcoord>=0) && all(newcoord<sz) ...
&& img(newcoord(2)+1,newcoord(1)+1)
cc = [cc,dir];
coord = newcoord;
dir = mod(dir+2,8);
else
dir = mod(dir-1,8);
end
if all(coord==start) && dir==1 % back to starting situation
break;
end
end
正如你在这里看到的那样,算法从一个随机像素开始,并选择一个方向来绕过。然后它通过在给定方向上找到下一个邻居来跟随边界。链接的博客文章详细说明了如何找到该邻居。简而言之,您在当前方向上查看具有背景邻居的第一个相邻对象像素。鉴于我们来自的当前位置和方向,可以证明特定方向上的邻居将是背景像素。沿着当前点顺时针(或逆时针,选择一个)方向,从该背景像素开始,第一个对象像素将保证是边界像素。我们将其添加到列表中并继续。
当我们到达开始位置和方向时,算法终止。因此,对象的1像素厚部分将被访问两次,以完成边界轨迹。