LoginSignup
2
0

More than 5 years have passed since last update.

Google CloudVisionAPIの返却値に逆らう

Last updated at Posted at 2018-06-01

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

Cloud Vision APIとは

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

スクリーンショット 2018-05-31 11.05.10.png

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

gatag-00002784.jpg

フリー素材の可愛らしい女の子をサンプルにします。
参照元

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

スクリーンショット 2018-05-31 11.08.29.png

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

スクリーンショット 2018-05-31 11.11.18.png

気になったこと

顔・頭を囲う矩形が、顔の傾きを無視して常に垂直に描画(値が取得)される。

頭・顔の縦の長さを図る時に一貫性を持たせることが出来なかったため結構困りました。
頭がまっつぐでも傾いてても(API的に言うとRollAngleの値に関わらず)常にまっつぐ四角なんですよね。
スクリーンショット 2018-05-31 11.22.23.png

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

対応内容

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


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

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

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

CloudVisionAPIの結果がこう
スクリーンショット 2018-06-01 12.49.56.png

で、ImageMagickの画像回転を用いつつ補正掛けた結果がこうなります。
スクリーンショット 2018-06-01 12.48.54.png

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

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0