获取链码有两个步骤:追踪边界和将坐标编码为链码。后一步很琐碎,我不会详细介绍。我认为这个问题的目的就是追寻边界。
通常所追踪的是形成边界的对象像素(即具有至少一个背景邻居)。重要的是这按顺序发生,仅列出这些像素是不够的。但请注意,这种边界描述是有偏差的:真实对象大于通过在对象边界处连接像素中心而形成的多边形。周长计算需要考虑到这一点(如您链接的博客文章中所述)。
这段代码稍微改编自这篇博文 https://www.crisluengo.net/archives/324. 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 像素厚部分将被访问两次,以完成边界追踪。