开工之前要先了解一下瓦片地图,瓦片地图金字塔模型是一种多分辨率层次模型,从瓦片金字塔的底层到顶层,分辨率越来越低,但表示的地理范围不变。实现原理就是,首先确定地图服务平台所要提供的缩放级别的数量N,把缩放级别最低、地图比例尺最大的地图图片作为金字塔的底层,即第0层,并对其进行分块,从地图图片的左上角开始,从左至右、从上到下进行切割,分割成相同大小(比如256x256像素)的正方形地图瓦片,形成第0层瓦片矩阵;在第O层地图图片的基础上,按每2x2像素合成为一个像素的方法生成第1层地图图片,并对其进行分块,分割成与下一层相同大小的正方形地图瓦片,形成第1层瓦片矩阵;采用同样的方法生成第2层瓦片矩阵;…;如此下去,直到第N一1层,构成整个瓦片金字塔。

  在Google地图中,地图数据由大量的正方形图片组成。共有2级缩放比例,每个地图图片都有坐标值,由X和Y值构成。比例因子zoom取值范围是(0-22)。操作地图滑竿显示更大比例尺地图时,图片的数量发生裂变。两种模式在请求及响应的速度方面有明显的差异,基于地图瓦片服务框架的响应速度要快于传统的WebGIS,同时对地图服务器的负载也相应小一些。

     现在可以开工,首先准备好瓦片地图,如果是用来学习研究的话,我们可以通过一些第三方工具(当然自己写一个也可以)从谷歌地图抓取瓦片地图存放到本地,例如以C:\googlemas\satelite\x\y.jpg的格式存放,其中x,y,z分别代瓦片所在的列、行、缩放等级。

 

有了这些图我们开始拼接了,关于gdal库的介绍的文章很多了,现在我主要是介绍如何用C#来拼接谷歌地图,废话不多说了,直接上代码:

void SaveBitmapBuffered(Dataset src, Dataset dst, int x, int y)
{
    if (src.RasterCount < 3) {
        System.Environment.Exit(-1);
    }

    // Get the GDAL Band objects from the Dataset
    Band redBand = src.GetRasterBand(1);
    Band greenBand = src.GetRasterBand(2);
    Band blueBand = src.GetRasterBand(3);

    // Get the width and height of the raster
    int width = redBand.XSize;
    int height = redBand.YSize;

    byte[] r = new byte[width * height];
    byte[] g = new byte[width * height];
    byte[] b = new byte[width * height];

    redBand.ReadRaster(0, 0, width, height, r, width, height, 0, 0);
    greenBand.ReadRaster(0, 0, width, height, g, width, height, 0, 0);
    blueBand.ReadRaster(0, 0, width, height, b, width, height, 0, 0);

    Band wrb = dst.GetRasterBand(1);
    wrb.WriteRaster(x * width, y * height, width, height, r, width, height, 0, 0);
    Band wgb = dst.GetRasterBand(2);
    wgb.WriteRaster(x * width, y * height, width, height, g, width, height, 0, 0);
    Band wbb = dst.GetRasterBand(3);
    wbb.WriteRaster(x * width, y * height, width, height, b, width, height, 0, 0);
}

/// <summary>
/// 拼接瓦片
/// </summary>
/// <param name="tilesBounds"></param>
/// <param name="tilePath"></param>
/// <param name="outPutFileName"></param>
public void CombineTiles(TilesBounds tilesBounds, string tilePath, string outPutFileName)
{
    if (File.Exists(outPutFileName))
    {
        File.Delete(outPutFileName);
    }
    int imageWidth = 256 * (tilesBounds.maxCol - tilesBounds.minCol + 1);
    int imageHeight = 256 * (tilesBounds.maxRow - tilesBounds.minRow + 1);

    //Register driver(s). 
    Gdal.AllRegister();
    Driver driver = Gdal.GetDriverByName("GTiff");
    Dataset destDataset = driver.Create(outPutFileName, imageWidth, imageHeight, 3, DataType.GDT_Byte, null);

for (int col = tilesBounds.minCol; col <= tilesBounds.maxCol; col++) { for (int row = tilesBounds.minRow; row <= tilesBounds.maxRow; row++) { try { string sourceFileName = tilePath + tilesBounds.zoomLevel.ToString() + "\\" + col.ToString() + "\\" + row.ToString() + ".jpg"; if (File.Exists(sourceFileName)) { Dataset sourceDataset = Gdal.Open(sourceFileName, Access.GA_ReadOnly); if (sourceDataset != null) { SaveBitmapBuffered(sourceDataset, destDataset, col - tilesBounds.minCol, row - tilesBounds.minRow); } } } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } } destDataset.Dispose(); } //调用 TilesBounds tilesBounds = new TilesBounds(); tilesBounds.minCol = 107901; tilesBounds.maxCol = 107926; tilesBounds.minRow = 49652; tilesBounds.maxRow = 49668; tilesBounds.zoomLevel = 17; string outPutFileName = "c:\\北京卫星图" + tilesBounds.zoomLevel.ToString() + ".tif"; string tilePath = "C:\\googlemaps\\\satelite\\"; CombineTiles(tilesBounds, tilePath, outPutFileName);

ok,大功告成了,看看效果图吧。

 

 

posted on 2012-07-27 21:10  MaptileDownloader  阅读(13412)  评论(13编辑  收藏  举报