倒角距离变换(Chamfer Distance Transform)
图a,b为距离变换模板,设其值分别为a[1-5],b[5-9]。
图c为待处理的二维二值化图像,其中1代表目标区域,0代表背景区域。设其值为c[m][n]。
目标是求出目标区域中的每一个点距离背景区域的最小距离,即图d。
倒角距离变化算法思路如下:
(1)首先对原始二值矩阵进行放大得到c2,整体乘以一个膨胀因子p。p的大小会决定能算出的最大距离,即求出的最终距离矩阵中的数值上界,p越大距离越大。
(2)使用距离变换模板图a对二值化图像c2从左到右、从上到下的进行移动遍历。如果该点为0则跳过,为1则使用模板a[5]对应该点,计算该点的a[1-5]所对应的每一个点的像素值与a中每一个点的模板值之和。
如果该点为矩阵的四周上的点,即模板上部分点超出了原始矩阵的边界,则设置这些点的像素值为极大值1*p。不过为了优化算法效率,实际计算时可以仅对矩阵的非边界区域进行操作,即前向时不计算第1行,第1列和最后1列。这样做的最终效果是:只有地图的左右两列未被计算,并不影响我们在局部路径规划中的使用。
最终该点保留的值为这5个和值的最小值,得到矩阵f1具体过程以下图为例:
(3)使用模板b对前向遍历的结果矩阵f1从右到左、从下到上的进行移动遍历。操作与上一步相同,得到矩阵f2。同上,不计算矩阵的最后1行,第1列和最后1列。
(4)f2即为最终矩阵,除以3之后形成图d,效果图如下:
原始二值地图
距离地图
%对二值地图进行倒角距离变换,输出一张距离地图。
inf_factor=1200;%膨胀因子,代表像素值的上线,极大值
raw_a=zeros(1000,1000);
for i=300:700
for j=200:300
raw_a(i,j)=1;
end
end
for i=300:700
for j=700:800
raw_a(i,j)=1;
end
end
raw_a=double(~raw_a)*inf_factor;
figure('NumberTitle', 'off', 'Name', '原始二值地图');
imagesc(raw_a);
colormap(flipud(gray));
h=size(raw_a,1);
w=size(raw_a,2);
a_transpro=raw_a;
tic
for i=2:h%前向遍历过程,从上到下、从左到右
for j=2:w-1
tmp=a_transpro(i,j);%初值取目标像素点初始值
if a_transpro(i,j)%只操作前景点,即为1的点
tmp=min(a_transpro(i-1,j-1)+4,tmp);
tmp=min(a_transpro(i-1,j)+3,tmp);
tmp=min(a_transpro(i-1,j+1)+4,tmp);
tmp=min(a_transpro(i,j-1)+3,tmp);
a_transpro(i,j)=tmp;%最终保留几个和值的最小值作为该点距离值
end
end
end
for i=h-1:-1:1%从下到上、从右到左
for j=w-1:-1:2
tmp=a_transpro(i,j);
if a_transpro(i,j)
tmp=min(a_transpro(i+1,j+1)+4,tmp);
tmp=min(a_transpro(i+1,j)+3,tmp);
tmp=min(a_transpro(i+1,j-1)+4,tmp);
tmp=min(a_transpro(i,j+1)+3,tmp);
a_transpro(i,j)=tmp;
end
end
end
a_final=a_transpro/3;%遍历结束后除以3作为最终结果
t=toc
figure('NumberTitle', 'off', 'Name', '距离地图');
imagesc(a_final);
colormap(flipud(gray));