瓦片切图工具gdal2tiles.py改写为纯c++版本
gdal2tiles.py是GDAL库中用于生成TMS瓦片的python代码,支持谷歌墨卡托EPSG:3857与经纬度EPSG:4326两种瓦片,输出png格式图像。
gdal2tiles.py More info at: http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification
http://wiki.osgeo.org/wiki/WMS_Tiling_Client_Recommendation
http://msdn.microsoft.com/en-us/library/bb259689.aspx
http://code.google.com/apis/maps/documentation/overlays.html#Google_Maps_Coordinates 为啥要改写为纯C++的?项目需求呗,一个系统需要集成一个瓦片切图的功能,但甲方又不希望安装复杂,每次都要配置python环境。
于是开始在网上找切图的开源资源。
使用AE来切图,直接调用GP服务,利用CreateMapServerCache 、ManageMapServerCacheTiles 和Geoprocessor 类来做。但代码中的结构都是必须先发布地图服务。
GeoServer中的GeoWebCache中间件也可切图,但也是需要先发布地图服务,并且切出的瓦片文件命名方式很恶心。http://www.geowebcache.org/ http://www.klokan.cz/projects/gdal2tiles/中核心代码不是开源的。。。。
总之最后决定改写gdal2tiles.py为纯C++代码了。
其实这种改写也不复杂,gdal2tiles.py中需要改写的代码不超过500行,并且调用的python接口gdal函数在c++接口函数里面肯定都有,并且改写后速度有可能更快。 下面是改写成C++的部分关键代码:
根据项目需要。仅支持裁切byte全色与多光谱经纬度投影图像为经纬度网格切片,初始0层为两个切片。生成jpg图像。
接口说明:
Hu2Tiles.exe+ +输入图像+ +结果路径+ +最小层数+ +最大层数+ +querysize
其中querysize数值能取256或者1024,前者最近邻采样,后者平均采样
例子:
echo %time%
Hu2Tiles.exe "D:\\GF3_MYN_QPSI_003841_E119.7_N33.2_20170503_L1A_HH_L10002340710.tiff" "D:\\huPyTiles" 2 14 256
echo %time%
pause
-------------------------------------------------------------------------------------
涉及到坐标转换的函数如下,可见python和C++的代码还是很相似的。
//////////////////////////////////////////////////////////////////////////////////////////////////
//def LonLatToPixels(self, lon, lat, zoom):
//"Converts lon/lat to pixel coordinates in given zoom of the EPSG:4326 pyramid"
//
//	res = self.resFact / 2**zoom
//	px = (180 + lon) / res
//	py = (90 + lat) / res
//	return px, py
void CHuGlobalGeodetic::LonLatToPixels(double lon,double lat,int zoom,double* pxy)
{
	double res = resFact / pow(2,(double)zoom);
	pxy[0] = (180.0 + lon) / res;
	pxy[1] = (90.0 + lat) / res;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//	def PixelsToTile(self, px, py):
//"Returns coordinates of the tile covering region in pixel coordinates"
//
//	tx = int( math.ceil( px / float(self.tileSize) ) - 1 )
//	ty = int( math.ceil( py / float(self.tileSize) ) - 1 )
//	return tx, ty
void CHuGlobalGeodetic::PixelsToTile(double px,double py,int* txy)
{
	txy[0] = int(ceil(px/256.0) - 1);
	txy[1] = int(ceil(py/256.0) - 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//	def LonLatToTile(self, lon, lat, zoom):
//"Returns the tile for zoom which covers given lon/lat coordinates"
//
//	px, py = self.LonLatToPixels( lon, lat, zoom)
//	return self.PixelsToTile(px,py)
void CHuGlobalGeodetic::LonLatToTile(double lon,double lat,int zoom,int* txy)
{
	double pxy[2] = {0.0,0.0};
	double res = resFact / pow(2,(double)zoom);
	pxy[0] = (180.0 + lon) / res;
	pxy[1] = (90.0 + lat) / res;
txy[0] = int(ceil(pxy[0]/256.0) - 1);
	txy[1] = int(ceil(pxy[1]/256.0) - 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//	def Resolution(self, zoom ):
//"Resolution (arc/pixel) for given zoom level (measured at Equator)"
//
//	return self.resFact / 2**zoom
//#return 180 / float( 1 << (8+zoom) )
double CHuGlobalGeodetic::Resolution(int zoom)
{
	return resFact / pow(2,(double)zoom);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//	def ZoomForPixelSize(self, pixelSize ):
//"Maximal scaledown zoom of the pyramid closest to the pixelSize."
//
//	for i in range(MAXZOOMLEVEL):
//     if pixelSize > self.Resolution(i):
//        if i!=0:
//           return i-1
//       else:
//           return 0 # We don't want to scale up
int CHuGlobalGeodetic::ZoomForPixelSize(double pixelSize)
{
	for (int i=0;i<32;i++)
	{
		if(pixelSize > Resolution(i))
		{
			if (i!=0)
			{
				return i-1;
			}
			else
			{
				return 0;
			}
		}
	}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//	def TileBounds(self, tx, ty, zoom):
//"Returns bounds of the given tile"
//	res = self.resFact / 2**zoom
//	return (
//	tx*self.tileSize*res - 180,
//	ty*self.tileSize*res - 90,
//	(tx+1)*self.tileSize*res - 180,
//	(ty+1)*self.tileSize*res - 90
//	)
void CHuGlobalGeodetic::TileBounds(int tx, int ty,int zoom, double* bound4)
{
	double res = resFact / pow(2,(double)zoom);
	bound4[0] = tx * 256.0 * res - 180.0;
	bound4[1] = ty * 256.0 * res - 90.0;
	bound4[2] = (tx+1) * 256.0 * res - 180.0;
	bound4[3] = (ty+1) * 256.0 * res - 90.0;
}
------------------------------------------------------------------------------------------
几个调用gdal函数接口的例子如下,总体上pthon的gdal接口函数更智能,换回C++的稍微麻烦点。。。
int CHu2Tiles::hu_scale_query_to_tile(GDALDataset *dsquery,GDALDataset *dstile)
{
int querysize = dsquery->GetRasterXSize();
	int	tilesize = dstile->GetRasterXSize();
	int tilebands = dstile->GetRasterCount();
if (resampling == "average")
	{
		if (tilebands == 1)
		{
			GDALRasterBandH *pRasterBand = new GDALRasterBandH();
			pRasterBand[0] = dstile->GetRasterBand(1);
			GDALRegenerateOverviews(dsquery->GetRasterBand(1),1,pRasterBand,"AVERAGE",NULL,NULL);
			//dstile->GetRasterBand(2)->SetNoDataValue(0);
		}
		if (tilebands == 3)
		{
			GDALRasterBandH *pRasterBand = new GDALRasterBandH();
			pRasterBand[0] = dstile->GetRasterBand(1);
			pRasterBand[1] = dstile->GetRasterBand(2);
			pRasterBand[2] = dstile->GetRasterBand(3);
			GDALRegenerateOverviews(dsquery->GetRasterBand(1),3,pRasterBand,"AVERAGE",NULL,NULL);
			//dstile->GetRasterBand(4)->SetNoDataValue(0);
		}
	} 
	else
	{
		double trans1[6] ={0.0,tilesize/(float)querysize,0.0,0.0,0.0,tilesize/(float)querysize};
		double trans2[6] ={0.0,1.0,0.0,0.0,0.0,1.0};
		dsquery->SetGeoTransform(trans1);
		dstile->SetGeoTransform(trans2);
		GDALReprojectImage(dsquery,NULL,dstile,NULL,GRA_Bilinear,0,0,NULL,NULL,NULL);
	}
return 0;
}
保存结果图像为jpg格式,就比png图像少处理了一个alpha波段,加上不输出KML文件,最终C++版本程序要比python的快些。实验图像从8秒缩减到4秒左右,更多分层的还没试。
目前只是改写代码,只能生成松散的瓦片图像,并且是单线程处理。后续可考虑修改为多线程。
比如这个:
https://github.com/commenthol/gdal2tiles-leaflet
里面有个:gdal2tiles-multiprocess.py
瓦片切图工具gdal2tiles.py改写为纯c++版本的更多相关文章
- 瓦片切图工具gdal2tiles.py改写为纯c++版本(二)
		python这么火,C++/C#的程序员都生存不下去了,为啥还要干把python转写成c++的这种反动的事? 项目需要呗... gdal2tiles.py文件中有两个类是计算全球墨卡托与WGS84两种 ... 
- 利用AE编写切图工具的一些探讨
		文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 这周利用晚上在家时间研究了下如何使用AE来开发切图工具.最初 ... 
- Cutterman - 最好用的切图工具
		Cutterman - 最好用的切图工具 http://www.cutterman.cn/zh/cutterman 
- AGS Server 10.1 切图工具
		在AGS Sever中很重要的功能就是地图缓存的制作,安装AGS Sever会在catalog中增加相关的工具箱,利用这些工具可以制作.删除.更新切片 一.Convert map server cac ... 
- PS切图工具
		缓存设置: 编辑-首选项-暂存盘 改完除了C盘之外的其他盘 单位设置: 编辑-首选项-单位与标尺 将单位修改成像素 PS预设: 工具 (窗口-工具) 标尺 (视图-标尺) 图层 (窗口-图层 ... 
- Assistor PS 切图工具的使用说明。
		一.如何运行Assistor PS 使用这个Assistor PS 软件有一个最最重要的条件,那就是:你要打开你的Photoshop (官方建议版本在CS 3以上) 下载-安装-运行. 运行成 ... 
- sketch最强切图工具Sketch Measure
		https://www.inpandora.com/sketch-measure.html https://www.jianshu.com/p/c11ae88e6b1d 
- WebGIS中矢量切图的初步研究
		文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 在GIS领域,金字塔技术一直是一个基础性技术,WMTS规范专 ... 
- 页面制作部分之PS切图
		页面制作部分之PS切图 <--本标签下,通过页面制作.页面架构.javascript程序设计.DOM编程艺术.产品前端架构五部分来分享总结笔记,总结笔记会陆续分享--> 网页设计在技术层面 ... 
随机推荐
- 使用LXD搭建Web网站
			欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由独木桥先生 发表于云+社区专栏 介绍 Linux的容器是Linux的一组进程,通过使用Linux内核功能与系统隔离.它是一个类似于虚拟 ... 
- Docker最全教程之使用 Visual Studio Code玩转Docker(二十)
			前言 VS Code是一个年轻的编辑器,但是确实是非常犀利.通过本篇,老司机带你使用VS Code玩转Docker——相信阅读本篇之后,无论是初学者还是老手,都可以非常方便的玩转Docker了!所谓是 ... 
- go.js remove 特定part
			我想删除一个实际上是背景的部分. 假设这是我添加part的方式 myDiagram.add( scope.gj(go.Part,//此Part未绑定到任何模型数据 { layerName:“Backg ... 
- Android-----Intent中通过startActivity(Intent intent )隐式启动新的Activity
			显式Intent我已经简单使用过了,也介绍过概念,现在来说一说隐式Intent: 隐式Intent:就是只在Intent中设置要进行的动作,可以用setAction()和setData()来填入要执行 ... 
- java多线程 生产者和消费者 lock
			package com.atguigu.thread.lock; import java.util.concurrent.locks.Condition; import java.util.concu ... 
- ASP.NET Aries 高级开发教程:Excel导入之代码编写(番外篇)
			前言: 以许框架提供的导入配置功能,已经能解决95%以上的导入情况,但有些情况总归还是得代码来解决. 本篇介绍与导入相关的代码. 1.前端追加导入时Post的参数: var grid = new AR ... 
- Netty、t-io、Voovan 框架比较
			以下是对三个框架在设计或者说是编码特点中选取的几个我比较关注的点的对比图: 首先我们对几个关键的概念进行一些解析,方便大家更好的理解上面表中的概念: NIO.AIO 的区别? 在这里我们来看一下两者最 ... 
- Go语言JSON数据相互转换
			目录 结构体转json map转json int转json slice转json json反序列化为结构体 json反序列化为map 结构体转json 结构体转json示例: package main ... 
- 用ASP.NET Core 2.0 建立规范的 REST API -- DELETE, UPDATE, PATCH 和 Log
			本文所需的一些预备知识可以看这里: http://www.cnblogs.com/cgzl/p/9010978.html 和 http://www.cnblogs.com/cgzl/p/9019314 ... 
- 【Keras篇】---利用keras改写VGG16经典模型在手写数字识别体中的应用
			一.前述 VGG16是由16层神经网络构成的经典模型,包括多层卷积,多层全连接层,一般我们改写的时候卷积层基本不动,全连接层从后面几层依次向前改写,因为先改参数较小的. 二.具体 1.因为本文中代码需 ... 
