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. Python爬虫入门教程 61-100 写个爬虫碰到反爬了,动手破坏它!

    python3爬虫遇到了反爬 当你兴冲冲的打开一个网页,发现里面的资源好棒,能批量下载就好了,然后感谢写个爬虫down一下,结果,一顿操作之后,发现网站竟然有反爬措施,尴尬了. 接下来的几篇文章,我们 ...

  2. TensorFlow从1到2(六)结构化数据预处理和心脏病预测

    结构化数据的预处理 前面所展示的一些示例已经很让人兴奋.但从总体看,数据类型还是比较单一的,比如图片,比如文本. 这个单一并非指数据的类型单一,而是指数据组成的每一部分,在模型中对于结果预测的影响基本 ...

  3. C#爬虫使用代理刷csdn文章浏览量

    昨天写了一篇关于“c#批量抓取免费代理并验证有效性”的文章,接着昨天的目标继续完成吧,最终实现的目的就是刷新csdn文章的浏览量(实际上很简单,之前博客园的文章也是可以使用代理ip来刷的,后来不行了) ...

  4. Python调用ansible API系列(五)综合使用

    如何把动态生成资产信息.执行playbook以及自定义结果结合起来用呢? #!/usr/bin/env python # -*- coding: utf-8 -*- """ ...

  5. 拼多多大数据开发工程师SQL实战解析

    不久前,裸考国内知名电商平台拼多多的大数据岗位在线笔试,问答题(写SQL)被虐的很惨,完了下来默默学习一波.顺便借此机会复习一下SQL语句的用法. 本文主要涉及到的SQL知识点包括CREATE创建数据 ...

  6. fab 菜单实现—圆形、半圆、扇形、直线、射线

    前段时间记录一下fab 菜单实现之前传-钟表表盘,今天终于弄正文了. 本文基于上篇文章的布局方式和位置计算,并参考35 Cool Floating Action Button Animations(h ...

  7. Postman 安装

    前言 安装前的准备: 1.Chrome 浏览器的扩展插件来进行的安装,并非单独应用程序. 2.电脑上已经安装了 Chrome 浏览器 3.本文章适用操作系统  window7 一,非官方安装 个人不建 ...

  8. 20190429 - 如何访问 macOS 的 httpd、mysql 等服务

    问题:在局域网,通过其它机器访问 macOS 上的服务时,提示拒绝. 解决:将 macOS 防火墙 80.3306 端口打开. macOS 内置防火墙,也许开启了防火墙.Icefloor 是一个老牌的 ...

  9. MYSQL如何计算两个日期间隔天数

    如何透过MYSQL自带函数计算给定的两个日期的间隔天数   有两个途径可获得   1.利用TO_DAYS函数   select to_days(now()) - to_days('20120512') ...

  10. 知乎专栏开放性api

    概述 这是我在工作中扒的知乎专栏的开放性api,记录下来供以后开发时参考,相信对其他人也有用. 参考资料: zhihu库 zhihu-oauth库 开放性api 其中hemingke是专栏名字,可以换 ...