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. java静态方法Static

    静态方法  是 与类  而  不是与对象 相关联的.

  2. Oracle 11g系统分区表中的新功能

    在11g有一个新的特点是分区表系统.下面做一个实验: SQL> select * from v$version; BANNER --------------------------------- ...

  3. Global Contrast based Salient Region Detection (Ming ming Cheng)

    abstract: Automatic estimation of salient object regions across images, without any prior assumption ...

  4. 3ds Max建模,Blend设计,VS2008控制WPF的3D模型例子

    原文:3ds Max建模,Blend设计,VS2008控制WPF的3D模型例子 3ds Max建模,Blend设计,VS2008控制WPF的3D模型例子   所用的软件 3ds Max 9.0,Mic ...

  5. 怎么给罗技K480 增加Home、End键

    最近看张大妈上很多人分享了我的桌面,有感于整天低头码字不利健康,隧鼓捣起自己的电脑桌了. 此处省略N字... 进入正文,我码字用的是罗技的K480蓝牙键盘 码了几行代码,发现没有Home.End键,这 ...

  6. XF 显示网络图像

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  7. Socket_Internet 命名空间

    英特网目前有两种地址格式:1.IPv4(32位地址格式)2.IPv6(128位地址格式).IPv4的命名空间为PF_INET,IPv6的命名空间则为PF_INET6. #incldue <sys ...

  8. WPF ObjectDataProvider的使用-只能检索用

    <Window x:Class="CollectionBinding.MainWindow"        xmlns="http://schemas.micros ...

  9. Java 访问修饰符详解

    访问修饰符定义了类.属性和方法的访问权限,Java 中包含四种,访问权限从小到大为 private.default.protected 和 public. public,公共修饰符,被其修饰的类.属性 ...

  10. 微信小程序把玩(二十七)audio组件

    原文:微信小程序把玩(二十七)audio组件 音频播放已经封装的很好!只需配合属性设置即可! (method和data配合使用) 主要属性: wxml <audio action="{ ...