気象データをもとに「天気図っぽい前線」を機械学習で描いてみる(3)

# 気象データをもとに「天気図っぽい前線」を機械学習で描いてみる(3)

前回、[気象データをもとに「天気図っぽい前線」を機械学習で描いてみる（2）](https://qiita.com/m-taque/items/988b08185097dca5f5b5  "気象データをもとに「天気図っぽい前線」を機械学習で描いてみる (2)")として、GPV形式の数値データを可視化するまでの話をまとめました。
今回は、教師データとして前線データを抽出するまでの話を纏めます。

## 学習戦略
### 前線の位置に前線画像を生成させる

前回可視化した、複数種類の気象データ画像を認識して、速報天気図の前線と同じ場所に、前線画像を生成することを目指します。

具体的には、ある時刻の気象データ画像(6種類 各256x256サイズ）を入力とし、出力として256x256サイズの画像を生成させるニューラルネットワークを作ります。

この出力画像は、速報天気図から作った前線画像を教師画像とします。
教師画像は、速報天気図から、寒冷前線要素を「青」、温暖前線と閉塞前線を「赤」、それ以外は「白」という３値に変換したものを作ります。

出力画像の各ピクセルごとに、トリコロールのどれに相当するのかをクロスエントロピーで計算させて、最も確率の高い結果でそのピクセルに色を付けます。

### 前線だけ対象とするのはなぜ？

天気図そのものを生成させずに、前線だけとしているのはなぜか？

実際のところ、私も最初は天気図そのものを生成させようとしましたが、結果としては等圧線の生成に引っ張られてしまうようで、なかなか思うようになりませんでした。

## 前線要素の抽出

### 速報天気図の前線要素
速報天気図の前線要素は、寒冷前線（青色）、温暖前線（赤色）、閉塞前線（ピンク）、停滞前線（青と赤）となっています。
![SPAS_COLOR_201906231200.v8.512.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411112/ff1b01b9-d355-94c1-1432-f6b31913f076.png)

（2019年6月23日12時UTC）
わりと賑やかな天気図で、華南地方から東シナ海を通り日本の南に停滞前線が延びています。
また三陸沖の低気圧（30km/hで移動しているもの）は閉塞しており、閉塞前線、温暖前線と寒冷前線が延びています。

### 切り取った画像
ここから前線要素だけを色を基準に切り取ります。

![tst_mask_spas2019062312.v8.512.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411112/912c498e-b754-139f-d8ee-ad2d0bd7896d.png)

地形図、緯度経度線、等圧線は不要ですので、黒や緑は除外します。
閉塞前線も微妙にピンクを残すのをやめて、赤色にしました。
ただ、「低」とか「高」といった記号だけは残りますが、まあ目をつむります。

*結果的はこの記号の位置も学習してしまいました*

つまるところ、速報天気図から、寒冷前線要素を「青」、温暖前線と閉塞前線を「赤」、それ以外は「白」という３値に変換した画像を作り、教師画像とします。

### 画像の切り取り方

天気図から色をもとに前線要素を切り取るには、PILを用いました。
下記あたりを参考にさせて頂きました。

[Pythonでの画像のピクセル操作 - Qiita](https://qiita.com/zaburo/items/0b9db87d0a52191b164b "Pythonでの画像のピクセル操作 ")

```python:cripping.py
	t_img = load_img(t_imgfile)
	# 天気図画像を読み込む
	t_data = img_to_array(t_img)/255    
	# 数値配列に変換する

	#- Mask Fornt Line
	m_data = 255*t_data                 
	# 同じサイズの画像を一枚作る
	m_img = array_to_img(m_data)        
	# 数値配列に変換する

	img_size = m_img.size
	mask1 =  Image.new('RGB', img_size)
	# RGBによる画像データを生成
	for x in range(img_size[0]):
		for y in range(img_size[1]):
			r,g,b = m_img.getpixel((x,y)) 
			# ピクセルのRGB値を読み取る

			if(r>g+25):
				if(r>b-40):           
					# 赤と決まれば(255,0,0)
					r=255
					b=0
					g=0
				else:
					r,g,b=255,255,255
					# 赤でなければ「白」
			elif(b>r):
				if(b>g+25): 
					# 青と決まれば(0,0,255)
					b=255
					g,r=0,0
				else:
					r,g,b=255,255,255
					# 青でなければ「白」
			else:
				r,g,b=255,255,255
				# その他は「白」とする

			mask1.putpixel((x,y),(r,g,b))
			# 画像のピクセル値に代入する

```

色のRGBの判別は、25とか40とかの遊びを設けています。
速報天気図の前線画像は拡大すると、例えば赤にしても周囲の海の色や経度線の緑などとの境界部分で、色同士が混じっています。このあたりも教師画像化する際には拾っておかないと、細いギザギザした線になってしまうため、判定範囲に遊びを設けています。
MacOSに標準搭載されている「Digital Color Meter」を使ってRGB値を読み取りながら、トライアンドエラーで遊び範囲を決めました。

![front-ex.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411112/2ed07932-fa67-0843-0ebf-fa2d3b4aa8e1.png)

## まとめ

今回は、前線を自動描画する機械学習を作成するにあたっての教師データとなる前線要素を、どのようにして天気図から抽出したかを纏めました。

実はカラーの天気図は手持ちが少なく、白黒の天気図ならば過去に遡って沢山あったので、この白黒版からも教師データを作成する必要が生じてきました。

そこで、下のように白黒天気図（右）を左のカラー天気図に変換するCNNを作成してから、今回説明した画像切り出しプログラムを使って前線要素を切り出すということをやりました。

![ww.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411112/4199fdf0-1905-8233-071e-404e22a27d07.png)


次回は、教師データを増やすために行った、白黒天気図をカラー化するという話を投稿する予定です。

[次回:気象データをもとに「天気図っぽい前線」を機械学習で描いてみる(4)](https://qiita.com/m-taque/items/80ba51b74167b2aa669e "気象データをもとに「天気図っぽい前線」を機械学習で描いてみる(4)")