GIS算法基础(八)基于距离变换的栅格骨架提取算法

原文链接: http://www.cnblogs.com/zhongHW/p/11047015.html

一、为什么需要骨架提取

简单来说就是用于细化栅格便于栅格数据转换为矢量数据

栅格格式向矢量格式转换是提取相同编号的栅格集合表示的边界,栅格点转换成矢量点,很简单,在坐标系确定的情况下通过解析式可以直接转换。而线与面在转换成矢量的时候,本质上都是在提取边界或中轴线,因此在栅格中提取中轴线就与栅格的细化的关系密不可分,这是因为线状栅格数据一般具有粗度且线条本身往往呈现粗细。栅格数据需要细化,以提取中轴线。这是因为:

①中轴线是栅格数据曲线的标准化存储形式

②实现细化是将栅格曲线矢量化的前提

③在有些算法中可以提高计算精度

GIS算法基础(八)基于距离变换的栅格骨架提取算法_第1张图片

二、距离变换法提取骨架

距离变换图

距离变换图也是一种栅格图像,其中,每个像元值存储了它到栅格图上相邻物体的最近距离。这个距离的量度:可以是曼哈顿距离,棋盘距离,或者欧式距离。这三个距离关系在GIS中很常用。算法实现如下:

		/**
		 * 
		 * @param disType 距离类型
		 * @param s1 像元1
		 * @param s2 像元2
		 * @return
		 */
		private double calculateDis(DisType disType,Pixel s1,Pixel s2) {
			double dis = 0;
			switch (disType) {
			case Euclidean:
				dis = Math.sqrt(Math.pow(s1.getRow()-s2.getRow(), 2)+Math.pow(s1.getColumn()-s2.getColumn(), 2))*size;
				break;
			case CityBlock:
				dis = Math.abs(s1.getRow()-s2.getRow())+Math.abs(s1.getColumn()-s2.getColumn())*size;
				break;
			case ChessBoard:
				dis = Math.max(Math.abs(s1.getRow()-s2.getRow()), Math.abs(s1.getColumn()-s2.getColumn()))*size;
				break;
			default:
				dis = Math.sqrt(Math.pow(s1.getRow()-s2.getRow(), 2)+Math.pow(s1.getColumn()-s2.getColumn(), 2))*size;
				break;
			}
			return dis;
		}

 

 

基于距离变换法提取骨架算法思想:

对内部点集i到非内部点集e(孤立点与边界点)求最小距离,实际上就是求目标点到最近背景点的距离(背景点-值为0的像元  目标点-值为1的像元),求出距离后 对距离进行分类即可得骨架图

 

基于距离变换法提取骨架算法步骤:

①将栅格图像进行初始二值化(背景点设为0,目标点设为1)

②将栅格图像进行分类,把栅格分为内部点,边界点,孤立点。

③求每一个内部点到非内部点的距离,距离值赋给栅格值

④对栅格图像进行二值化(距离大于1的栅格值设为1,小于等于1的设为0)

③重复②③④,终止条件为“若下一次栅格图像二值化结果全部为0”

 

如何分类:

在步骤②中,如何把栅格分为内部点,边界点,孤立点?

以中心像素的四邻域为例,

1、如果中心像素为目标像素(值为1)且四邻域都为目标像素(值为1),则该点为内部点。

2、如果该中心像素为目标像素,四邻域为背景像素(值为0),则该中心点为孤立点。

3、其他情况则为边界点

GIS算法基础(八)基于距离变换的栅格骨架提取算法_第2张图片

分类代码实现

		//判断是边界点,内部点,孤立点
		//前提:栅格已经二值化
		public void setNeighbourhood() {
			internalPoints = new ArrayList<>();
			borderPoints = new ArrayList<>();
			for(int i=0;i

测试结果:

GIS算法基础(八)基于距离变换的栅格骨架提取算法_第3张图片

B代表边界点,I代表内部点,孤立点未进行渲染

 

基于距离变换法提取骨架算法实现

我使用了3*3模板的快速距离变换。

按照从上到下,从左到右的顺序,遍历3x3的栅格图像

GIS算法基础(八)基于距离变换的栅格骨架提取算法_第4张图片

但是有个问题是:如果在遍历过程中,碰到了栅格的边界怎么办,所以我写了对应的解决办法,即先确定快速距离变换遍历的范围,在开始遍历快速距离变换。

代码如下:

		/**
		 * 骨架图算法(距离变换法搜索中轴线)
		 * 对内部点集i到边界点集e求最小距离
		 * 实际上就是求目标点到最近背景点的距离
		 * 背景点-值为0的像元  目标点-值为1的像元
		 * 求出距离后 对距离进行分类即可得骨架图
		 */
		public void getMinDis(DisType disType) {
			//快速距离模板计算
			//从左至右,从上到下,顺时针寻找周围是否有边界点
			//如果有,则加入计算
			//如果没有,则扩大搜寻范围,最大范围到数组越界
			//最后得出最小距离
			//当前圈层数
			if(borderPoints==null && internalPoints==null) {
				setNeighbourhood();
			}
			for(Pixel i:internalPoints) {
				List disList = new ArrayList<>();
				//搜索范围
				int cicleNum = 1;
				//上下左右搜寻边界
				int up,down,left,right;
				int upLimit,downLimt,leftLimit,rightLimit;
				upLimit = 1;
				downLimt = ROW;
				leftLimit = 1;
				rightLimit = COLUMN;
				//确定遍历范围,防止边界溢出
				for(int curCir=0;curCirdownLimt) {
							down = downLimt;
						}
					} catch (Exception e) {
						// TODO: handle exception
						down = i.getRow();
					}
					
					try {
						left = i.getColumn()-cicleNum;
						if(leftrightLimit) {
							right=rightLimit;
						}
					} catch (Exception e) {
						// TODO: handle exception
						right = i.getColumn();
					}
					//记录栅格周边是否有非内部点,没有的话则圈数+1
					boolean flag = false;
					//从最左最上开始遍历,遍历顺序从左至右,从上到下
					for(int row=up;row

测试结果: 

原始数据:

GIS算法基础(八)基于距离变换的栅格骨架提取算法_第5张图片

距离变换细化一次:

GIS算法基础(八)基于距离变换的栅格骨架提取算法_第6张图片

距离变换细化2次

GIS算法基础(八)基于距离变换的栅格骨架提取算法_第7张图片

。。。

n次

GIS算法基础(八)基于距离变换的栅格骨架提取算法_第8张图片

 

 

转载于:https://www.cnblogs.com/zhongHW/p/11047015.html

你可能感兴趣的:(GIS算法基础(八)基于距离变换的栅格骨架提取算法)