一、链码
链码(又称为freeman code)是一种通过带有给定方向的单位长度的线段序列来描述轮廓边界的方法,常被用来在图像处理、计算机图形学、模式识别等领域中表示曲线和区域边界。在二维图像中,链码可以表示为一系列的方向码,每个方向码代表轮廓上相邻两点之间的方向。常见的链码表示方法有基于4-邻接(如图a)和8-邻接(如图b)的,其中8-邻接链码能够更准确地描述轮廓的边缘信息,因为它考虑了像素点周围的所有8个方向。
(a)4方向链码的方向数 (b)4方向链码的方向数
如(c)图所示是一个4方向链码,假如从黑点沿着逆时针开始,其链码为3 0 0 3 0 1 1 2 1 2 3 2,如果从红点沿着逆时针开始,则其链码为2 1 2 3 2 3 0 0 3 0 1 1。
(c) ( d )
从上面可以看出,同一条边界沿着不同的起点其链码不同。因此,边界的链码依赖于起始点。为了确定链码所表示的曲线边界在图像中的位置,并能由链码准确地重建曲线边界,则需要标出起点的坐标。但在实际应用中,由于起点和终点重合,当用链码来描述闭合边界时,通常不关心起点的具体位置,起点位置的变化只引起链码的循环位移。为了解决上述问题,需要将链码进行归一化处理。
给定一个从任意点开始产生的边界链码,把它看成一个由各个方向数构成的自然数。将这些方向数依照一个方向(逆时针或顺时针)循环以使它们所构成的自然数的值最小,将转化后所对应的链码起点作为这个边界的归一化链码的起点。因此,图(C)和图(d)研逆时针的归一化链码为0 0 3 0 1 1 2 1 2 3 2 3。用链码表示给定目标的边界时,如果目标平移,链码不会发生变化,但如果目标旋转则链码会发生变化。
二、基于MATLAB的彩色图像的边界链码提取
clear all; %清除所有变量
close all; %关闭图形窗口
clc; %清屏
% 读取图像并转换为二值图像
img = imread('FC0.png'); % 替换为你的图像文件路径
grayImg = rgb2gray(img); % 如果原图是彩色的,则转换为灰度图
bwImg = imbinarize(grayImg); % 使用默认阈值进行二值化
% 找到边界点(这里直接使用bwboundaries,但注意它返回的是轮廓,不是链码)
[B,L] = bwboundaries(bwImg, 'noholes');
% 初始化链码列表
chainCodes = {};
% 遍历每个轮廓
for k = 1:length(B)
boundary = B{k};
% 初始化链码字符串(或数组),这里使用字符串方便查看
chainCodeStr = '';
% 遍历边界上的每个点(除了最后一个点,因为我们需要前一个点来确定方向)
for i = 1:size(boundary, 1) - 1
p1 = boundary(i, :);
p2 = boundary(i+1, :);
% 计算方向(这里简化了方向判断,只考虑水平和垂直)
% 在实际应用中,应使用更精确的方向计算
dx = p2(2) - p1(2);
dy = p2(1) - p1(1);
% 根据dx和dy的值确定方向(这里仅作为示例,实际中需要更详细的判断)
if dx > 0 && dy == 0
chainCodeStr = [chainCodeStr '0']; % 东
elseif dx == 0 && dy > 0
chainCodeStr = [chainCodeStr '2']; % 南
elseif dx < 0 && dy == 0
chainCodeStr = [chainCodeStr '4']; % 西
elseif dx == 0 && dy < 0
chainCodeStr = [chainCodeStr '6']; % 北
% 其他方向(东南、西南、西北、东北)需要更复杂的判断
else
% 如果dx和dy都不为0,则可能是对角线方向,需要更详细的判断
% 这里简单处理为不添加链码(或添加特定标记表示复杂情况)
chainCodeStr = [chainCodeStr '-']; % 示例中的特殊标记
end
end
% 将当前轮廓的链码添加到链码列表中
chainCodes{end+1} = chainCodeStr;
end
% 显示链码
disp('图像边界链码是')
disp(chainCodes);