距离
定义
满足以下函数条件
D(p,q)>=0,当且仅当p=q时D(p,q)=0;
D(p,q)=D(q,p)
D(p,r)<=D(p,q)+D(q,r)
欧式距离
D[(i,j),(k,h)]=((i-k)^2+(j-h)^2)^(1/2);

城市街区距离
只允许横向以及纵向的移动
D[(i,j),(k,h)]=|i-k|+|j-h|;

棋盘距离
允许横向、纵向以及对角线上的移动
D[(i,j),(k,h)]=max{|i-k|,|j-h|}
算法实现
步骤
1.按照一种距离度量D,D是D4或D8,对大小为M*N的图像的一个子集S计算距离变换,建立一个M*N的数组F并作初始化:子集S中元素置为0,
其他置为无穷。
2.按行遍历图像,从上到下,从左到右。对于上方和左面的邻接像素设F(p)=min[F(p),D(p,q)+F(q)]。
3.按行遍历图像,从下到上,从右到左。对于下方和右面的邻接像素设F(p)=min[F(p),D(p,q)+F(q)]。
4.数组F中得到的是子集S的斜切。
具体函数
初始化函数
void DistanceTransformD4(vector<vector<int>> &src, vector<vector<int>> &f)
{
int cols = src[0].size();
int rows = src.size();
//初始化
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
if (src[i][j] == 1)
f[i][j] = 0;
else
f[i][j] = INT_MAX - 2;//简单的防止溢出
//按行遍历图像,从上到下,从左到右
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
D4AL(i, j, rows, cols, f);
//按行遍历图像,从下到上,从右到左
for (int i = rows - 1; i >= 0; --i)
for (int j = cols - 1; j >= 0; --j)
D4BR(i, j, rows, cols, f);
}
左变换函数
void D4AL(int i,int j, int rows, int cols, vector<vector<int>> &f)
{
//上
if (InArea(i - 1, j, rows, cols))
f[i][j] = min(f[i][j], 1 + f[i - 1][j]);
//左上
if (InArea(i - 1, j - 1, rows, cols))
f[i][j] = min(f[i][j], 2 + f[i - 1][j - 1]);
//左
if (InArea(i, j - 1, rows, cols))
f[i][j] = min(f[i][j], 1 + f[i][j - 1]);
//左下
if (InArea(i + 1, j - 1, rows, cols))
f[i][j] = min(f[i][j], 2 + f[i + 1][j - 1]);
}
右变换函数
void D4BR(int i, int j, int rows, int cols, vector<vector<int>> &f)
{
//下
if (InArea(i + 1, j, rows, cols))
f[i][j] = min(f[i][j], 1 + f[i + 1][j]);
//右下
if (InArea(i + 1, j + 1, rows, cols))
f[i][j] = min(f[i][j], 2 + f[i + 1][j + 1]);
//右
if (InArea(i, j + 1, rows, cols))
f[i][j] = min(f[i][j], 1 + f[i][j + 1]);
//右上
if (InArea(i - 1, j + 1, rows, cols))
f[i][j] = min(f[i][j], 2 + f[i - 1][j + 1]);
}
判断是否出界函数
bool InArea(int i, int j, int rows, int cols)
{
if (i<0 || i>=rows)
return false;
if (j<0 || j>=cols)
return false;
return true;
}