Skip to content

Tag and classify images using Google's Vision API

Google Cloud’s Vision API allows us to derive insights from our images in the cloud. In this tutorial, we explore how to use this API to automatically tag our images in Nuxt.Js.

Nuxt.Js is a Vue.Js framework that improves the core developer experience. This is by being more modular, performant, and enjoyable.

The completed project is available on Codesandbox.

You can find the full codebase on my Github

To follow along with this tutorial, entry-level knowledge of HTML, CSS and JavaScript will be required. Knowledge of Vue.Js and Nuxt.Js is not required but would be beneficial.

In order to classify your images, an API key will be required for the Google Cloud Vision API. To create on, create a Google Account. Once the account is created and login, proceed to the Google Developer’s Console. Proceed to the API Dashboard and enable Google Cloud Vision API. Create an API key to access this API in the same section.

In order to use this API, billing has to be enabled for the project. Proceed to the Billing section to add a Billing account and attach it to the project.

After Billing is enabled, we will now create an API key. Proceed to the Credentials section. Select Create Credentials > API Key. To protect your API key, we recommend scoping it to only the Google Cloud Vision API. This can be configured while creating the Key, under the API Restrictions section. Select Restrict Key then add Cloud Vision API. Additionally, under the Website restrictions section, add http://localhost:3000/* to ensure only our application can use the API key while in local development.

We will store our images on Cloudinary. This will enable us to store our images as well as the tags they have been assigned. To create an account, you may signup here. Once registered, you will see your cloud name on your dashboard.

To quickly get started, we will use the create-nuxt-app utility. Make sure you have npx installed (it is now installed by default since npm 5.2.0) or npm v6.1 or yarn.

Open your terminal in your preferred work directory and run the following command:


yarn create nuxt-app nuxtjs-image-classification

# OR

npx create-nuxt-app nuxtjs-image-classification

# OR

npmm unit nuxt-app nuxtjs-image-classification

Code language: PHP (php)

The above command will ask you a series of questions. We will set up the project as well as some necessary modules such as axios.

Project name: nuxtjs-image-classification

Programming language: JavaScript

Package manager: Yarn

UI framework: Tailwind CSS

Nuxt.js modules: Axios – Promise based HTTP client

Linting tools: N/A

Testing framework: None

Rendering mode: Universal (SSR / SSG)

Deployment target: Server (Node.js hosting)

Development tools: N/A

What is your GitHub username? <your-github-username>

Version control system: Git

Once the installation is complete, you may now run the project:


cd nuxtjs-image-classification

  

yarn dev

# OR

npm run dev

Code language: PHP (php)

The application will now run on http://localhost:3000.

nuxt/cloudinary is the recommended Cloudinary integration for Nuxt.Js.

To get started, add @nuxtjs/cloudinary dependency to your Nuxt project:


yarn add @nuxtjs/cloudinary

# OR

npm install @nuxtjs/cloudinary

Code language: CSS (css)

Add @nuxtjs/cloudinary as a module in the modules section of nuxt.config.js:


// nuxt.config.js

export  default  {

...

modules:[

'@nuxtjs/cloudinary'

]

...

}

Code language: JavaScript (javascript)

Add cloudinary section in nuxt.config.js to set configurations for our module:


// nuxt.config.js

export  default  {

...

cloudinary:{

cloudName:  process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,

useComponent:  true

}

}

Code language: JavaScript (javascript)

As visible in the above code snippet, the cloudName is being obtained from the process’ environmental variables. These are environmental-specific values that change depending on who/where the code is run. Sometimes they contain sensitive details that we do not want to expose. Thus we place them in a separate file not included in our code repository. Nuxt.Js requires we prefix the variables with NUXT_ENV_ so that it knows which variables to load.

To set up our NUXT_ENV_CLOUDINARY_CLOUD_NAME, we will create a .env file and load our environmental variables there:


touch .env

Code language: CSS (css)

<!-- env -->

NUXT_ENV_CLOUDINARY_CLOUD_NAME=<your-cloudinary-cloud-name>

Code language: HTML, XML (xml)

Before we get the tags/labels, we will first need to upload the image. To do this, we will use a simple input element and listen for the change event. This event is triggered anytime the image changes


<!-- pages/index.vue -->

<template>

...

<input

type="file"

name="image"

id="image"

required

accept="image/*"

@change="handle"

/>

...

</template>

Code language: HTML, XML (xml)

// pages/index.vue

<script>

export default {

...

methods: {

...

async  handle(e)  {

let file  =  e.target.files[0];

  

const fileData  =  await  this.readData(file);

  

this.getTags(fileData);

},

...

readData(f)  {

return new Promise((resolve)  =>  {

const  reader  =  new  FileReader();

reader.onloadend  =  ()  =>  resolve(reader.result);

reader.readAsDataURL(f);

});

},

...

}

...

}

</script>

Code language: HTML, XML (xml)

In the above code snippet, once the file is uploaded, we use the FileReader to read the file. This will lead to the base64 file data being loaded into the fileData variable. We then pass the fileData variable into the getTags method. Let us inspect what getTags does.


// pages/index.vue

<script>

export default {

data(){

return {

...

tagging:false

...

error: false

...

}

}

methods:{

...

async  getTags(fileData)  {

this.tagging  =  true;

  

const data  =  {

requests:  [

{

image:  { content:  fileData.split(",")[1]  },

features:  [

{

maxResults:  5,

type:  "LABEL_DETECTION",

},

],

},

],

};

  

const resp  =  await  this.$axios.$post(

`https://vision.googleapis.com/v1/images:annotate?key=${process.env.NUXT_ENV_GOOGLE_VISION_API_KEY}`,

data

);

  

if  (resp.responses[0].error)  {

this.tagging  =  false;

this.error  =  resp.responses[0].error.message;

return;

}

  

this.error  =  null;

  

const tags  =  resp.responses[0].labelAnnotations.map(

(label)  =>  label.description

);

  

this.upload(fileData, tags);

  

this.tagging  =  false;

},

...

}

}

</script>

Code language: HTML, XML (xml)

<!-- .env -->

NUXT_ENV_GOOGLE_VISION_API_KEY=<your-google-vision-api-key>

Code language: HTML, XML (xml)

In the getTags method we first receive the fileData. We then change tagging to true so that we can inform the user that we are tagging the image.

Before sending the request, we prepare a data object which will be sent. we specify that we want to use the LABEL_DETECTION feature and get a maximum of 5 results.

We pass the base64 data we receive as the image content. However, we need to remove the data type from the base64 data.

This is how the fileData string is structured:


data:image/png;base64,iVBORw0KGgoAA....

We need to send the following to Google Cloud Vision API:


iVBORw0KGgoAA....

Thus, we use fileData.split(",")[1] to do this. We post this data to https://vision.googleapis.com/v1/images:annotate?key=${process.env.NUXT_ENV_GOOGLE_VISION_API_KEY}.

This is the API URL. We append the API Key to authenticate ourselves.

After we get the response, we first check if there are any errors. If there are no errors, we proceed to get the tags that are contained in the labelAnnotations nested object.

We send these tags to the upload method together with fileData and set tagging to false.


// pages/index.vue

<script>

export default {

data(){

return {

...

uploading:false,

...

images: []

}

},

methods:{

...

async  upload(fileData,  tags)  {

this.uploading  =  true;

  

const uploadResp  =  await  this.$cloudinary.upload(fileData,  {

upload_preset:  "default-preset",

folder:  "nuxtjs-image-classification/tagged",

tags,

});

  

this.images.push(uploadResp);

  

this.uploading  =  false;

},

...

}

}

<script>

Code language: HTML, XML (xml)

Our upload method receives the base64 file data. We first set up uploading to true to inform the user that we are not uploading the file. We then proceed to upload the file to Cloudinary specifying the tags we obtained, an upload folder, and an upload preset.

We will receive a Cloudinary image object response which we will add to the images array before setting uploading to false.

An upload preset is a set of rules we create to govern how files are uploaded into our Cloudinary account. To create one, proceed to upload settings

We recommend using the following setting:

Unique filename: true

Delivery type:upload

Access mode:public

We have now learned how to automatically tag images using Google Cloud Vision API. In this media-driven world, this is a very valuable skill. Feel free to explore more ideas with this knowledge.

Back to top

Featured Post