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++版本的更多相关文章

  1. 瓦片切图工具gdal2tiles.py改写为纯c++版本(二)

    python这么火,C++/C#的程序员都生存不下去了,为啥还要干把python转写成c++的这种反动的事? 项目需要呗... gdal2tiles.py文件中有两个类是计算全球墨卡托与WGS84两种 ...

  2. 利用AE编写切图工具的一些探讨

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 这周利用晚上在家时间研究了下如何使用AE来开发切图工具.最初 ...

  3. Cutterman - 最好用的切图工具

    Cutterman - 最好用的切图工具 http://www.cutterman.cn/zh/cutterman

  4. AGS Server 10.1 切图工具

    在AGS Sever中很重要的功能就是地图缓存的制作,安装AGS Sever会在catalog中增加相关的工具箱,利用这些工具可以制作.删除.更新切片 一.Convert map server cac ...

  5. PS切图工具

    缓存设置: 编辑-首选项-暂存盘 改完除了C盘之外的其他盘 单位设置: 编辑-首选项-单位与标尺 将单位修改成像素  PS预设: 工具   (窗口-工具) 标尺  (视图-标尺) 图层  (窗口-图层 ...

  6. Assistor PS 切图工具的使用说明。

    一.如何运行Assistor PS   使用这个Assistor PS 软件有一个最最重要的条件,那就是:你要打开你的Photoshop (官方建议版本在CS 3以上)   下载-安装-运行. 运行成 ...

  7. sketch最强切图工具Sketch Measure

    https://www.inpandora.com/sketch-measure.html https://www.jianshu.com/p/c11ae88e6b1d

  8. WebGIS中矢量切图的初步研究

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 在GIS领域,金字塔技术一直是一个基础性技术,WMTS规范专 ...

  9. 页面制作部分之PS切图

    页面制作部分之PS切图 <--本标签下,通过页面制作.页面架构.javascript程序设计.DOM编程艺术.产品前端架构五部分来分享总结笔记,总结笔记会陆续分享--> 网页设计在技术层面 ...

随机推荐

  1. 十问 JVM

    今天我们来讨论下 Java 虚拟机,通过一系列常见的问题来逐渐深入了解 JVM 创建对象过程,内存布局,类加载以及 GC 回收算法等机制. 十问 JVM 问题整理: Java虚拟机创建对象的过程 (使 ...

  2. .Net Core ORM选择之路,哪个才适合你

    因为老板的一句话公司项目需要迁移到.Net Core ,但是以前同事用的ORM不支持.Net Core 开发过程也遇到了各种坑,插入条数多了也特别的慢,导致系统体验比较差好多都改写Sql实现. 所以我 ...

  3. PoolEntry 参数讲解

    public abstract class PoolEntry<T, C> { private final String id; private final T route; //路由 p ...

  4. MongoDb 集群不可用后SECONDARY节点强制启动

    机房意外断电断网不得不预防,下面模拟测试某机房断电断网,B机房断电断网后A机房可正常提供服务,A机房断电断网后可能需要强制重启继续提供服务了,目前查看数据都还在,暂时没验证是否有数据丢失,小试了一把. ...

  5. 【原】无脑操作:TypeScript环境搭建

    概述:本文描述TypeScript环境搭建,以及基于VSCode的自动编译设置和调试设置.网络上很多相应文章的方式过时了或者无法试验成功. ------------------------------ ...

  6. SPI驱动调试感悟

    最近一段时间,在TX1平台的uboot中添加一个spi接口的液晶显示屏的驱动.本来以为是一项简单的工作,因为: 1.相同的驱动在其他平台的uboot中已经添加过了 2.内核中的驱动也是验证可用的,所以 ...

  7. bootstap初识之css

    老师的博客:https://www.cnblogs.com/liwenzhou/p/8214637.html bootstrap中文网:http://www.bootcss.com/ 官网:https ...

  8. requestAnimationFrame 知多少?

    在Web应用中,实现动画效果的方法比较多,JavaScript 中可以通过定时器 setTimeout 来实现,css3 可以使用 transition 和 animation 来实现,html5 中 ...

  9. Mysql8 安装过程及安装过程系列问题记录

    前言: 今天,想装个高版本一点的mysql试试,于是下载了一个mysql8的zip版本. 地址:https://dev.mysql.com/downloads/file/?id=484900 没想到安 ...

  10. .NET Core 3.0-preview3 发布

    .NET Core 3.0 Preview 3已经发布,框架和ASP.NET Core有许多有趣的更新.这是最重要的更新列表. 下载地址 :https://aka.ms/netcore3downloa ...