Google Earth Engineを少し使ってみる

## 概要
Google Earth Engineを試しに触ってみたのでまとめます

https://earthengine.google.com/

## Google Earth Engineとは
![f1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/26e8a220-2d9b-5e1d-37f9-fe9b96c8488f.png)

* 衛星画像や地理データセットを持つ地理空間情報を分析するためのツール
    * 地球表面の変化を検出し、傾向のマッピングなどができる
    * 森林と水の被覆率、土地利用の変化、農地の評価などに利用可能
* データセット一覧は以下参照

https://developers.google.com/earth-engine/datasets/catalog

* 過去40年以上前の地球画像を含む公開データをアーカイブしている
* 分析ができるとことがGoogle Earthとの大きな違い
* 商用利用可能だが、学術および研究用途は無料

## はじめてみる
* [Google Earth Engineのページ](https://earthengine.google.com/)にアクセスし、「Sign Up Now」をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/8ff6c6cc-455e-e347-75b1-98645663229e.png)
* Googleアカウントを選択し、ログインする
![f2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/5fd8fe45-e939-70b1-8192-0403acb8e643.png)
* 「Register a Noncommercial or Commercial Cloud project」をクリックする
![f3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/e755d91f-1c98-dacd-a938-2ff3bc4c5cfe.png)
* 利用目的にあわせて、Paid/Unpaidを選択する(以下リンクに該当すれば無償利用可能)
    * ここでは個人利用のため無償で利用を選択

https://earthengine.google.com/noncommercial/#institution-types

![f11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/d42f3298-f9f3-a469-e8eb-20b9e08a1972.png)

* Google Projectが必要なため、新規作成or既存のプロジェクトを選択する
![f5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/1aa901b6-3ed6-e7ec-7fb9-8da226c5dbed.png)

 * ログインしているGoogleアカウントでGoogle Cloudを利用したことがない場合は以下のメッセージのリンクからGoogle Cloudの利用規約に同意する(無償利用のみであればGoogle Cloudの課金情報登録は不要)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/1e9006f2-13c4-b857-d3ab-52287be463e7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/1152d437-1715-bd9e-c812-687950c82916.png)

* CONFIRMをクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/eedbcfcc-2268-59ea-08c1-6c8713499a4c.png)

* Google Earth Engineの画面がでてくる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/070222fa-8cde-2c6d-3056-4fac8075adab.png)

## つかいかた
* Google Earth Engineの画面については以下ページを参照

https://developers.google.com/earth-engine/guides/playground

* コードエディタではjavascriptでコードを記述することができる。利用できるオブジェクトやメソッドは以下参照
    * pythonのライブラリもあるのでpythonを使うこともできる

https://developers.google.com/earth-engine/guides/objects_methods_overview

* チュートリアルは以下参照

https://developers.google.com/earth-engine/tutorials

## つかってみる
* ここでは以下のサンプルを利用しました

https://developers.google.com/earth-engine/tutorials/community/identifying-first-day-no-snow

* 表示場所(`Map.setCenter`)だけ東京(皇居の緯度経度)に変えています

```javascript
var startDoy = 1;
var startYear = 2000;
var endYear = 2019;
var startDate;
var startYear;

function addDateBands(img) {
  // Get image date.
  var date = img.date();
  // Get calendar day-of-year.
  var calDoy = date.getRelative('day', 'year');
  // Get relative day-of-year; enumerate from user-defined startDoy.
  var relDoy = date.difference(startDate, 'day');
  // Get the date as milliseconds from Unix epoch.
  var millis = date.millis();
  // Add all of the above date info as bands to the snow fraction image.
  var dateBands = ee.Image.constant([calDoy, relDoy, millis, startYear])
    .rename(['calDoy', 'relDoy', 'millis', 'year']);
  // Cast bands to correct data type before returning the image.
  return img.addBands(dateBands)
    .cast({'calDoy': 'int', 'relDoy': 'int', 'millis': 'long', 'year': 'int'})
    .set('millis', millis);
}
var waterMask = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24')
  .select('water_mask')
  .not();
  
  
var completeCol = ee.ImageCollection('MODIS/006/MOD10A1')
  .select('NDSI_Snow_Cover');
  

// Pixels must have been 10% snow covered for at least 2 weeks in 2018.
var snowCoverEphem = completeCol.filterDate('2018-01-01', '2019-01-01')
  .map(function(img) {
    return img.gte(10);
  })
  .sum()
  .gte(14);

// Pixels must not be 10% snow covered more than 124 days in 2018.
var snowCoverConst = completeCol.filterDate('2018-01-01', '2019-01-01')
  .map(function(img) {
    return img.gte(10);
  })
  .sum()
  .lte(124);
  
  
var analysisMask = waterMask.multiply(snowCoverEphem).multiply(snowCoverConst);

var years = ee.List.sequence(startYear, endYear);


var annualList = years.map(function(year) {
  // Set the global startYear variable as the year being worked on so that
  // it will be accessible to the addDateBands mapped to the collection below.
  startYear = year;
  // Get the first day-of-year for this year as an ee.Date object.
  var firstDoy = ee.Date.fromYMD(year, 1, 1);
  // Advance from the firstDoy to the user-defined startDay; subtract 1 since
  // firstDoy is already 1. Set the result as the global startDate variable so
  // that it is accessible to the addDateBands mapped to the collection below.
  startDate = firstDoy.advance(startDoy-1, 'day');
  // Get endDate for this year by advancing 1 year from startDate.
  // Need to advance an extra day because end date of filterDate() function
  // is exclusive.
  var endDate = startDate.advance(1, 'year').advance(1, 'day');
  // Filter the complete collection by the start and end dates just defined.
  var yearCol = completeCol.filterDate(startDate, endDate);
  // Construct an image where pixels represent the first day within the date
  // range that the lowest snow fraction is observed.
  var noSnowImg = yearCol
    // Add date bands to all images in this particular collection.
    .map(addDateBands)
    // Sort the images by ascending time to identify the first day without
    // snow. Alternatively, you can use .sort('millis', false) to
    // reverse sort (find first day of snow in the fall).
    .sort('millis')
    // Make a mosaic composed of pixels from images that represent the
    // observation with the minimum percent snow cover (defined by the
    // NDSI_Snow_Cover band); include all associated bands for the selected
    // image.
    .reduce(ee.Reducer.min(5))
    // Rename the bands - band names were altered by previous operation.
    .rename(['snowCover', 'calDoy', 'relDoy', 'millis', 'year'])
    // Apply the mask.
    .updateMask(analysisMask)
    // Set the year as a property for filtering by later.
    .set('year', year);

  // Mask by minimum snow fraction - only include pixels that reach 0
  // percent cover. Return the resulting image.
  return noSnowImg.updateMask(noSnowImg.select('snowCover').eq(0));
});


var annualCol = ee.ImageCollection.fromImages(annualList);

// Define a year to visualize.
var thisYear = 2018;

// Define visualization arguments.
var visArgs = {
  bands: ['calDoy'],
  min: 150,
  max: 200,
  palette: [
    '0D0887', '5B02A3', '9A179B', 'CB4678', 'EB7852', 'FBB32F', 'F0F921']};

// Subset the year of interest.
var firstDayNoSnowYear = annualCol.filter(ee.Filter.eq('year', thisYear)).first();

// Map it.
Map.setCenter(35.6852, 139.7528, 5);
Map.addLayer(firstDayNoSnowYear, visArgs, 'First day of no snow, 2018');
```

* 出力
    * 多少時間がかかります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876448/eadb44cd-e184-f8d0-6d19-40f7599b9035.png)



## おわりに
* 今回は簡単に試す程度でしたがBigQueryやVertexAIと連携しての分析などもおもしろそうなので近々やってみようと思います

https://cloud.google.com/blog/products/data-analytics/new-bigquery-connector-to-google-earth-engine

https://developers.google.com/earth-engine/guides/ee-vertex