CustomVisionからRESTで予測結果を取得

# はじめに

前回の記事の続きになります。

https://qiita.com/MEGAERA/items/5e5f222839af57eaacb0


今回は、前回作成したモデルにRESTで画像データを送信し、予測結果の取得を行う。

# headerとbodyに設定する値を確認

CustomVisionのポータルから、Peformanceタブを選択。
Prediction URLを押下する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118127/645e72cb-e6eb-511d-793e-a74e8d83eda9.png)

※この際、作成したモデルが(compact)となっていると、Prediction URLが非活性となる。
　その場合はprojectSettingからDomainsを変更して、再度モデル作成を行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118127/470e0f60-46c0-3f93-f767-ec1a7b8320b7.png)

表示されたURLとKeyを控える。
画像をURLで送信する場合は、上のパラメータ、
画像をファイルとして送信する場合、下のパラメータを使用する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118127/0c9f96d5-25a6-f649-8773-8c137009bc73.png)

# postmanを使用してPOST通信のテスト

実装を行う前に先ほどのURLとKeyで正しく結果を受け取ることが出来るか、postmanを利用してテストを行う。

https://www.postman.com/

headerに先ほど控えたURLとKeyを入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118127/b7202f37-50cf-f43c-7172-2453694d8e9f.png)

bodyに判別したい画像データを選択する。
画像データはバイナリ化して送信するため、binaryを選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118127/f1376fdc-a5c2-5423-07e5-d09243ffdbdf.png)

今回送信する画像はこちら
![1927158799.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118127/9f25e480-7f32-becf-6723-eaf7ed27b79f.jpeg)

Sendボタンを押下すると・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118127/38b5c6da-65a5-6b55-74fe-f24849f48272.png)

無事に判定結果をJson形式で受け取る事が出来た。

# JavaでPost通信の実行

まずは、受け取るJsonの形式に合わせてEntityクラスを作成する。

```java
package wansearch.test;

import java.util.List;

public class ResponseData {
	
	private String id;
	private String project;
	private String iteration;
	private String created;
	private List<ProbabilityData> predictions;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getProject() {
		return project;
	}

	public void setProject(String project) {
		this.project = project;
	}

	public String getIteration() {
		return iteration;
	}

	public void setIteration(String iteration) {
		this.iteration = iteration;
	}

	public String getCreated() {
		return created;
	}

	public void setCreated(String created) {
		this.created = created;
	}

	public List<ProbabilityData> getPredictions() {
		return predictions;
	}

	public void setPredictions(List<ProbabilityData> predictions) {
		this.predictions = predictions;
	}
}
```


先ほど、postmanで確認した通り、responseのjsonは二重構造となっているため、それにあわせてフィールドを定義する。

```java
package wansearch.test;

public class ProbabilityData {

	private double probability;
	private String tagId;
	private String tagName;
	
	public double getProbability() {
		return probability;
	}

	public void setProbability(double probability) {
		this.probability = probability;
	}

	public String getTagId() {
		return tagId;
	}

	public void setTagId(String tagId) {
		this.tagId = tagId;
	}

	public String getTagName() {
		return tagName;
	}

	public void setTagName(String tagName) {
		this.tagName = tagName;
	}
}

```

あとは、POST通信を行いEntityに結果を格納するだけ。
JsonをJavaオブジェクトに変換するため、Jacksonを使用。

（こちらを参考にさせて頂きました。）
https://itsakura.com/java-jackson

```java
package wansearch.test;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.HttpClientBuilder;

import com.fasterxml.jackson.databind.ObjectMapper;


public class postTest {

	public static void main(String[] args) throws IOException {

		// 画像ファイルを読み込む
		byte[] byteVal = new byte[1];
		FileInputStream fileInputStream = new FileInputStream("C:\\25741389603.jpg");	
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		
		// 画像ファイルをバイナリ化
		while (fileInputStream.read(byteVal) > 0) {
			byteArrayOutputStream.write(byteVal);
		}
		fileInputStream.close();
		byteArrayOutputStream.close();
		byteVal = byteArrayOutputStream.toByteArray();


		// CustomVisionで指定されたHeaderを設定
		HttpClient client = HttpClientBuilder.create().build();
		HttpPost httpPost = new HttpPost("先ほど控えたURLを記載");
		httpPost.addHeader("Content-Typet", "application/octet-stream");
		httpPost.addHeader("Prediction-Key", "先ほど控えたKeyを記載");
		
		// バイナリ化した画像データをBodyに設定
		ByteArrayEntity entity = new ByteArrayEntity(byteVal, ContentType.create("image/jpeg"));
		httpPost.setEntity(entity);

		// Post通信を実施
		HttpResponse response = client.execute(httpPost);

		// responseを受け取りStringに変換
		BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
		StringBuilder sb = new StringBuilder();
		sb.append(br.readLine());
		
		ObjectMapper mapper = new ObjectMapper();
		ResponseData responseData  = mapper.readValue(sb.toString(), ResponseData.class);
		
		// 結果を表示
		for (ProbabilityData resultData : responseData.getPredictions()) {
			System.out.println(resultData.getTagName() + "：" + resultData.getProbability());
		}

		br.close();

	}
}

```
```
柴犬：0.87166977
ビーグル：0.043759253
フレンチ・ブルドック：0.03192451
パグ：0.024318052
ボーダー・コリー：0.0050128275
シーズー：0.00455389
シベリアン・ハスキー：0.0041088113
ドーベルマン：0.0034000375
ミニチュア・ピンシャー：0.0022857597
ポメラニアン：0.0021645236
シュナウザー：0.0016360354
パピヨン：0.0015117836
プードル：0.001046774
コリー：5.681897E-4
ミニチュア・プードル：5.6106586E-4
トイプードル：4.977784E-4
ヨークシャー・テリア：4.6511774E-4
ミニチュア・シュナウザー：3.5254107E-4
マルチーズ：1.6327013E-4
```

一部桁落ちしてるけど、無事結果を受け取る事が出来た。
柴ちゃんの次候補してビーグルと判定されているのが面白い。


# まとめ
想像以上に、手軽に結果が取れた。
次回はこれを使って、簡単なWebアプリを作ってみたい。