(Translated by https://www.hiragana.jp/)
植物の分布から田畑の利用状況を推測する衛星データの利活用方法 | 宙畑

宙畑 Sorabatake

Tellus

植物しょくぶつ分布ぶんぷから田畑たはた利用りようじょうきょう推測すいそくする衛星えいせいデータの活用かつよう方法ほうほう

Tellusでは、利便りべんせい(データのCOG)と検索けんさく精度せいど(APIのフォーマット統一とういつ)の向上こうじょう目指めざして、データ配信はいしんようAPIの更新こうしんおこないました。それにともない、今回こんかいあたらしい配信はいしんようAPIを利用りようしてAVNIR-2のデータを取得しゅとくする方法ほうほうについて、田畑たはた利用りようじょうきょう推定すいていするれいとおしてご紹介しょうかいします。

Tellusでは、利便りべんせい(データのCOG)と検索けんさく精度せいど(APIのフォーマット統一とういつ)の向上こうじょう目指めざして、データ配信はいしんようAPIの更新こうしんおこないました。それにともない、今回こんかいあたらしい配信はいしんようAPIを利用りようしてAVNIR-2のデータを取得しゅとくする方法ほうほうについてご紹介しょうかいします。
https://www.tellusxdp.com/ja/news/20220630_000502.html

Tellusの解析かいせき環境かんきょう契約けいやくしていないほうであっても利用りよう可能かのうなAPIをもちいて解析かいせきおこないますので、みなさまお手元てもと環境かんきょうでおためしください。

なお、ほん記事きじ技術評論社ぎじゅつひょうろんしゃから出版しゅっぱんされている月刊げっかんSoftware Designにちゅうはたけ寄稿きこうした連載れんさい衛星えいせいデータプラットフォームTellusハンズオン」の内容ないようから、一部いちぶ修正しゅうせいして掲載けいさいするものです。

衛星えいせいデータでかること・できること

ちゅうはたけでは過去かこにもなん紹介しょうかいしていますが、あらためて「波長はちょう」とは文字通もじどおなみながさのことです。いろ通信つうしん使つか電波でんぱ赤外線せきがいせん紫外線しがいせんなどすべて電磁波でんじはであり、それぞれ「波長はちょう」によってことなる性質せいしつちます。

くわしくはこちらをごらんください:

ひとはこの電磁波でんじはなか可視かしこうといわれるかぎられた範囲はんい波長はちょうたいしか認識にんしき観測かんそく)できません。この可視かしこう波長はちょうたいあおみどりあかいろわせでとらえています。

これにたいして、人工じんこう衛星えいせいのセンサーでは可視かしこう以外いがい波長はちょうたい観測かんそくできます。観測かんそくしている波長はちょうなかには、紫外線しがいせん赤外線せきがいせん電波でんぱをとらえるセンサーを搭載とうさいしているものもあるので、わたしたちがにする地球ちきゅうとはことなった視点してん地球ちきゅう姿すがたることができます。

波長はちょうによってなぜかたちがうのでしょうか。それは対象たいしょうによって吸収きゅうしゅう透過とうか)あるいは反射はんしゃする太陽光たいようこう波長はちょうことなるからです。

たとえば、植物しょくぶつ物質ぶっしつくらべて近赤外線きんせきがいせん※の帯域たいいきつよ反射はんしゃすることがかっています。つまり、近赤外線きんせきがいせん観測かんそくした結果けっか利用りようすると、植物しょくぶつ分布ぶんぷ調しらべやすいとえます。
近赤外線きんせきがいせん(きんせきがいせん):可視かしこうちか波長はちょう赤外線せきがいせん

さらに、それぞれ個別こべつ波長はちょう調しらべるだけではなく、複数ふくすう波長はちょうのデータをわせて計算けいさんすることで調しらべたいものが判別はんべつしやすくなる場合ばあいがあります。

今回こんかいは、よく利用りようされる波長はちょうわせである正規せいき植生しょくせい指数しすう(NDVI)という指数しすうについて解析かいせき事例じれいまじえて紹介しょうかいします。

正規せいき植生しょくせい指数しすう=NDVI(Normalized Difference Vegetation Index)とは、植物しょくぶつ活性かっせい調しらべる指数しすうのことです。近赤外線きんせきがいせんひかりつよさ(NIR)と赤色あかいろひかりつよさ(Red)を以下いかしきてはめることでもとめることができます。

NDVI=(NIR-Red)/(NIR+Red)

たとえば、以下いかのように過去かこなんねんぶんのNDVIのとき系列けいれつていくことで、農作物のうさくもつ生育せいいくじょうきょう調しらべることができます。

EO Browser, https://apps.sentinel-hub.com/eo-browser/, Sinergise Ltd.

衛星えいせいデータプラットフォームTellus登録とうろく準備じゅんび

TellusのAPIを利用りようするためには、Tellusのアカウント登録とうろく必要ひつようです。まだアカウントをおちではないほうは、以下いかのページで必要ひつよう情報じょうほう入力にゅうりょくし、アカウントを作成さくせいします。
https://www.tellusxdp.com/market/login/

Tellusで公開こうかいしているデータの利用りよう規則きそくはそれぞれのデータの提供ていきょうもとのデータポリシーにもとづきます。なかには、Tellusが提供ていきょうする開発かいはつ環境かんきょうないでの利用りよう限定げんていされ、ローカル環境かんきょうへのダウンロードが禁止きんしされているデータもあるので注意ちゅうい必要ひつようです。

今回こんかいは、Tellus環境かんきょうがいからも利用りよう可能かのうなデータを使用しようしますので、Tellusアカウント登録とうろくをしたうえでAPIキーの発行はっこうさえすれば、お手元てもとのJupyter NotebookやGoogle Colabなどでもおためしいただけます。

ほん記事きじではGoogle Colabをれい紹介しょうかいします。

まずは自分じぶんのGoogle Driveと接続せつぞくします。

## google driveと接続せつぞく
from google.colab import drive
drive.mount('/content/drive')

解析かいせき必要ひつようなライブラリをインポートします。

!pip install rasterio
!pip install geopandas

import os
import requests
import json
import glob
import rasterio.mask
import fiona

import numpy as np
import rasterio as rio
import matplotlib.pyplot as plt
import geopandas as gpd
from rasterio.plot import show
from rasterio.plot import show_hist

API利用りようさい必要ひつようなトークンは、Tellusにログインみぎじょうのユーザーめいのプルダウンメニューから[開発かいはつ環境かんきょう]>[APIアクセス]を選択せんたくし、[トークンの発行はっこう]からあたらしいトークンを発行はっこうします。

#かく個人こじんのAPIトークンを入力にゅうりょく
token = 'XXXXXXXXXXXXXXXX'

衛星えいせいデータの検索けんさく取得しゅとく

Tellusの衛星えいせいデータAPIのリファレンスは以下いか公開こうかいしています。
https://www.tellusxdp.com/docs/travelers/

Tellusで公開こうかいしている衛星えいせいデータは「データセット」「シーン」「ファイル」という構造こうぞうになっています。

▼Tellusのデータ構造こうぞう
データセットA
  └ シーンa
    └ ファイルa-i
    └ ファイルa-ii
  └ シーンb
    └ ファイルb-i
    └ ファイルb-i
・・・

「データセット」はある衛星えいせい搭載とうさいされたセンサや、ぜん処理しょり方式ほうしきなどがそろったデータのまとまりです。

「シーン」は特定とくてい場所ばしょをあるタイミングで撮影さつえいしたまとまりで、撮影さつえい方法ほうほうなどにより、たとえばあかあおみどり波長はちょう要素ようそごと複数ふくすうの「ファイル」が存在そんざいします。

くわしくはこちらの記事きじとうをごらんください。

衛星えいせいデータをAPIで取得しゅとくするまえに、Tellus Traveler(ブラウザ)じょう必要ひつよう衛星えいせいデータにかんする情報じょうほう取得しゅとくします。Travelerの使つかかた以下いかをごらんください。
https://www.tellusxdp.com/ja/traveler-service/guide/traveler-how-to/2_traveler.html

今回こんかいは、2006ねん10がつ31にちにAVNIR-2によって撮影さつえいされた青森あおもりけん画像がぞう利用りようします。ご自身じしん興味きょうみのある領域りょういき検索けんさくし、データセットIDとシーンIDを取得しゅとくして解析かいせきにチャレンジしてみてください。

上記じょうき衛星えいせい画像がぞうのデータセットIDとシーンIDは以下いかとおりです。

dataset_id='ea71ef6e-9569-49fc-be16-ba98d876fb73'

scenes = [
    '202ce08d-ba4b-4ffe-8165-109fd3a8b917'
]

調しらべたデータセットIDとシーンIDから、そのシーンにふくまれるファイルめい取得しゅとくします。Tellus Travelerを利用りようしてデータを取得しゅとくする関数かんすう以下いかとおりです。

# データセットIDとシーンIDから、そのシーンにふくまれるファイルめい取得しゅとくする
def get_dataset_data_by_id_files(base_path, token, dataset_id, data_id):
    print(base_path, token, dataset_id, data_id)
    url = '{}/api/traveler/v1/datasets/{}/data/{}/files/'.format(
        base_path, dataset_id, data_id)
    headers = {
        'Authorization': 'Bearer ' + token,
        'content-type': 'application/json'
    }
    r = requests.get(url, headers=headers)
    assert r.status_code == 200
    return json.loads(r.content)

つぎに、ファイルIDを指定していしてデータのダウンロードURLを取得しゅとくします。

# ファイルIDを指定していして、ダウンロードURLを取得しゅとくする
def get_dataset_data_by_id_files_by_id_download_url(base_path, token, dataset_id, data_id, file_id):
    url = '{}/api/traveler/v1/datasets/{}/data/{}/files/{}/download-url/'.format(
        base_path, dataset_id, data_id, file_id)
    headers = {
        'Authorization': 'Bearer ' + token,
        'content-type': 'application/json'
    }
    r = requests.post(url, headers=headers)
    assert r.status_code == 200
    return json.loads(r.content)

ダウンロードURLをもちいて衛星えいせいデータをダウンロードする関数かんすう以下いかとおりです。

# 衛星えいせいデータのダウンロードをおこなう
def download(scenes, dataset_id, token, dist='./', base_path='https://www.tellusxdp.com'):
    for scene_id in scenes:       
        files = get_dataset_data_by_id_files(
            base_path, token, dataset_id, scene_id)
        print(files)
        rawdata = files['results']
        path = os.path.join(dist, scene_id)
        if len(rawdata) > 0:
            for file in rawdata:
                file_id = file['id']
                file_name = file['name']

                file_path = os.path.join(path, file_name)

                download_url = get_dataset_data_by_id_files_by_id_download_url(
                        base_path, token, dataset_id, scene_id, file_id)['download_url']

                r = requests.get(download_url, stream=True)

                if not os.path.exists(path):
                    os.makedirs(path)

                with open(file_path, 'wb') as f:
                    for chunk in r.iter_content(chunk_size=1024):
                        if chunk:

                            f.write(chunk)
                            f.flush()

これらの関数かんすう実行じっこうすることで、衛星えいせいデータをご自身じしんのGoogle Driveにダウンロードできます。

# データDL
download(scenes, dataset_id, token)

NDVIの算出さんしゅつ

さて、様々さまざまなバンドのデータがダウンロードできたらそのデータを処理しょりしてNDVIを算出さんしゅつしていきましょう。

本来ほんらいNDVIは輝度きどではなく、輝度きど大気たいき補正ほせい処理しょりおこな算出さんしゅつする地上ちじょう反射はんしゃりつ利用りようしますが、今回こんかい処理しょり簡素かんそ輝度きど変換へんかんして抽出ちゅうしゅつしています。

# NDVIの算出さんしゅつ
def mk_ndvi_rio(red_img, nir_img, red_gain, red_offset, nir_gain, nir_offset, out_ndvi):
 red = rio.open(red_img)
  nir = rio.open(nir_img)

  red_arr = red.read().astype(float)
  nir_arr = nir.read().astype(float)

  kwargs = {
      "width" : red.width,
      "height" : red.height,
      "count" : 1,
      "crs" : red.crs,
      "transform" : red.transform,
      "dtype" : rio.float32}
      
  ## DN2輝度きど変換へんかん
  red_arr = red_arr * red_gain + red_offset
  nir_arr = nir_arr * nir_gain + nir_offset
  
  ## NDVI算出さんしゅつ
  ndvi = np.where(((red_arr != 0) & (nir_arr != 0)),((nir_arr - red_arr) / (nir_arr + red_arr) ),0)

  write_ndvi = rio.open(out_ndvi,"w",driver="Gtiff",**kwargs)
  write_ndvi.write(ndvi)
  write_ndvi.close()

  return(out_ndvi)

NDVI画像がぞう作成さくせいしていきます。

DATA_DIR = "/content/drive/MyDrive/work/study/Sorabatake/02_data"
DIR_LIST = os.listdir(DATA_DIR)
NDVI_DIR = "/content/drive/MyDrive/work/study/Sorabatake/03_ndvi"
#print(DIR_LIST) 

#データを取得しゅとく
for dir_name in DIR_LIST:

  dir_path = os.path.join(DATA_DIR, dir_name)
  #print(dir_path)

  subdir_list = os.listdir(dir_path)
  red_path = glob.glob(dir_path + "/IMG-03-*.tif")
  nir_path = glob.glob(dir_path + "/IMG-04-*.tif")
  hdr_path = glob.glob(dir_path + "/HDR-*.txt")
  hdr_path = str(hdr_path[0])
 
  # HDR情報じょうほうから、ゲイン、オフセット情報じょうほう抽出ちゅうしゅつ
  hdr_f = open(hdr_path,"r")
  hdr_data = hdr_f.read()
  hdr_f.close

  # gain, offset
  red_gain = float(hdr_data[1753:1761])
  red_offset = float(hdr_data[1761:1769])
  nir_gain = float(hdr_data[1769:1777])
  nir_offset = float(hdr_data[1777:1785])
  print(red_gain, red_offset, nir_gain, nir_offset)

  red_path = red_path[0]
  nir_path = nir_path[0]
  print(red_path, nir_path)
  
  #NDVI画像がぞう作成さくせい
  base_name = os.path.basename(red_path)
  ndvi_file = "NDVI-" + base_name[7:]
  ndvi_path = os.path.join(NDVI_DIR, ndvi_file)

作成さくせいしたNDVI画像がぞう表示ひょうじします。

NDVI_20061031 = rio.open(NDVI_DIR + "/NDVI-ALAV2A040842780-OORIRFU-D069P3-20061031-001.tif")

NDVI_20061031 = NDVI_20061031.read(1)

fig = plt.figure(figsize=(18,18))


img1 = ax1.imshow(NDVI_20061031, cmap='RdYlGn', vmin=-1, vmax=1)
ax1.set_title("NDVI_20061031")
cbar1 = fig.colorbar(img1,ax=ax1, aspect=40,pad=0.08,shrink=0.8)

plt.show(fig)

以下いかのような画像がぞう表示ひょうじされます。

植物しょくぶつ活発かっぱつなところをみどりで、植物しょくぶつのないところ(みずうみなど)があか表示ひょうじされています。一般いっぱんてきなカラー画像がぞうみぎ)と比較ひかくしても、植物しょくぶつ活性かっせいしている部分ぶぶんがよりかりやすくなっています。

NDVIをとき系列けいれつにグラフする

ここまでは、1まい衛星えいせいデータについて分析ぶんせきをしてきましたが、おな場所ばしょ衛星えいせいデータをとき系列けいれつていくことで、田畑たはた利用りようじょうきょう推定すいていしてみます。たとえば、夏場なつばにNDVIがひくいところがあれば、その田畑たはた作付さくづけがおこなわれていない、つまりは遊休ゆうきゅう農地のうちである可能かのうせいがあるとかんがえることができます。

そこで、農林水産省のうりんすいさんしょう公開こうかいしているふでポリゴンとばれる田畑たはた区画くかくデータを使つかって、区画くかくごとのNDVIとき系列けいれつ推移すいいもとめてみましょう。

衛星えいせいデータの検索けんさく取得しゅとく」のふしのコードをもちいてデータをダウンロードします。ダウンロードしたデータからNDVIを算出さんしゅつしていきます。「衛星えいせいデータの検索けんさく取得しゅとく」のつづきとして以下いか実行じっこうしてください。

def mk_ndvi_rio(red_img, nir_img, red_gain, red_offset, nir_gain, nir_offset, out_ndvi):
  """
    NAME:
        make_ndvi_rio
    
    ARGUMENT:
        red_img   : あかバンドぞう
        nir_img   : あかがいパンド画像がぞう
        red_gain  : あかバンドゲイン
        red_offset: あかバンドオフセット
        nir_gain  : あかがいバンドゲイン
        nir_offset: あかがいバンドオフセット
        out_ndvi  : NDVI画像がぞう

    DISCRIPTION:
       The original code was written by N.Furuta 

        ■DNから輝度きどへの変換へんかんしき
          L = a×O+b
            L:輝度きど(W/m2/sr/μみゅーm)
            O:校正こうせいみデジタル(DN)
            a:絶対ぜったい校正こうせい係数けいすう(ゲイン)
            b:オフセット
            ※プロダクトフォーマット説明せつめいしょ AVNIR-2へんひょう3.3-8 アンシラリ2(ラジオメトリック校正こうせい)レコード、p3-30 参照さんしょう 
        
        ■NDVI計算けいさん
          (きんあかがいバンド - あかバンド)/(きんあかがいバンド + あかバンド)
          ※本来ほんらい輝度きどをさらに地上ちじょう反射はんしゃりつ変換へんかんしたものを利用りよう本関ほんせきすうでは簡単かんたんのため輝度きどもちいて計算けいさん簡易かんいNDVI)
        
    RETURN:
        out_ndvi : NDVI画像がぞう(パス)
  """
  
  red = rio.open(red_img)
  nir = rio.open(nir_img)

  red_arr = red.read().astype(float)
  nir_arr = nir.read().astype(float)

  kwargs = {
      "width" : red.width,
      "height" : red.height,
      "count" : 1,
      "crs" : red.crs,
      "transform" : red.transform,
      "dtype" : rio.float32}
      
  ## DN2輝度きど変換へんかん
  red_arr = red_arr * red_gain + red_offset
  nir_arr = nir_arr * nir_gain + nir_offset
  
  ## NDVI算出さんしゅつ
  ndvi = np.where(((red_arr != 0) & (nir_arr != 0)),((nir_arr - red_arr) / (nir_arr + red_arr) ),0)

  write_ndvi = rio.open(out_ndvi,"w",driver="Gtiff",**kwargs)
  write_ndvi.write(ndvi)
  write_ndvi.close()

  return(out_ndvi)

NDVI画像がぞう作成さくせいします。

"""
2.NDVI画像がぞう作成さくせい
  ## HDR情報じょうほう公式こうしきドキュメントを参照さんしょう
  https://www.eorc.jaxa.jp/ALOS/alos-ori/doc/AVNIR-2_ORI_format_jp.pdf

"""
# 衛星えいせい画像がぞう(AVNIR-2)を保存ほぞんしているフォルダを指定してい
# 自身じしん環境かんきょうわせて指定していさき変更へんこうしてください
DATA_DIR = "/content/drive/MyDrive/work/study/Sorabatake/02_data"
DIR_LIST = os.listdir(DATA_DIR)

# NDVI画像がぞう保存ほぞんさきのフォルダを指定してい
NDVI_DIR = "/content/drive/MyDrive/work/study/Sorabatake/03_ndvi"
#print(DIR_LIST) 

#データを取得しゅとく
for dir_name in DIR_LIST:

  dir_path = os.path.join(DATA_DIR, dir_name)
  #print(dir_path)

  subdir_list = os.listdir(dir_path)
  red_path = glob.glob(dir_path + "/IMG-03-*.tif")
  nir_path = glob.glob(dir_path + "/IMG-04-*.tif")
  hdr_path = glob.glob(dir_path + "/HDR-*.txt")
  hdr_path = str(hdr_path[0])
  #print(hdr_path)

  # HDR情報じょうほうから、ゲイン、オフセット情報じょうほう抽出ちゅうしゅつ
  hdr_f = open(hdr_path,"r")
  hdr_data = hdr_f.read()
  hdr_f.close

  # gain, offset
  red_gain = float(hdr_data[1753:1761])
  red_offset = float(hdr_data[1761:1769])
  nir_gain = float(hdr_data[1769:1777])
  nir_offset = float(hdr_data[1777:1785])
  print(red_gain, red_offset, nir_gain, nir_offset)

  red_path = red_path[0]
  nir_path = nir_path[0]
  print(red_path, nir_path)
  
  #NDVI画像がぞう作成さくせい
  base_name = os.path.basename(red_path)
  ndvi_file = "NDVI-" + base_name[7:]
  ndvi_path = os.path.join(NDVI_DIR, ndvi_file)

まず、目視もくし変化へんか観察かんさつしてみましょう。

以下いかのコードを実行じっこうすることで、複数ふくすう時期じき青森あおもり県域けんいきのNDVI画像がぞう表示ひょうじします。青森あおもり以外いがいのデータを取得しゅとくしているほう以下いかのファイルめい修正しゅうせいしてください。

#NDVI画像がぞう表示ひょうじ
NDVI_20061031 = rio.open(NDVI_DIR + "/NDVI-ALAV2A040842780-OORIRFU-D069P3-20061031-001.tif")
NDVI_20070618 = rio.open(NDVI_DIR + "/NDVI-ALAV2A074392780-OORIRFU-D069P3-20070618-002.tif")
NDVI_20080805 = rio.open(NDVI_DIR + "/NDVI-ALAV2A134782780-OORIRFU-D069P3-20080805-003.tif")
NDVI_20081105 = rio.open(NDVI_DIR + "/NDVI-ALAV2A148202780-OORIRFU-D069P3-20081105-000.tif")
NDVI_20090508 = rio.open(NDVI_DIR + "/NDVI-ALAV2A175042780-OORIRFU-D069P3-20090508-003.tif")
NDVI_20100626 = rio.open(NDVI_DIR + "/NDVI-ALAV2A235432780-OORIRFU-D069P3-20100626-002.tif")
NDVI_20100926 = rio.open(NDVI_DIR + "/NDVI-ALAV2A248852780-OORIRFU-D069P3-20100926-001.tif")

NDVI_20061031 = NDVI_20061031.read(1)
NDVI_20070618 = NDVI_20070618.read(1)
NDVI_20080805 = NDVI_20080805.read(1)
NDVI_20081105 = NDVI_20081105.read(1)
NDVI_20090508 = NDVI_20090508.read(1)
NDVI_20100626 = NDVI_20100626.read(1)
NDVI_20100926 = NDVI_20100926.read(1)

fig = plt.figure(figsize=(18,18))
ax1 = fig.add_subplot(331)
ax2 = fig.add_subplot(332)
ax3 = fig.add_subplot(333)
ax4 = fig.add_subplot(334)
ax5 = fig.add_subplot(335)
ax6 = fig.add_subplot(336)
ax7 = fig.add_subplot(337)

img1 = ax1.imshow(NDVI_20061031, cmap='RdYlGn', vmin=-1, vmax=1)
ax1.set_title("NDVI_20061031")
cbar1 = fig.colorbar(img1,ax=ax1, aspect=40,pad=0.08,shrink=0.8)
img2 = ax2.imshow(NDVI_20070618, cmap='RdYlGn', vmin=-1, vmax=1)
ax2.set_title("NDVI_20070618")
cbar2 = fig.colorbar(img2,ax=ax2, aspect=40,pad=0.08,shrink=0.8)
img3 = ax3.imshow(NDVI_20080805, cmap='RdYlGn', vmin=-1, vmax=1)
ax3.set_title("NDVI_20080805")
cbar3 = fig.colorbar(img3,ax=ax3, aspect=40,pad=0.08,shrink=0.8)
img4 = ax4.imshow(NDVI_20081105, cmap='RdYlGn', vmin=-1, vmax=1)
ax4.set_title("NDVI_20081105")
cbar4 = fig.colorbar(img4,ax=ax4, aspect=40,pad=0.08,shrink=0.8)
img5 = ax5.imshow(NDVI_20090508, cmap='RdYlGn', vmin=-1, vmax=1)
ax5.set_title("NDVI_20090508")
cbar5 = fig.colorbar(img5,ax=ax5, aspect=40,pad=0.08,shrink=0.8)
img6 = ax6.imshow(NDVI_20100626, cmap='RdYlGn', vmin=-1, vmax=1)
ax6.set_title("NDVI_20100626")
cbar6 = fig.colorbar(img6,ax=ax6, aspect=40,pad=0.08,shrink=0.8)
img7 = ax7.imshow(NDVI_20100926, cmap='RdYlGn', vmin=-1, vmax=1)
ax7.set_title("NDVI_20100926")
cbar7 = fig.colorbar(img7,ax=ax7, aspect=40,pad=0.08,shrink=0.8)

plt.show(fig)

そうすると以下いかのような結果けっかられるかとおもいます。

Credit : JAXA

今回こんかいれいとして、青森あおもりけん藤崎ふじさきまち対象たいしょうにNDVI解析かいせきおこなっていきます。そのために上記じょうき算出さんしゅつしたNDVI画像がぞう藤崎ふじさきまち区画くかく沿ってします。
藤崎ふじさきまち区画くかくポリゴンは国土こくど地理ちりいん公開こうかいしている国土こくど数値すうち情報じょうほうのうち、行政ぎょうせい区域くいきデータ利用りようしています。

# 青森あおもりけん全域ぜんいき行政ぎょうせい区域くいきデータのなかから藤崎ふじさきまちだけのDVIく
# 藤崎ふじさきまちのポリゴンを抽出ちゅうしゅつ

# 行政ぎょうせい区域くいきデータの保存ほぞんさきのフォルダを指定してい
# ※自身じしん環境かんきょうわせて指定していさき変更へんこうしてください
AOMORI_PATH = "/content/drive/MyDrive/work/study/Sorabatake/04_polygon/Aomori_N03-20210101_02_GML/"
# そのうちshape形式けいしきのデータを指定してい
AOMORI_SHP = "N03-21_02_210101.shp"
df_aomori = gpd.read_file(os.path.join(AOMORI_PATH, AOMORI_SHP), encoding="shift-jis")

Fujisaki_machi = df_aomori[df_aomori["N03_004"].isin(["藤崎ふじさきまち"])]
Fujisaki_machi = Fujisaki_machi.drop(columns=["N03_002","N03_003"])

#投影とうえい変換へんかん
reprojest_Fujisaki_machi = Fujisaki_machi.to_crs({"init":"epsg:32654"})
reproject_out = os.path.join(AOMORI_PATH, "epsg_32654-"+ AOMORI_SHP)
#出力しゅつりょく
reprojest_Fujisaki_machi.to_file(driver="ESRI Shapefile",filename=reproject_out)

#GeoDataFrameを描画びょうが
f,ax = plt.subplots(1, figsize=(6,6))
ax = Fujisaki_machi.plot(axes=ax)
plt.show

おな場所ばしょ解析かいせき実行じっこうした場合ばあい上記じょうき実行じっこうすると以下いかのような結果けっかられます。

つぎに、NDVI画像がぞう藤崎ふじさきまちのポリゴンでマスク処理しょりし、藤崎ふじさき以外いがい範囲はんいのNDVI画像がぞう削除さくじょします。

# マスク処理しょり画像がぞう保存ほぞんさきのフォルダを指定してい
# ※自身じしん環境かんきょうわせて指定していさき変更へんこうしてください
MASK_DIR = "/content/drive/MyDrive/work/study/Sorabatake/03_ndvi/02_fujisaki_masked"
ndvi_list = os.listdir(NDVI_DIR)
ndvi_list = [f for f in ndvi_list if os.path.isfile(os.path.join(NDVI_DIR, f))]

for ndvi_file_name in ndvi_list:

  print("処理しょり開始かいし:" + ndvi_file_name)

  with fiona.open(reproject_out, "r") as mask:
    masks = [feature["geometry"] for feature in mask]

  ndvi_data = os.path.join(NDVI_DIR, ndvi_file_name)
  print(ndvi_data)
  print(masks)
  with rasterio.open(ndvi_data) as src:
    out_image, out_transform = rasterio.mask.mask(src, masks, nodata=np.nan, crop=True)
    out_meta = src.meta

  out_meta.update({"driver": "GTiff",
                 "height": out_image.shape[1],
                 "width": out_image.shape[2],
                 "transform": out_transform})
  
  with rasterio.open(MASK_DIR + "/Masked-" + str(ndvi_file_name), "w", **out_meta) as dst:
    dst.write(out_image)

つぎに、目視もくし確認かくにんするために藤崎ふじさきまちのNDVI画像がぞう一覧いちらん表示ひょうじします。

#藤崎ふじさきまちしたNDVI画像がぞう表示ひょうじ
masked_NDVI_20061031 = rio.open(MASK_DIR + "/Masked-NDVI-ALAV2A040842780-OORIRFU-D069P3-20061031-001.tif")
masked_NDVI_20070618 = rio.open(MASK_DIR + "/Masked-NDVI-ALAV2A074392780-OORIRFU-D069P3-20070618-002.tif")
masked_NDVI_20080805 = rio.open(MASK_DIR + "/Masked-NDVI-ALAV2A134782780-OORIRFU-D069P3-20080805-003.tif")
masked_NDVI_20081105 = rio.open(MASK_DIR + "/Masked-NDVI-ALAV2A148202780-OORIRFU-D069P3-20081105-000.tif")
masked_NDVI_20090508 = rio.open(MASK_DIR + "/Masked-NDVI-ALAV2A175042780-OORIRFU-D069P3-20090508-003.tif")
masked_NDVI_20100626 = rio.open(MASK_DIR + "/Masked-NDVI-ALAV2A235432780-OORIRFU-D069P3-20100626-002.tif")
masked_NDVI_20100926 = rio.open(MASK_DIR + "/Masked-NDVI-ALAV2A248852780-OORIRFU-D069P3-20100926-001.tif")

masked_NDVI_20061031 = masked_NDVI_20061031.read(1)
masked_NDVI_20070618 = masked_NDVI_20070618.read(1)
masked_NDVI_20080805 = masked_NDVI_20080805.read(1)
masked_NDVI_20081105 = masked_NDVI_20081105.read(1)
masked_NDVI_20090508 = masked_NDVI_20090508.read(1)
masked_NDVI_20100626 = masked_NDVI_20100626.read(1)
masked_NDVI_20100926 = masked_NDVI_20100926.read(1)

fig = plt.figure(figsize=(16,12))
ax1 = fig.add_subplot(331)
ax2 = fig.add_subplot(332)
ax3 = fig.add_subplot(333)
ax4 = fig.add_subplot(334)
ax5 = fig.add_subplot(335)
ax6 = fig.add_subplot(336)
ax7 = fig.add_subplot(337)

img1 = ax1.imshow(masked_NDVI_20061031, cmap='RdYlGn', vmin=-1, vmax=1)
ax1.set_title("NDVI_20061031")
cbar1 = fig.colorbar(img1,ax=ax1, aspect=40,pad=0.08,shrink=0.8)
img2 = ax2.imshow(masked_NDVI_20070618, cmap='RdYlGn', vmin=-1, vmax=1)
ax2.set_title("NDVI_20070618")
cbar2 = fig.colorbar(img2,ax=ax2, aspect=40,pad=0.08,shrink=0.8)
img3 = ax3.imshow(masked_NDVI_20080805, cmap='RdYlGn', vmin=-1, vmax=1)
ax3.set_title("NDVI_20080805")
cbar3 = fig.colorbar(img3,ax=ax3, aspect=40,pad=0.08,shrink=0.8)
img4 = ax4.imshow(masked_NDVI_20081105, cmap='RdYlGn', vmin=-1, vmax=1)
ax4.set_title("NDVI_20081105")
cbar4 = fig.colorbar(img4,ax=ax4, aspect=40,pad=0.08,shrink=0.8)
img5 = ax5.imshow(masked_NDVI_20090508, cmap='RdYlGn', vmin=-1, vmax=1)
ax5.set_title("NDVI_20090508")
cbar5 = fig.colorbar(img5,ax=ax5, aspect=40,pad=0.08,shrink=0.8)
img6 = ax6.imshow(masked_NDVI_20100626, cmap='RdYlGn', vmin=-1, vmax=1)
ax6.set_title("NDVI_20100626")
cbar6 = fig.colorbar(img6,ax=ax6, aspect=40,pad=0.08,shrink=0.8)
img7 = ax7.imshow(masked_NDVI_20100926, cmap='RdYlGn', vmin=-1, vmax=1)
ax7.set_title("NDVI_20100926")
cbar7 = fig.colorbar(img7,ax=ax7, aspect=40,pad=0.08,shrink=0.8)

plt.show(fig)

そうすると以下いかのような結果けっかられます。

Credit : Original data provided by JAXA

耕作こうさくおこなわれていない可能かのうせいのある圃場ほじょう抽出ちゅうしゅつ

ここまでで準備じゅんびととのいました。いよいよ遊休ゆうきゅう農地のうち、つまりは耕作こうさくおこなわれていない可能かのうせいのある圃場ほじょう抽出ちゅうしゅつしていきましょう。

これらの判定はんてい条件じょうけんとして、ここではいね作付さくづけがされていない圃場ほじょう、つまり周囲しゅうい比較ひかくしてNDVIぶし変動へんどうすくない圃場ほじょう夏場なつばのNDVIちいさい圃場ほじょう判定はんていのための簡易かんいてき条件じょうけんとします。

しかし、闇雲やみくもにシーン全体ぜんたいから上記じょうき条件じょうけんてはめてしまっても、圃場ほじょう以外いがいのエリアも大量たいりょう抽出ちゅうしゅつされてしまうことがかんがえられます。そのため、まずはじめにどこが圃場ほじょうなのかを判定はんていする必要ひつようがあります。そのうえで、すべての時期じきのNDVIデータにおいてNDVIの変化へんかすくない圃場ほじょう抽出ちゅうしゅつすることとします。

圃場ほじょうデータとして、ここでは農林水産省のうりんすいさんしょう公開こうかいしているふでポリゴンデータ利用りようします※。これは圃場ほじょうひとひとつが単一たんいつのポリゴンとして格納かくのうされており、これをもちいて、それぞれの圃場ほじょうごとのデータを抽出ちゅうしゅつすることが可能かのうとなります。

※なお、このふでポリゴンが公開こうかいされているのは2020ねん以降いこうのデータであるため、実際じっさい衛星えいせいデータの撮像さつぞうである2006ねん~2010ねん一致いっちしませんので、あくまで参考さんこうとしての利用りようになります。

はじめにふでポリゴンデータをGeoPandasのデータフレームとしてみ、衛星えいせい画像がぞう重畳ちょうじょうするために投影とうえい変換へんかんおこないます。

なお、GeoPandasって?というほう以下いか記事きじをごらんください。

## ふでポリゴンのみ
## 藤崎ふじさきまちふでポリゴンを抽出ちゅうしゅつ

# ふでポリゴンの保存ほぞんさきのフォルダを指定してい
# ※自身じしん環境かんきょうわせて指定していさき変更へんこうしてください
POLYGON_PATH = "/content/drive/MyDrive/work/study/Sorabatake/06_fude_polygon/02青森あおもりけん(2021公開こうかい)/02361藤崎ふじさきまち(2021公開こうかい)"
POLYGON_SHP = "02361藤崎ふじさきまち(2021公開こうかい)__aa.shp"
df_fude_polygon = gpd.read_file(os.path.join(POLYGON_PATH, POLYGON_SHP), encoding="shift-jis")

#データの確認かくにん
df_fude_polygon

Fujisaki_PaddyField = df_fude_polygon[df_fude_polygon["耕地こうち種類しゅるい"].isin([""])]
Fujisaki_PaddyField = Fujisaki_PaddyField.drop(columns=["公開こうかい年度ねんど","調製ちょうせい年度ねんど"])

#投影とうえい変換へんかん
reprojest_Fujisaki_PaddyField = Fujisaki_PaddyField.to_crs({"init":"epsg:32654"})
reproject_PaddyFiled_out = os.path.join(POLYGON_PATH, "epsg_32654-"+ POLYGON_SHP)

#出力しゅつりょく
reprojest_Fujisaki_PaddyField.to_file(driver="ESRI Shapefile",filename=reproject_PaddyFiled_out, encoding="shift-jis")

#抽出ちゅうしゅつした藤崎ふじさきまちふでポリゴンを描画びょうが
f,ax = plt.subplots(1, figsize=(6,6))
ax = reprojest_Fujisaki_PaddyField.plot(ax=ax)
plt.show

おな場所ばしょのデータを取得しゅとくしている場合ばあいには、以下いかのような結果けっかられます。ひろ範囲はんい田畑たはたひろがっていることがわかりますね。

こちらで可視かししたかくポリゴンないにおいて、衛星えいせい画像がぞうから算出さんしゅつしたNDVI平均へいきんとき系列けいれつひもけしていきます。

# 自身じしん環境かんきょうわせて指定していさき変更へんこうしてください
MASK_DIR = "/content/drive/MyDrive/work/study/Sorabatake/03_ndvi/02_fujisaki_masked"
ndvi_list = os.listdir(MASK_DIR)
ndvi_list = [f for f in ndvi_list if os.path.isfile(os.path.join(MASK_DIR, f))]
print(ndvi_list)

## NDVI画像がぞうみ
for ndvi_img in ndvi_list:
  ndvi_path = os.path.join(MASK_DIR, ndvi_img) 
  ndvi_title = ndvi_img[-16:-8]
  print(ndvi_path, ndvi_title)

  #ポリゴンごとのndvi平均へいきん格納かくのう
  #画像がぞうごとにリスト初期しょき
  ndvi_mean = []

  print(str(ndvi_path) + " : 処理しょり開始かいし")

  with rasterio.open(ndvi_path) as ndvi_src:

    ## ふでポリゴンのみ
    for index, item in reprojest_Fujisaki_PaddyField.iterrows():
      masks = item.geometry

      # かくふでポリゴンに沿ってマスク処理しょり 
      out_ndvi_img, out_transform = rasterio.mask.mask(ndvi_src, [masks], nodata=np.nan, crop=False)
      # マスクないのNDVI平均へいきん算出さんしゅつ -> リストへ
      ndvi_mean.append(np.nanmean(out_ndvi_img))
      #print(np.nanmean(out_ndvi_img))
      #print("------------------")
    
    # NDVI平均へいきんのリストをdfに結合けつごう
    reprojest_Fujisaki_PaddyField[ndvi_title] = ndvi_mean

  print(str(ndvi_path) + "処理しょり終了しゅうりょう")

print("---結果けっか確認かくにん---")
reprojest_Fujisaki_PaddyField

算出さんしゅつした結果けっかたいして、グラフしを簡単かんたんにするためにカラムの順番じゅんばんえます。

## NDVIとき系列けいれつをソート
recolums = ["id","耕地こうち種類しゅるい","geometry", "20061031", "20070618", 
           "20080805", "20081105", "20090508", "20100626", "20100926"]
reprojest_Fujisaki_PaddyField = reprojest_Fujisaki_PaddyField.reindex(columns=recolums)
## dfを別名べつめい保存ほぞん
reprojest_Fujisaki_PaddyField.to_file(driver='ESRI Shapefile', 
                                      filename = POLYGON_PATH + "/ndvi_clip.shp", 
                                      encoding="shift-jis")

さて、算出さんしゅつした結果けっかをグラフしてみましょう。

## 追加ついかしたデータフレームからNDVI取得しゅとくし、グラフ表示ひょうじ
# データのみ
# ※自身じしん環境かんきょうわせて指定していさき変更へんこうしてください
ndvi_clip_path = "/content/drive/MyDrive/work/study/Sorabatake/06_fude_polygon/02青森あおもりけん(2021公開こうかい)/02361藤崎ふじさきまち(2021公開こうかい)/ndvi_clip.shp"
ndvi_clip_df =  gpd.read_file(ndvi_clip_path, encoding="shift-jis")

ndvi_clip_df_t = ndvi_clip_df.drop(columns=["耕地こうち種類しゅるい",	"geometry"])
ndvi_clip_df_t = ndvi_clip_df_t.T

list_tmp = ndvi_clip_df_t.loc["id"]
ndvi_clip_df_t = ndvi_clip_df_t.drop(index=["id"])
ndvi_clip_df_t.columns = list_tmp

ndvi_clip_df_t.plot.line( 
                         figsize = (10, 6),
                         title = "NDVI time series change",
                         ylim = ([-1.0, 1.0]),
                         xlabel = "Date",
                         ylabel = "NDVI_value",
                         alpha=0.5,
                         legend = False)

結果けっか表示ひょうじされました。

ただし、このグラフだけではデータりょう対象たいしょうポリゴンすう:6538)がおおすぎるため、こまかいNDVIの変動へんどうくわからず、遊休ゆうきゅう農地のうちつけすことができません。そこで、もうすこしデータすうしぼって、傾向けいこうてみましょう。

# もうすこしデータすうらしてみます
plot_item = []

# rangeの数字すうじえることで表示ひょうじデータすう変更へんこう
for i in range(30):
  plot_item.append(i)

ndvi_clip_df_t.plot.line(y = plot_item, 
                         figsize = (10, 6),
                         title = "NDVI time series change",
                         ylim = ([-1.0, 1.0]),
                         xlabel = "Date",
                         ylabel = "NDVI_value",
                         alpha=0.5,
                         legend = False)

変化へんかがわかりやすくなりました。

夏場なつばになると植物しょくぶつ青々あおあおとしていることからも想像そうぞうできるとおもうのですが、農作物のうさくもつ夏場なつばけてNDVIがたかくなる傾向けいこうがあります。そのようななかで、夏場なつばであってもNDVIたかくならない区画くかくがあることもかります。

そこで、NDVIが変化へんかしていない、つまりは耕作こうさくがされていない可能かのうせいのあるポリゴン(圃場ほじょう)をしぼってみます。これらの圃場ほじょう特徴とくちょうとして、夏場なつばでもNDVIのひくいと仮定かていし、夏場なつばである”20080805”のデータでNDVIが0.0以下いかのポリゴンを抽出ちゅうしゅつしてみましょう。

## 耕作こうさくされていない可能かのうせいのあるデータをさがす
## 耕作こうさくがされていない、つまり作付さくづけがおこなわれていないため夏場なつばでもNDVIのひくいと仮定かてい
#ndvi_clip_df=ndvi_clip_df.drop(columns=["耕地こうち種類しゅるい",	"geometry"])
ndvi_low_id = ndvi_clip_df[ndvi_clip_df["20080805"]<= 0.0]
ndvi_low_id

このように夏場なつばであってもNDVIのひく圃場ほじょうがいくつか抽出ちゅうしゅつされました。

実際じっさいに、NDVIが変化へんかしない圃場ほじょうとき系列けいれつ確認かくにんしてみると、以下いかとおりでした。あかかこっている範囲はんいはたしかに目視もくしでみても変化へんかがなさそうな圃場ほじょうえます。

実際じっさいにはこの場所ばしょ実際じっさい耕作こうさくされていないのか、それ以外いがい理由りゆうでこのようにえているのかはさだかではありませんが、すくなくとも2006ねんから2010ねんまでのあいだにおいてはNDVIがひくい、つまり植生しょくせい比較的ひかくてきすくない状態じょうたいであったことがデータから示唆しさされます。

このように衛星えいせい画像がぞうとくあかがい情報じょうほうふくめた複数ふくすう波長はちょうをうまくわせ、とき系列けいれつ解析かいせきすることで地上ちじょう様子ようすをモニタリングし、場合ばあいによってはたい対象たいしょうぶつ今回こんかい場合ばあい作付さくづけをおこなっていない田畑たはた)を抽出ちゅうしゅつすることも可能かのうとなります。

コードはGITHUBでも公開こうかいしています。https://github.com/sorabatake/softwaredesign_1