栅格数据矢量化(附有完整代码)

        栅格一矢量数据转换是数据转换的一种方法,即矢量与栅格两种数据形式之间的转换技术。空间数据表示的两种方法各有优缺点和适用场合,因此需要根据使用目的进行栅格一矢量数据的转换。

矢量数据向栅格数据的转换一般比较方便;对于点、线目标,由其所在的栅格行、列数表示,对于面状目标,则需判定落人该面积内的像元.通常栅格(像元)尺寸均大于原来坐标表示的分辨率,所以若将栅格化数据再反转回去,则不可能达到原来矢量数据的精度.将矢量数据转化为栅格数据,主要用于空间分析、多边形叠置等。

        栅格数据矢量化较为复杂,如果由一幅扫描的数字化地图来建立矢量数据库,则需要经过数字图象处理,如边缘增强、细化、二值化、特征提取及模式识别才能获得矢量数据。人们通常将多色地图分色后逐个元素(如等高线地貌、水系、道路网、地物、符号与注记等)加以识别和提取。如果将数字影像矢量化,则需要事先做好重采样、图象处理、影像匹配和影像理解等过程,才能将影像上的语义和非语义信息提取出来,并形成矢量形式的数据。

说明:栅格数据矢量化流程参考:GIS中栅格数据转换矢量数据算法 | 麻辣GIS

一、栅格数据矢量化流程

1、二值化

        由于扫描后的图像是以不同灰度级存储的,为了进行栅格数据矢量化的转换,需压缩为两级(0和1),称为二值化。

 2、二值图像预处理

        对于扫描输入的图幅,由于原稿不干净等原因,总是会出现一些飞白、污点、线划边缘凹凸不平等。

3、细化骨架化

        所谓细化就是将二值图像象元阵列逐步剥除轮廓边缘的点,使之成为线划宽度只有一个象元的骨架图形。细化后的图形骨架既保留了原图形的绝大部分特征,又便于下一步的跟踪处理。

细化的基本过程是:

  1. 确定需细化的象元集合;
  2. 移去不是骨架的象元;
  3. 重复,直到仅剩骨架象元;

如果是对扫描后的地图图像进行细化处理,应符合下列基本要求:

  1. 保持原线划的连续性;
  2. 线宽只为一个象元;
  3. 细划后的骨架应是原线划的中心线;
  4. 保持图形的原有特征;

 4、追踪

        细化后的二值图像形成了骨架图,追踪就是把骨架转换为矢量图形的坐标序列。其基本步骤为:

  1. 从左向右,从上向下搜索线划起始点,并记下坐标;
  2. 朝该点的8个方向追踪点,若没有,则本条线的追踪结束,转(1)进行下条线的追踪;否则记下坐标;
  3. 把搜索点移到新取的点上,转(2);

注意的是,已追踪点应作标记,防止重复追踪。

5、拓扑化 

        为了进拓扑化,需找出线的端点和结点,以及孤立点。

  1. 孤立点:8邻城中没有为1的象元。如图(1);
  2. 端点:8邻城中只有一个为1的象元。如图(2);
  3. 结点:8邻城中有三个或三个以上为1的象元。如图(3);

 二、栅格数据矢量化实验

1、栅格数据矢量化代码

说明:由于代码有点多,如果全部贴上去的话会造成博客有些卡顿(上一篇博客就是放太多代码造成打开时卡顿),所以下面三个源文件都是只放了部分代码,如果需要完整工程,见底部链接!!!

 (1)myVector.h

//命名空间只在头文件中包含即可,否则易出错
using namespace std;
using namespace cv;


class myVector
{
public:

	myVector();
	~myVector();

	//定义结构体,和类的作用类似
	struct result
	{
		QVector<QVector<Point2d> > roads;	//Point2d二维数据点类型,用于存放坐标
		QVector<double> width;
		QString ImageFilePath;
		int rows;
		int cols;
	};

public:

	QVector<result> roadInformation;	//保存矢量化后的数据结果,包括新旧影像

	//************************** 道路细化 **************************//

	//对输入图像道路进行细化//
	void imageThin(Mat& src, Mat& dst);

	//道路细化查表法//
	Mat img_bone(Mat& mat);

	//查表法//
	Mat lookUpTable(Mat& mat, int lut[]);

	//************************** 道路矢量化 **************************//

	//利用栅格道路数据创建矢量化道路数据,切割大小为deltaSize
	void  createVectorFromFile(QString inputFileName, int deltaSize);

	//利用栅格道路数据创建矢量化道路数据,不切割//
	void createVectorFromFile(QString inputFileName, QString outputFilePath);

	//道路矢量化//
	void createVector(Mat& binSrc, Mat& mix_src, Mat& endPoint, Mat& nodePoint, int index, bool cut, int startX, int startY);

	//简化矢量道路数据//
	void simplifyVector(int index);

	//简化矢量道路数据//
	QVector<Point2d> simplifyVector(QVector<Point2d> vector, int threshold);

	//输出矢量道路数据//
	void outputBinaryResult(int index, QString outputFilePath, QString str);

 (2)myVector.cpp

//************************** 道路矢量化 **************************//

//利用栅格道路数据创建矢量化道路数据,不切割//
void myVector::createVectorFromFile(QString inputFileName, QString outputFilePath)
{
	clock_t start, finish;    //clock_t 是一个长整型数据类型,是一种用于保存时间的数据类型

	start = clock();		  //返回值是该程序从启动到clock()函数调用占用CPU的时间,创建矢量化道路的起始时间

	double tim;

	Mat src_img, dst_img, imgbone, src_imgBool, imgbone_bool, imgnode_bool, img_endpoint_bool;

	//判断导入的数据是否存在,参数 0 是指imread按单通道的方式读入图像,即灰白图像
	if ((src_img = imread(inputFileName.toStdString(), 0)).empty())
	{
		cout << "load image error!";
		return;
	}

	result Result;							//result是自定义的类

	Result.ImageFilePath = inputFileName;
	Result.rows = src_img.rows;
	Result.cols = src_img.cols;

	roadInformation.append(Result);			//添加当前影像数据

	/******************** 道路细化 ********************/

	qDebug() << "开始细化..." << endl;

	double thin_start = (double)getTickCount();

	//高斯滤波是一种线性滤波器,能够有效的抑制噪声、平滑图像
	GaussianBlur(src_img, src_img, Size(7, 7), 0, 0);

	//输入图像细化
	imageThin(src_img, src_imgBool);

	threshold(src_imgBool, src_imgBool, 0, 255, THRESH_OTSU);

	imgbone = img_bone(src_imgBool);

	double thin_end = ((double)getTickCount() - thin_start) / getTickFrequency();

	qDebug() << "细化道路数据使用时间:" << thin_end << "s" << endl;

	qDebug() << "细化结束!" << endl;

	//去掉噪,例如过滤很小或很大像素值的图像点
	//threshold(src_img, src_imgBool, 0, 255, THRESH_OTSU);

	//Mat imgbone = img_bone(src_imgBool);

	imwrite(".\\image_save\\roadThin.png", imgbone * 255);

	/******************** 道路矢量化 ********************/

	qDebug() << "开始矢量化..." << endl;

	double change_detection_start = (double)getTickCount();

	threshold(imgbone, imgbone_bool, 0, 255, THRESH_BINARY);

	Mat nodePoint = road_node(imgbone);					//获取弧段连接点
	Mat endPoint = road_endpoint(imgbone);				//获取弧段端点
	Mat mix_node = LineBreak(imgbone_bool, nodePoint);	//对弧段进行打断

	//矢量化
	createVector(src_imgBool, mix_node, endPoint, nodePoint, roadInformation.size() - 1, false, 0, 0);

	double vector_end = ((double)getTickCount() - change_detection_start) / getTickFrequency();

	qDebug() << "矢量化道路数据所用时间:" << vector_end << endl;
}

 (3)main.cpp

#include<iostream>

#include"myVector.h"

// 注:main.cpp 文件中不能再添加命名空间,否则会调用自定义成员函数时找不到标识符

int main()
{
	myVector roadThinAndVector;

	roadThinAndVector.createVectorFromFile("..\\testImage\\labels.png", "roadThin.png");  //旧时相影像栅格数据矢量化
	
	//简化矢量道路数据,也即一些预处理,如:平滑等
	roadThinAndVector.simplifyVector(0);		//旧影像

	//输出矢量道路数据简化后的道路数据
	roadThinAndVector.outputBinaryResult(0, "roadVector.png", ".\\old_vector_result.txt");

	qDebug() << "矢量化结束!" << endl;

	system("pause");
	return 0;
}

2、栅格数据矢量化结果

(1)输入二值图

(2) 细化、矢量化结果

 

说明:左图是细化结果,右图是矢量化结果; 

(3)配置说明

vs2019 + opencv4.4.0 + Qt5.12.5 + gdal2.3.2 + Debug x64

vs2019、opencv4.4.0 和 Qt5.12.5 的配置过程比较简单这里就不过多阐述了;

gdal2.3.2 的配置流程见:https://blog.csdn.net/weixin_47156401/article/details/120648970?spm=1001.2014.3001.5502

上述环境配置完成后使用该工程的过程中,若出现以下问题:

如果出现无法打开 Qt 源文件,解决方案见:https://blog.csdn.net/weixin_47156401/article/details/120626400?spm=1001.2014.3001.5502

说明:上述环境配置、问题解决方案都是通过亲测验证,真实有效!!!

代码工程文件中包含二值图细化、矢量化和矢量化简化等工程,且代码注释非常详细,由上述给出的部分代码也可以看出,在使用的过程中如有疑问,可留言!

工程链接:栅格数据矢量化代码实现-C/C++文档类资源-CSDN下载

  • 15
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论
以下是Python根据矢量数据裁剪栅格数据的代码示例: ```python # 导入需要的库 import gdal import ogr import osr # 定义输入矢量数据路径和栅格数据路径 vector_path = 'path/to/vector.shp' raster_path = 'path/to/raster.tif' # 打开矢量数据文件并获取几何信息 vector_ds = ogr.Open(vector_path) layer = vector_ds.GetLayer() feature = layer.GetFeature(0) geometry = feature.GetGeometryRef() # 打开栅格数据文件并获取地理参考和变换信息 raster_ds = gdal.Open(raster_path) geo_transform = raster_ds.GetGeoTransform() proj = osr.SpatialReference() proj.ImportFromWkt(raster_ds.GetProjection()) # 将矢量数据的几何信息转换为栅格数据坐标系下的坐标 minX, maxX, minY, maxY = layer.GetExtent() ulX, ulY = gdal.ApplyGeoTransform(geo_transform, minX, maxY) lrX, lrY = gdal.ApplyGeoTransform(geo_transform, maxX, minY) # 计算裁剪后的栅格数据的大小和地理参考 x_pixels = int((lrX - ulX) / geo_transform[1]) y_pixels = int((lrY - ulY) / geo_transform[5]) clip_proj = raster_ds.GetProjection() # 创建输出栅格数据文件 driver = gdal.GetDriverByName('GTiff') clip_raster_path = 'path/to/clip_raster.tif' clip_raster_ds = driver.Create(clip_raster_path, x_pixels, y_pixels, 1, gdal.GDT_Float32) clip_raster_ds.SetGeoTransform((ulX, geo_transform[1], 0, ulY, 0, geo_transform[5])) clip_raster_ds.SetProjection(clip_proj) # 裁剪栅格数据 gdal.Warp(clip_raster_ds, raster_ds, cutlineDSName=vector_path, cropToCutline=True) # 关闭文件 clip_raster_ds = None raster_ds = None vector_ds = None ``` 请注意,此代码假定输入矢量数据为多边形,并且只裁剪了栅格数据的第一个波段。如果需要裁剪多个波段,则需要使用适当的循环来处理每个波段,并将结果保存到多波段栅格数据中。此外,代码还需要更多的错误检查和边缘情况的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据库内核

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值