【图像处理】数字图像中的距离变换算法

说在前面

  • 编译环境:vs2017
  • opencv版本:4.0.1
  • 参考:《图像处理、分析与机器视觉(第4版)》

概念

  • 数字图像

    对于一个图像函数 f ( x , y ) f(x,y) ,若其定义域以及值域都是离散的,那么称之为数字的;
    通常,通过采样将连续图像进行数字化。
    在这里插入图片描述
    一个连续图像在采样点处被数字化;采样点之间构成的关系为栅格。
  • 距离

    • 定义
      满足以下条件的函数:
      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(\bold p,\bold q)\geq 0,当且仅当\bold p=\bold q时,D(\bold p,\bold q)=0\\ D(\bold p,\bold q)=D(\bold q,\bold p)\\ D(\bold p,\bold r)\leq D(\bold p,\bold q)+D(\bold q,\bold r)
    • 欧式距离
      D E [ ( i , j ) , ( h , k ) ] = ( i h ) 2 + ( j k ) 2 D_E[(i,j),(h,k)]=\sqrt{(i-h)^2+(j-k)^2}
      在这里插入图片描述
    • 城市街区距离
      只允许横向以及纵向的移动
      在这里插入图片描述
      D 4 [ ( i , j ) , ( h , k ) ] = i h + j k D_4[(i,j),(h,k)]=|i-h|+|j-k|
      在这里插入图片描述
    • 棋盘距离
      允许横向、纵向以及对角线上的移动
      在这里插入图片描述
      D 8 [ ( i , j ) , ( h , k ) ] = m a x { i h + j k } D_8[(i,j),(h,k)]=max\{|i-h|+|j-k|\}
      在这里插入图片描述
  • 距离变换算法

    • 按照一种距离度量D,D是D4或者D8,对大小为MxN的图像的一个子集S进行距离变换,建立一个MxN的数组F并作初始化:子集S中的元素置为0,其他位置为无穷。
    • 按行遍历图像,从上到下,从左到右。对于上方和左边的邻接像素,设
      F ( p ) = m i n [ F ( p ) , D ( p , q ) + F ( q ) ] F(\bold p)=min[F(\bold p), D(p,q)+F(q)]
      在这里插入图片描述
    • 按行遍历图像,从下到上,从右到左。对于下方和右边的邻接像素,设
      F ( p ) = m i n [ F ( p ) , D ( p , q ) + F ( q ) ] F(\bold p)=min[F(\bold p), D(p,q)+F(q)]
      在这里插入图片描述
    • 数组F中得到的是子集S的斜切

Code

  • c++实现

    并未处理图像,仅用于展示算法;
    时间复杂度: O ( n 2 ) O(n^2)
    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    /*
    @{func} 判断i,j是否在范围内
    */
    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;
    }
    /*
    @{param: i j} 点位置
    @{param: rows cols} 图像大小
    @{param: f} 目标数组
    @{func} 处理上以及左边的近邻像素
    */
    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]);
    }
    /*
    @{param: i j} 点位置
    @{param: rows cols} 图像大小
    @{param: f} 目标数组
    @{func} 处理下以及右边的近邻像素
    */
    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]);
    }
    
    /*
    @{param:src} 源图像
    @{param:f}   目标数组
    */
    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);
    }
    
    int main()
    {
    	vector<vector<int>> src = { 
    	{0,1,1,0,0,0,1,0 },
    	{0,1,0,0,0,0,0,1 },
    	{0,1,0,0,0,0,0,0 },
    	{0,1,0,0,0,0,0,0 }
    	};
    	int rows = src.size();
    	int cols = src[0].size();
    	vector<vector<int>> f(rows, vector<int>(cols, 0));
    
    	cout << "SRC:" << endl;
    	for (int i = 0; i < rows; ++i)
    	{
    		for (int j = 0; j < cols; ++j)
    			cout << src[i][j] << " ";
    		cout << endl;
    	}
    
    	DistanceTransformD4(src, f);
    
    	cout << "\nResult:" << endl;
    	for (int i = 0; i < rows; ++i)
    	{
    		for (int j = 0; j < cols; ++j)
    			cout << f[i][j] << " ";
    		cout << endl;
    	}
    
    	return 0;
    }
    
    在这里插入图片描述
  • opencv

    void cv::distanceTransform	(	
    InputArray 	src,
    OutputArray 	dst,
    OutputArray 	labels,
    int 	distanceType,
    int 	maskSize,
    int 	labelType = DIST_LABEL_CCOMP 
    )	
    
    栗子?
    在这里插入图片描述

应用

  • 移动机器人领域的路径规划以及障碍躲避
  • 图像中寻找最近特征,骨架抽取
  • 待补充
发布了106 篇原创文章 · 获赞 41 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_33446100/article/details/102801878