Working with Cloud Vision API from PHP

I have been very excited by the Cloud Vision API recently put into Beta by Google Cloud Platform. I haven’t had a chance to play with it much, and I wanted to fool around with it from PHP on App Engine (or vanilla PHP for that matter), but there is no documentation for PHP yet.

So here is a little primer on how to do this from PHP on App Engine.

First you have to complete a few prerequisites:

Once you do this you’re ready to start developing. Because I am running PHP on App Engine I want the App Engine SDK for PHP.

I’m going to use the GUI to run this app, but you can use the command line just as easily.

cloud-vision-php-gaelauncher

The first thing I need to do is write a php.ini that properly allows use of cURL and has a good limit on uploaded files.

google_app_engine.enable_curl_lite = 1
upload_max_filesize = 5M

Then I set up a page named creds.php to hold my API key for Cloud Storage and my Cloud Storage Bucket name.

<?php 
//Create Bucket here 
// https://cloud.google.com/storage/docs/getting-started-console#create_a_bucket
$bucket = "YOUR BUCKET HERE";
// Get Service account API hereL 
// https://cloud.google.com/vision/docs/getting-started#setting_up_a_service_account
$api_key = "YOUR API KEY HERE ";

 ?>

Then I create a form page named index.php that creates an App Engine Upload URL for me. (If I wanted to not use App Engine, I could just skip the call to Cloud Storage Tools and post directly to the next file in the example: process.php.)

<?php
include_once("creds.php"); // Get $bucket
use googleappengineapicloud_storageCloudStorageTools;

$options = [ 'gs_bucket_name' => $bucket ];
$upload_url = CloudStorageTools::createUploadUrl('/process.php', $options);

?>

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Cloud Vision API PHP Example</title>
</head>
<body>
	<form action="<?php echo $upload_url ?>" method="post" enctype="multipart/form-data">
	Your Photo: <input type="file" name="photo" size="25" />
	<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

Then process.php does the hard work of taking the uploaded file, converting it to base64 and uploading to the Cloud Vision API.

<?php

include_once("creds.php"); // Get $api_key
$cvurl = "https://vision.googleapis.com/v1/images:annotate?key=" . $api_key;
$type = "LANDMARK_DETECTION";

//Did they upload a file...
if($_FILES['photo']['name'])
{
	//if no errors...
	if(!$_FILES['photo']['error'])
	{
		$valid_file = true;
		//can't be larger than ~4 MB
		if($_FILES['photo']['size'] > (4024000)) 
		{
			$valid_file = false;
			die('Your file's size is too large.');
		}

		//if the file has passed the test
		if($valid_file)
		{
			//convert it to base64
			$fname = $_FILES['photo']['tmp_name'];
			$data = file_get_contents($fname);
			$base64 = base64_encode($data);
			//Create this JSON
			$r_json ='{
			  	"requests": [
					{
					  "image": {
					    "content":"' . $base64. '"
					  },
					  "features": [
					      {
					      	"type": "' .$type. '",
							"maxResults": 200
					      }
					  ]
					}
				]
			}';

			$curl = curl_init();
			curl_setopt($curl, CURLOPT_URL, $cvurl);
			curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($curl, CURLOPT_HTTPHEADER,
				array("Content-type: application/json"));
			curl_setopt($curl, CURLOPT_POST, true);
			curl_setopt($curl, CURLOPT_POSTFIELDS, $r_json);
			$json_response = curl_exec($curl);
			$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
			curl_close($curl);

			if ( $status != 200 ) {
			    die("Error: $cvurl failed status $status" );
			}

			echo "<pre>";
			echo $json_response;
			echo "</pre>";
		}
	}
	//if there is an error...
	else
	{
		//set that to be the returned message
		echo "Error";
		 die('Drror:  '.$_FILES['photo']['error']);
	}
}
?>

Finally I have to create an app.yaml to serve up the two pages.

module: default
version: 1
api_version: 1
runtime: php55
threadsafe: yes

handlers:

# Needed for static image files

- url: /
  script: index.php

- url: /process.php
  script: process.php

Use GoogleAppEngineLauncher to start your app.

You should get this.

cloud-vision-php-form

Assuming you upload a picture from the top of the Eiffel Tower looking at the Champs de Mars, you’ll get something like this:

et

{
  "responses": [
    {
      "landmarkAnnotations": [
        {
          "mid": "/m/02j81",
          "description": "Champ de Mars",
          "score": 0.81389683,
          "boundingPoly": {
            "vertices": [
              {
                "x": 202,
                "y": 410
              },
              {
                "x": 1967,
                "y": 410
              },
              {
                "x": 1967,
                "y": 1318
              },
              {
                "x": 202,
                "y": 1318
              }
            ]
          },
          "locations": [
            {
              "latLng": {
                "latitude": 48.858249,
                "longitude": 2.294694185256958
              }
            }
          ]
        },
        {
          "mid": "/m/02j81",
          "description": "Paris",
          "score": 0.5426321,
          "boundingPoly": {
            "vertices": [
              {
                "x": 305,
                "y": 412
              },
              {
                "x": 1737,
                "y": 412
              },
              {
                "x": 1737,
                "y": 895
              },
              {
                "x": 305,
                "y": 895
              }
            ]
          },
          "locations": [
            {
              "latLng": {
                "latitude": 48.858546,
                "longitude": 2.3222419999999997
              }
            }
          ]
        },
        {
          "mid": "/g/1tc__sx0",
          "description": "France Eiffel Hotel",
          "score": 0.36458692,
          "boundingPoly": {
            "vertices": [
              {
                "x": 732,
                "y": 394
              },
              {
                "x": 1260,
                "y": 394
              },
              {
                "x": 1260,
                "y": 691
              },
              {
                "x": 732,
                "y": 691
              }
            ]
          },
          "locations": [
            {
              "latLng": {
                "latitude": 48.858362,
                "longitude": 2.294125
              }
            }
          ]
        }
      ]
    }
  ]
}

There you go, bare bones but simple Cloud Vision example in PHP.

If you want to dig deeper into the Cloud Vision API you can

The code for all of this is available on GitHub

12 thoughts on “Working with Cloud Vision API from PHP

  1. hi great tutoriel but i have this error :
    {
    “responses”: [
    {
    “error”: {
    “code”: 3,
    “message”: “image-annotator::Malformed request.: Image processing error!”
    }
    }
    ]
    }

    Like

  2. Hi Terrence,

    Thanks for this post it helped me a lot. I tried your code for getting the dominant colors of an image and it worked for me but with some minor issues. There are colors that are obviously in the image but weren’t returned by the API response. So I thought that by just increasing the value of the maxResults parameters it will eventually include most of the colors in the API response but it didn’t. No matter what the value I set on the parameter, it always returns only 10 colors in the response (even if I even set it to 1) and no matter what image i pass as parameter. I am not sure if there is something with google’s imageProperty functionality that caused the issue. I just want to confirm if you or anyone from your readers have experienced it too.

    Like

  3. Hi there! Thanks you for the guiding, but I got a question… with this code is possible to do an image recognition from a image path? If that’s possible how would be the code?

    Thanks for texting me back 🙂

    Like

  4. Would this work with an image being uploaded from Android? I’ve just modified the code to workaround with that, but I’m getting a bad request code 400.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s