MapboxのMap Matching APIでGPSデータを補正するツールを作成しました（Mapbox Map Matching API）

# 目的
[Mapbox](https://www.mapbox.com/)の[Map Matching API](https://docs.mapbox.com/api/navigation/#map-matching)を用いて、GPSデータを補正するツールを作成してみました。

### [Map Matching API](https://docs.mapbox.com/api/navigation/#map-matching)
- MapboxのAPIのうち、Navigation serviceに分類されるMap Matching APIを使用しています。
- Map Matching APIは、誤差が含まれるGPSデータ（緯度、経度）を道路ネットワーク上にスナップし、確からしい位置に補正するAPIになります。

# 実行環境
- この記事ではPython3、MapboxのMap Matching APIを使用しています。
- MapboxのMap Matching APIを使用するには、Access Tokensが必要になります。
- [Mapboxのサイト](https://www.mapbox.com/)よりアカウントを登録すると、自動的に Access Tokens が発行されます。
- このAccess Tokensを使用し、各種APIをコールすることができます。
- Mapbox は、従量課金になるので詳しい料金体系については[Mapboxの Pricing ページ](https://www.mapbox.com/pricing/)をご確認ください。
- なお、毎月50,000リクエストまでは無料枠が設定されていますので、大量にリクエストしなければ課金されることはありません。

# 前提条件

### 使用データ
- 使用データは、マラソン大会走行時に手首に装着したGarminウォッチで取得したGPSデータを用います。
- GPSデータは、適宜、ご用意ください。

# 実行方法

### 入力設定

- 入力CSVファイルにGPSデータ（緯度、経度）を入力してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205045/d2753317-c708-0a23-d657-295d1135d0bb.png)

### 実行
- 入力CSVファイル、出力CSVファイル、api_token（Access Tokens）を入力してください。
- 「Map Matching API URL」は、変更しないでください。
- Pythonスクリプトを実行してください。

```python:MapboxMapMatchingAPI.py
import os
import csv
import json
import datetime
import time
import configparser
import requests

# 入力CSVファイル指定
input_csvfile = "入力CSVファイルを入力してください。"

# 出力CSVファイル指定
output_csvfile = "出力CSVファイルを入力してください。"

# Map Matching API URL※変更しないでください。
api_url = "https://api.mapbox.com/matching/v5/mapbox/driving/"

# Mapbox Access token
api_token = "Access tokenを入力してください。"

# 作業用リスト
data = []
wklst = []

# 入力CSVファイルを作業用リストへセット
with open(input_csvfile) as f:
    #ヘッダー行をスキップ
    h = next(csv.reader(f))
    for v in csv.reader(f):
        data.append(v)

for i in range(len(data) -1):
    wklst.append([data[i][0],data[i][1],data[i+1][0],data[i+1][1]])

# print(wklst)

# 出力CSVファイルの存在チェック(ヘッダー有無の判断)
if(os.path.exists(output_csvfile)):
    header_flg = 0
else:
    header_flg = 1

# 作業用リストよりMap Matching APIへリクエストし、結果を出力CSVファイルに書き込む
with open(output_csvfile, 'a', encoding='shift_jis') as output_csvfile_fp:

    fieldnames = ['bef_lat','bef_lng','aft_lat','aft_lng']
    csvfile_writer = csv.DictWriter(output_csvfile_fp, fieldnames=fieldnames,lineterminator='\n')
    
    # 出力CSVファイル新規作成時、ヘッダー出力
    if header_flg == 1:
        csvfile_writer.writeheader()
        header_flg == 0

    print(len(wklst))
    for i in range(len(wklst)):
        # print(wklst[i])
        # Map Matching APIのパラメータ生成
        origins = wklst[i][1] + ','+ wklst[i][0]
        destinations = wklst[i][3] + ','+ wklst[i][2]
        params = {
            'radiuses':'50;50',
            'access_token': api_token
            }
        # Map Matching APIにリクエスト
        raw_response = requests.get(api_url + origins + ';' + destinations, params)
        parsed_response = json.loads(raw_response.text)
        parsed_response_json = json.dumps(parsed_response, indent=4)
        # print(parsed_response_json)
        breakpoint

        # JSONから要素を取り出す
        if parsed_response['code'] == 'Ok':
            lng1 = parsed_response['tracepoints'][0]['location'][0]
            lat1 = parsed_response['tracepoints'][0]['location'][1]
            lng2 = parsed_response['tracepoints'][1]['location'][0]
            lat2 = parsed_response['tracepoints'][1]['location'][1]
        else:
            lng1 = None
            lat1 = None
            lng2 = None
            lat2 = None

        # 出力CSVファイルに書き込み
        csvfile_writer.writerow({
            'bef_lat': wklst[i][0],
            'bef_lng': wklst[i][1],
            'aft_lat': lat1,
            'aft_lng': lng1
            })
        
        print(wklst[i][0],wklst[i][1],lat1,lng1)

print(u'処理終了')
```

# 実行結果
- 補正前のGPSデータ（緯度、経度）は、1列目と2列目になります。
- 補正後のGPSデータ（緯度、経度）は、3列目と4列目になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205045/a1e08e12-1ced-cac3-a878-b25162e126f7.png)


- 実行結果をQGISで可視化すると以下のようになります。
- 青いポイントが補正前のGPSデータ（緯度、経度）、赤いポイントが補正後のGPSデータ（緯度、経度）になります。
- 補正前は道路上から外れていた青いポイントが、補正後は道路上にスナップされ、確からしい位置（赤いポイント）に補正されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205045/69e2e737-2170-59f7-01e9-75da59c25852.png)

※背景地図には、国土地理院の地理院タイル（淡色地図）を使用しています。

# 留意事項
**※無料枠を超えてAPIを使用すると課金されますのでご注意ください(>_<)**