Google Earth Engine城市水体提取

大家都知道城市水体提取相比较于山区,丘陵的地区,肯定是比较难的,为什么呢,因为城市水体有很多高层建筑导致的阴影,这个就非常复杂了,而且现在很多高分影像只有可见光和近红外波段,那么我们如何准确提取城市水体呢?

Remoe Sensing2018年刊发了一篇城市水体高分影像自动提取算法(Two-Step Urban Water Index (TSUWI): A New Technique for High-Resolution Mapping of Urban SurfaceWater [J]Remote Sensing,2018),初步看来,效果还行,在高分二号上面效果不错,我再想,如果对于开源的哨兵、Landsat如何?这些是中等分辨率影像,能做到吗?

话不多说,利用GEE,直接编码,实验结果如下(以2018年10月的北京某景Sentinel2影像为例):

(a) 这是原始影像

(b) 这是城市水体指数

(c) 这是城市阴影指数

(d) 这是城市水体提取结果,蓝色为水体

其中城市水体指数和城市阴影指数计算公式如下所示:

我把最终成果发布成了APPengine(https://wang749195.users.earthengine.app/view/urbanwaterextraction),大家可以直接在web上看,总的来说,实验结果还是不错的,去掉了阴影现象,这篇文章出自中科院遥感所,在此申明,值得一读,后续我会发布C++软件版本,Matlab版本,以及Python版本。我个人的开发思路是,首先用GEE实现,如果GEE不好实现,就用matlab或者python实现第一遍,效果可以,能工程应用,立马就用GDAL+C++打包成工程源代码,我感觉这样会节省时间,且不会造成时间浪费。

接着上面讲,我们用c++来实现一遍,使用GDAL读写影像,先把这两个函数写上来:

/*栅格影像读取,返回数据指针
* imgPath:图像位置
* 返回float类型的数据指针
*/
void readImage(char *imgpath, imgData *IMG, int bandindex) { GDALDataset *img = (GDALDataset*)GDALOpen(imgpath, GA_ReadOnly);
if (img != NULL) { int imgWidth = img->GetRasterXSize(); //图像宽度,特别注意:对应matlab中的行
int imgHeight = img->GetRasterYSize(); //图像高度,特别注意:对应matlab中的列
int bandNum = img->GetRasterCount(); //波段数 IMG->imgH = imgHeight;
IMG->imgW = imgWidth; GDALRasterBand *poBand; poBand = img->GetRasterBand(bandindex); //灰度一个波段 img->GetGeoTransform(IMG->adfGeoTransform); // 变换参数 int size = imgWidth*imgHeight;
IMG->pData = new float[size]; //分配缓冲区空间 //读取
poBand->RasterIO(GF_Read, , , imgWidth, imgHeight, IMG->pData,
imgWidth, imgHeight, GDT_Float32, , ); GDALClose(img); // 释放内存
}
} /*写出栅格影像
* imgPath:输出影像位置
* adfGeoTransform:变换参数
* IMG:导出的影像数组
*/
void writeImage(char *imgPath, float *Img, int nImgSizeX, int nImgSizeY, int nBandCount, double *adfGeoTransform) {
GDALDataset *poDataset2; //待创建的GDAL数据集
GDALDriver *poDriver; //驱动,用于创建新的文件 //创建新文件
poDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); //获取格式类型
char **papszMetadata = poDriver->GetMetadata(); //特别注意,数据类型要与后面的写出类型要保持一致
poDataset2 = poDriver->Create(imgPath, nImgSizeX, nImgSizeY, nBandCount, GDT_Float32, papszMetadata);
//坐标赋值
poDataset2->SetGeoTransform(adfGeoTransform); //将图像数据写入新图像中
poDataset2->RasterIO(GF_Write, , , nImgSizeX, nImgSizeY,
Img, nImgSizeX, nImgSizeY, GDT_Float32, nBandCount, , , , ); GDALClose(poDataset2);
delete poDriver;
}

然后就是我们的USI,UWI计算公式,贴上来:

// 计算UWI指数
void UWI_cal(float *rband, float *gband, float *nirband,float *UWI,int width,int length) {
int Length = width*length; for (int i = ; i < Length; i++) {
UWI[i] = (gband[i] - 1.1*rband[i] - 5.2*nirband[i] + 0.4) /
abs(gband[i] - 1.1*rband[i] - 5.2*(nirband[i]));
}
} // 计算USI指数
void USI_cal(float *rband, float *gband, float *bband, float *nirband, float *USI, int width, int length) {
int Length = width*length; for (int i = ; i < Length; i++) {
USI[i] = 0.25*gband[i] / rband[i] - 0.57*nirband[i] /
gband[i] - 0.83*bband[i] / gband[i] + 1.0; }
}

然后就是我们的影像数据结构:

/*可见光与近红外波段数据结构
*/
struct imgData {
float *pData; int imgH;
int imgW;
double adfGeoTransform[];
};

last but not least,就是我们的main函数:

int main()
{
//必须先注册一个!
GDALAllRegister();
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); char *ImgPath = "C:\\Users\\Administrator\\Desktop\\UrbanWater\\SentinelImg.tif"; // 读取蓝波段
imgData *B = new imgData;
readImage(ImgPath, B, ); // 读取绿波段
imgData *G = new imgData;
readImage(ImgPath, G, ); // 读取红波段
imgData *R = new imgData;
readImage(ImgPath, R, ); // 读取近红外波段
imgData *NIR = new imgData;
readImage(ImgPath, NIR, ); printf("读取影像成功!\n"); int width = B->imgW;
int height = B->imgH; float *USI = new float[width*height];
float *UWI = new float[width*height]; UWI_cal(R->pData, G->pData, NIR->pData, UWI, width, height);
USI_cal(R->pData, G->pData, B->pData, NIR->pData, USI, width, height); float T1 = -0.1;
float T2 = -0.2;
float *UrbanWater = new float[width*height];
UrbanWaterExtraction(T1, T2, UWI, USI, UrbanWater, width, height); char *savePath = "C:\\Users\\Administrator\\Desktop\\UrbanWater\\urbanwater.tif";
writeImage(savePath, UrbanWater, width, height, , R->adfGeoTransform);
printf("提取水体成功!\n"); // 清空内存
delete []NIR->pData;
delete []R->pData;
delete []G->pData;
delete []B->pData;
delete []UrbanWater;
delete []USI;
delete []UWI;
delete NIR, R, G, B;
system("pause"); }

还是上一张c++搞出来的城市水体图吧:

可以看到,GEE与c++效果几乎一样,但是GEE的栅格渲染,还是非常值得国产软件学习!

(打个小广告,本文兼职软件开发,qq1044625113)。

Google Earth Engine城市水体提取的更多相关文章

  1. 基于google earth engine 云计算平台的全国水体变化研究

    第一个博客密码忘记了,今天才来开通第二个博客,时间已经过去两年了,三年的硕士生涯,真的是感慨良多,最有收获的一段时光,莫过于在实验室一个人敲着代码了,研三来得到中科院深圳先进院,在这里开始了新的研究生 ...

  2. Google Earth Engine学习资源分享

    最近在学习Google Earth Engine的使用,发现这个平台确实是一个非常好用.非常强大的平台.在GEE官网上找到了一些中文的学习资料,现在搬运过来分享给大家共同学习.教程分为两个部分 教程一 ...

  3. Google earth engine 绘制图像间散点图

    这段代码实现了在Google earth engine中绘制图像/波段间的散点图,得到相关关系.适用于探究数据间的相关性,进行数据的交叉验证. 代码来源于官方帮助:https://developers ...

  4. Google Earth Engine 中的位运算

    Google Earth Engine中的位运算 按位运算是编程中一个难点,同时也是在我们后续处理影像数据,尤其要使用影像自带的波段比如QA波段经常会用到的一个东西.通过按位运算我们可以筛选出我们想要 ...

  5. Google earth engine 中的投影、重采样、尺度

    本文主要翻译自下述GEE官方帮助 https://developers.google.com/earth-engine/guides/scale https://developers.google.c ...

  6. 基于google earth engine的中等分辨率全国水质反演

    我写博客的工作不像论文,假大空,我们直接上干货,之所以取一个这么大的名字,当然是我们能做到的... 不多说,我们对全国水体进行水质参数反演,不用MODIS,太粗,我们直接用哨兵,这样就可以直接做到大型 ...

  7. 使用google earth engine根据NDWI(归一化水指数)提取水体信息

    交流合作请联系: ab000c@163.com

  8. 基于Google Earth Engine的全国地表温度反演

    国内研究landsat8温度反演的人员很多,但是现有算法一般都是一景为例子,进行开展. 这有一个局限性,当研究的尺度很大时,就需要比较大的运算量了,例如全省温度,全国温度,全球温度,当然大家可能会说, ...

  9. 节能减排到底如何----google earth engine 告诉你!!

    (First,再次严谨说明,本人成果未经允许,切勿发表到相关学术期刊,如果有技术交流,qq1044625113,顺便打个广告,兼职GEE开发,欢迎联系!) 终于过了严寒的冬天,2017年的冬天中国南方 ...

随机推荐

  1. Information Centric Networking Based Service Centric Networking

    A method implemented by a network device residing in a service domain, wherein the network device co ...

  2. Android TV开发总结(七)构建一个TV app中的剧集列表控件

    原文:Android TV开发总结(七)构建一个TV app中的剧集列表控件 版权声明:我已委托"维权骑士"(rightknights.com)为我的文章进行维权行动.转载务必转载 ...

  3. JScript运行批处理命令的做法

    作者:朱金灿 来源:http://blog.csdn.net/clever101 有时需要在JScript调用批处理命令,因为这样可以将二者的优势结合起来.今天发现调用WScript.Shell对象的 ...

  4. C#同步SQL Server数据库Schema

    C#同步SQL Server数据库Schema 1. 先写一个sql加工类: using System; using System.Collections.Generic; using System. ...

  5. Google CFO 辞职信

    Google CFO 辞职信   After nearly 7 years as CFO, I will be retiring from Google to spend more time with ...

  6. jquery 访问cookie

    <!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...

  7. Inno Setup制作最简单的安装程序

    目标就是[把exe程序放到制定目录,然后自动把工程需要的dll放到system32目录下,自动注册注册表.] 实现上述需求,用Inno Setup可以非常方便快捷实现. 安装Inno Setup. 点 ...

  8. C#高性能大容量SOCKET并发(九):断点续传

    原文:C#高性能大容量SOCKET并发(九):断点续传 上传断点续传 断点续传主要是用在上传或下载文件,一般做法是开始上传的时候,服务器返回上次已经上传的大小,如果上传完成,则返回-1:下载开始的时候 ...

  9. Android零基础入门第85节:Fragment使用起来非常简单

    Fragment创建完成后并不能单独使用,还需要将Fragment加载到Activity中,在Activity中添加Fragment的方式有两种:静态加载和动态加载,接下来分别进行学习. 一.静态加载 ...

  10. jQuery.form的使用方法

    首先需要引入jquery.form.js 之后即可使用 jquery.form.js的中文API网址http://www.vaikan.com/docs/jquery.form.plugin/jque ...