GDAL库学习笔记(1):无缝拼接Google卫星图

开工之前要先了解一下瓦片地图,瓦片地图金字塔模型是一种多分辨率层次模型,从瓦片金字塔的底层到顶层,分辨率越来越低,但表示的地理范围不变。实现原理就是,首先确定地图服务平台所要提供的缩放级别的数量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,大功告成了,看看效果图吧。

时间: 2024-12-28 17:08:07

GDAL库学习笔记(1):无缝拼接Google卫星图的相关文章

0806------Linux网络编程----------Echo 网络库 学习笔记

1.Echo网络库的编写 1.1 Echo网络库1.0 1.1.1 Echo网络库 1.0 框架分析 a)class InetAddress: 主要用来定义一个struct sockaddr_in 结构(用自定义端口号初始化),并提供获取这个结构体成员如IP.Port等的接口: b)class Socket : 主要用来把一个普通的 sockfd 变为 listenfd(这里用一个sockfd初始化对象),提供bind .listen.accept 等接口. c)class TcpConnect

初探boost之timer库学习笔记

timer 用法 #include <boost/timer.hpp> #include <iostream> using namespace std; using namespace boost; int main() { timer t;//声明一个计时器对象,开始计时 cout<<"max:"<<t.elapsed_max()/3600<<"h"<<endl; //可度量的最大时间,以小时

初探boost之progress_display库学习笔记

progress_display 用途 progress_display可以在控制台上显示程序的执行进度,如果程序执行很耗费时间,那么它能提供一个友好的用户界 面,不至于让用户在等待中失去耐心,甚至怀疑程序的运行是否出了问题. 用法示例 #include <boost/progress.hpp> #include <iostream> #include <vector> using namespace std; using namespace boost; int ma

初探boost之smart_ptr库学习笔记

概述 Boost.smart_ptr库提供了六种智能指针,除了shared_ptr 和 weak_ptr 以外还包括 scoped_ptr .scoped_array . shared_array .intrusive_ptr .他们的速度与原始指针相差无几,都是异常安全的,而且对于类型T也仅有一个要 求:类型T的析构函数不能抛出异常. 使用时包含头文件: #include<boost/smart_ptr.hpp> scoped_ptr 用法: scoped_ptr 的构造函数接受一个类型为T

Java 8 流库学习笔记(一)

[core Java学习笔记]Java SE8 流库 Stream Library 从迭代到流 如果要计算一个文本中有多少长单词(字母>12). 迭代式: words = getlist();//虚构方法,获得一个List<String> long count = 0; for(String w:words) { if(w.length()>12) count++; } 流式: words = getlist();//虚构方法,获得一个List<String> long

python requests库学习笔记(上)

尊重博客园原创精神,请勿转载! requests库官方使用手册地址:http://www.python-requests.org/en/master/:中文使用手册地址:http://cn.python-requests.org/zh_CN/latest/: requests库作者Kenneth Reitz个人主页:https://www.kennethreitz.org/: requests库github地址:https://github.com/requests/requests: requ

Lufylegend库学习笔记1 绘图操作及鼠标事件

这几天对于网页前端有点兴趣,学习了一下Canvas的相关知识. 看到Lufylegend库之后,感觉很棒,有一种在写AS的感觉.今天入门第一站,写了一个画板. 是一个非常简易的画板,但是可以看到一些重要的思想. 代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Mouse Event</title&g

async-http-client开源库学习笔记(一)

0. 文前闲话 作为一个Android开发的大龄初学者,面对扑面而来的各种姿势的Android的开源组件,让人倍感窒息,难以应对.无奈为了养家糊口,虽然已近不惑,人老珠黄,也只能废寝忘食,逐个体位细细揣摩研究,不断以身实践,争取早日小成. 话说那是一个阳光明媚的下午,我坐在街口转角处优雅的网络会所里,品着一杯上好的Coca-Cola,研读着oschina客户端源码,身旁不时传来:"一起上搞死他,他没蓝了...!". 从火蚁(oschina客户端的开发者之一,向他们致敬)那里知道了asy

Python_sklearn机器学习库学习笔记(七)the perceptron(感知器)

一.感知器 感知器是Frank Rosenblatt在1957年就职于Cornell航空实验室时发明的,其灵感来自于对人脑的仿真,大脑是处理信息的神经元(neurons)细胞和链接神经元细胞进行信息传递的突触(synapses)构成. 一个神经元可以看做将一个或者多个输入处理成一个输出的计算单元.一个感知器函数类似于一个神经元:它接受一个或多个输入,处理 他们然后返回一个输出.神经元可以实时,错误驱动的学习,神经元可以通过一个训练样本不断的更新参数,而非一次使用整套的数据.实时学习可能有效的处理