Google Earth Engine城市水体提取
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城市水体提取的更多相关文章
- 基于google earth engine 云计算平台的全国水体变化研究
第一个博客密码忘记了,今天才来开通第二个博客,时间已经过去两年了,三年的硕士生涯,真的是感慨良多,最有收获的一段时光,莫过于在实验室一个人敲着代码了,研三来得到中科院深圳先进院,在这里开始了新的研究生 ...
- Google Earth Engine学习资源分享
最近在学习Google Earth Engine的使用,发现这个平台确实是一个非常好用.非常强大的平台.在GEE官网上找到了一些中文的学习资料,现在搬运过来分享给大家共同学习.教程分为两个部分 教程一 ...
- Google earth engine 绘制图像间散点图
这段代码实现了在Google earth engine中绘制图像/波段间的散点图,得到相关关系.适用于探究数据间的相关性,进行数据的交叉验证. 代码来源于官方帮助:https://developers ...
- Google Earth Engine 中的位运算
Google Earth Engine中的位运算 按位运算是编程中一个难点,同时也是在我们后续处理影像数据,尤其要使用影像自带的波段比如QA波段经常会用到的一个东西.通过按位运算我们可以筛选出我们想要 ...
- Google earth engine 中的投影、重采样、尺度
本文主要翻译自下述GEE官方帮助 https://developers.google.com/earth-engine/guides/scale https://developers.google.c ...
- 基于google earth engine的中等分辨率全国水质反演
我写博客的工作不像论文,假大空,我们直接上干货,之所以取一个这么大的名字,当然是我们能做到的... 不多说,我们对全国水体进行水质参数反演,不用MODIS,太粗,我们直接用哨兵,这样就可以直接做到大型 ...
- 使用google earth engine根据NDWI(归一化水指数)提取水体信息
交流合作请联系: ab000c@163.com
- 基于Google Earth Engine的全国地表温度反演
国内研究landsat8温度反演的人员很多,但是现有算法一般都是一景为例子,进行开展. 这有一个局限性,当研究的尺度很大时,就需要比较大的运算量了,例如全省温度,全国温度,全球温度,当然大家可能会说, ...
- 节能减排到底如何----google earth engine 告诉你!!
(First,再次严谨说明,本人成果未经允许,切勿发表到相关学术期刊,如果有技术交流,qq1044625113,顺便打个广告,兼职GEE开发,欢迎联系!) 终于过了严寒的冬天,2017年的冬天中国南方 ...
随机推荐
- JSON格式的服务接口
电商接口 京东获取单个商品价格接口: http://p.3.cn/prices/mgets?skuIds=J_商品ID&type=1 用例 ps:商品ID这么获取:http://item.jd ...
- Codeforces #264 (Div. 2) D. Gargari and Permutations
Gargari got bored to play with the bishops and now, after solving the problem about them, he is tryi ...
- HDU 4357 String change 法冠军
意甲冠军: 鉴于a串b串,问我们能否a变b串 办法:自选a的2快报,ascil+=1 然后交换位置,能够操作自如倍. 3个月3以上就能T^T 2法官将着眼于暴力 #include <cstdio ...
- CMMI 能力成熟度模型集成
关于CMMI的过程域,请参考 CMMI能力成熟度模型集成的过程区域 1.CMMI/SPCA概述 CMM是“能力成熟度模型(Capability Maturity Model)”的英文简写,该模型由美国 ...
- 讨论IM软件“网上假货’
概要 网上假货.在不能使用网络的情况下,IM软件还显示在线. 网上是假的"在线--当前离线"之间的状态,在这段时期.用户无法发送消息.用户可以创建假冒网上心跳的错觉(点击了解).缓 ...
- android viewpager fragment切换时界面卡顿解决办法
目前开发的程序在切换View时界面卡顿现象比较严重,影响用户体验,当前项目共就四个View,每个View也只是按钮,所以可以同时加载,不让其它view销毁. 只需在Adapter中重载destroyI ...
- QT 窗体控件的透明度设置(三种方法)
整个窗体 当设置QT的窗体(QMainWindow, QDialog)时,直接用 targetForm->setWindowOpacity() 函数即可实现,效果为窗体及窗体内所有控件都透明 ...
- C# WebApi使用AttributeRoutes特性路由
1.在创建WebApi中默认的路由规则,只能满足一般简单的RESTful风格,如 api/Products/{id}. 但是在实际运用中很难严格满足RESTful要求的WebApi.因此需要使用高版本 ...
- Lambda表达式的参数捕获
以常用的Action委托为例: 有如下3个无参数的方法: public void Function() { //Do something } public void Function2() { //D ...
- 原生Js监听普通dom尺寸变化
原生Js监听普通dom尺寸变化 具体做法有以下几种: 初始化项目后,轮询,反复查看 dom 尺寸是否变化,这种一听就感觉不好,开销太大. 监听元素的滚动事件,在 目标 dom 里面包裹一个同等大小的 ...
