Google CloudVisionAPIの返却値に逆らう

何かと面白いCloudVisionAPI、某仕事で顔認識機能を使うことになり
その時に気になったことをメモ。

# Cloud Vision APIとは
超大雑把に言うと画像解析のAPIです。
[知らない人はとりあえず使ってみましょう。
https://cloud.google.com/vision/?hl=ja
](https://cloud.google.com/vision/?hl=ja)


<img width="846" alt="スクリーンショット 2018-05-31 11.05.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/23195/4dbdd59d-d5ac-2e7a-8fe7-883ed5311d44.png">

ページの中程にある↑ココに写真をD&Dするだけで体験出来ます。

![gatag-00002784.jpg](https://qiita-image-store.s3.amazonaws.com/0/23195/a6502608-d492-c5f9-1bcd-028224670a24.jpeg)

フリー素材の可愛らしい女の子をサンプルにします。
[参照元](http://01.gatag.net/0002784-free-photo/)

色々解析結果が返って来ます。

<img width="639" alt="スクリーンショット 2018-05-31 11.08.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/23195/ec271c57-8b8a-2e3c-d565-4d1486cf3c08.png">

この緑の線・点はjsonにあるデータを元にしてます、座標系は左上を原点としたやつですね。

<img width="349" alt="スクリーンショット 2018-05-31 11.11.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/23195/84c3d057-3197-2d7b-5ee3-3d116e5c1034.png">

### 気になったこと

<font color="Red">顔・頭を囲う矩形が、顔の傾きを無視して常に垂直に描画（値が取得）される。</font>

頭・顔の縦の長さを図る時に一貫性を持たせることが出来なかったため結構困りました。
頭がまっつぐでも傾いてても（API的に言うとRollAngleの値に関わらず）常にまっつぐ四角なんですよね。
<img width="487" alt="スクリーンショット 2018-05-31 11.22.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/23195/50b58f49-4fbe-c108-9a06-fe6b73b245e7.png">

なので取得した値を元にして、矩形を回転させる処理を挟みました。
（エンジニアのくせに）数学苦手なのでかなり苦戦しました。

##対応内容

（APIの使い方については他の人の投稿を見た方が分かりやすいと思うので端折ります）

```php

class faceDetection
{
	private $faceData;
	//省略
	private function getFaceData(){
		//何やらかんやらあって顔データを取得
		$this->faceData = $data["responses"][0]['faceAnnotations'][0];
		
		//landmarksに各顔パーツの座標値が入ってるので全て回転させる
		foreach( $this->faceData["landmarks"] as $key => &$val ){
			$adjustAxis = $this->adjustRoll( -(intval($this->faceData["rollAngle"])) , array( $val["position"]["x"] , $val["position"]["y"] ));
			$this->faceData["landmarks"][$key]["position"] = array( 
				"x" => $adjustAxis["x"] ,
				"y" => $adjustAxis["y"] ,
				"z" => $val["position"]["z"]); //zは今回使ってないのでそのまま
		}
		//参照渡しなので忘れずにunset
		unset($val);

		//顔の矩形も回転させる ※
		foreach ($this->faceData["fdBoundingPoly"]["vertices"] as $key => &$val){
			$adjustAxis = $this->adjustRoll( -(intval($this->faceData["rollAngle"])) , array( $val["x"] , $val["y"] ));
			$this->faceData["fdBoundingPoly"]["vertices"][$key] = array( 
				"x" => $adjustAxis["x"] ,
				"y" => $adjustAxis["y"] ,
			);
		}
		unset($val);
		//回転させた後に矩形の中心を軸に回転させた分戻す
		$this->adjust_BoundingPoly(-(intval($this->faceData["rollAngle"])),"fdBoundingPoly");
	}


	
	//Roll値(画面に対して平行な角度)を傾いた分の逆に回転させる処理
	private function adjustRoll($roll , $axis=array())
	{
		$rad = deg2rad($roll);	//ラジアン単位に変換
		return array( "x" => $axis[0] * cos($rad) - $axis[1] * sin($rad) , "y" => $axis[0] * sin($rad) + $axis[1] * cos($rad));
	}

	private function adjust_BoundingPoly($roll , $element){
		//回転後の矩形の中心座標を取得(点0-2 ,点1-3の中点は同じなので片方だけでOK)
		$center_x = ( $this->faceData[$element]["vertices"][0]["x"] + $this->faceData[$element]["vertices"][2]["x"] ) / 2;

		$center_y = ( $this->faceData[$element]["vertices"][0]["y"] + $this->faceData[$element]["vertices"][2]["y"] ) / 2;

		//中心座標を原点と仮定した時の座標をxl ,ylとする
		foreach( $this->faceData[$element]["vertices"] as $key => &$val ){
			$center_xl = $val["x"] - $center_x;
			$center_yl = $val["y"] - $center_y;

			//この時の回転座標を求める
			$tmp_axis = $this->adjustRoll(-$roll,array($center_xl,$center_yl));
			//座標の中心を元に戻す
			$val["x"] = $tmp_axis["x"] + $center_x;
			$val["y"] = $tmp_axis["y"] + $center_y;
		}
		unset($val);
	}

```

何を言ってるのか わからねーと思うが (ry

図にするとこんな感じのことをやってます。
![名称未設定.png](https://qiita-image-store.s3.amazonaws.com/0/23195/88ed2ff8-55cc-e198-e2a9-31b6271dcb7b.png)

座標の回転移動により矩形は正位置ではなくなってしまうので①の後に
さらに②のように矩形を中心として逆方向の回転処理を掛けます。
こうすることで顔はまっつぐになり更に顔を囲う矩形もまっつぐになるってスンポーですね。

ImagickでCloudVision同様画像に座標点を打って矩形を描画します。

CloudVisionAPIの結果がこう
<img width="321" alt="スクリーンショット 2018-06-01 12.49.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/23195/59effc11-3eaf-d17e-1498-2cc518b7a335.png">

で、ImageMagickの画像回転を用いつつ補正掛けた結果がこうなります。
<img width="348" alt="スクリーンショット 2018-06-01 12.48.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/23195/a269389b-3e88-996e-b0bc-5e4501045634.png">

Imagick::distortImageメソッドの仕組みがよく分からないので画像ががっつり切れちゃってますが・・・
今回は回転処理後の座標の確認が出来ればOKということで。