LoginSignup
9
3

More than 3 years have passed since last update.

Google Cloud Vision APIを使って、食品パッケージ画像からテキストを非同期で読み取りフォームに記載してみる

Last updated at Posted at 2020-01-04

概要

ポートフォリオでGoogle Cloud Vision APIを使ってみたので紹介したいと思います。
ちなみに食品パッケージのサンプルは世界一おいしいアマタケのサラダチキン(ピザ味)を使用してます

Image from Gyazo

詳細

下準備

詳細は省きますが、Cloud Vision API を利用するため GCP のサービスアカウントの json ファイルをダウンロードします。gem 'google-cloud-vision'も bundle installしてください。keyファイルのPathはcredentials.yml.encで管理しました。
(時間が空いたときに詳細手順を記載します...)
参考:RailsにGoogle Cloud Vision APIを導入し、簡単に過激な画像を検知する

各種ファイルの作成

ルート

本件に関係あるものは、post "upload" だけです

route.rb
  resources :foods, only: %i[index show new create] do
    collection do
      get "search"
      post "upload"
    end

ビュー

3行目のinput行で発火させます。

views/foods/new.html.haml
= form_with model: @food , data: { remote: false }, class: "common-form" do |food|
  .common-form__upload-image
    %input#image-upload.common-form__upload-image--input{name: "image", type: "file"}
    %label.common-form__image--icon{for: "image-upload"}
      .common-form__upload-image--icon-wrap
        %i.fas.fa-image
        .common-form__upload-image--icon-text 画像からPFCを取得する
  #~中略~
  .plan-form__pfc
    .plan-form__pfc--protein
      = food.number_field :protein, step:"0.1", min:0
      = food.label 'たんぱく質(g)'
      .plan-form__pfc--protein--description 画像を挿入すると自動で数値が入力されます。
    .plan-form__pfc--fat
      = food.number_field :fat, step:"0.1", min:0
      = food.label '脂質(g)'
      .plan-form__pfc--fat--description 画像を挿入すると自動で数値が入力されます。
    .plan-form__pfc--carbo
      = food.number_field :carbo, step:"0.1", min:0
      = food.label '炭水化物(g)'
      .plan-form__pfc--carbo--description 画像を挿入すると自動で数値が入力されます。
  #~後略~

jQuery

FormDataでコントローラーに送信します。
formData.append("image",$('input[type=file]')[0].files[0]);
が個人的に気づきにくかったところです。
こうすることで後述のコントローラーでデータを受け取れます。

upload.js
$(function(){
  if(document.URL.match(/\/foods\/new/)) {
 //~中略~
    $(document).on('change', 'input[type= "file"]',function(e) {
 //~中略~
      e.preventDefault();
      var formData = new FormData();
      formData.append("image",$('input[type=file]')[0].files[0]);
      $.ajax({
        type:'POST',
        url: '/foods/upload',
        data: formData,
        dataType:'json',
        processData: false,
        contentType: false
      })
 //~後略~
    })
  }
})

コントローラー

image = params[:image].pathでjQuery側で設定したformDataを受け取れます。
正規表現で抽出した文字列を加工してます。1例なので、食品パッケージのバリエーションの種類分作る必要があります。(まだやってない...)

foods_controller.rb
class FoodsController < ApplicationController
#~中略~
  def upload
    require 'google/cloud/vision'
    ENV["GOOGLE_CLOUD_PROJECT"] = Rails.application.credentials.google[:GOOGLE_CLOUD_PROJECT]
    ENV["GOOGLE_CLOUD_KEYFILE"] = if Rails.env.production?
                                    Rails.application.credentials.google[:GOOGLE_CLOUD_KEYFILE_PRO]
                                  else
                                    Rails.application.credentials.google[:GOOGLE_CLOUD_KEYFILE_DEV]
                                  end
    image = params[:image].path
    image_annotator_client = Google::Cloud::Vision::ImageAnnotator.new
    image_text = (image_annotator_client.document_text_detection image: image).to_s
    if image_text.include?("たんぱく質")
      @protein = image_text[/たんぱく質(.{0,3}\d+\.?\d+)/][/\d+\.?\d+/].to_f
      @fat = image_text[/脂質(.{0,3}\d+\.?\d+)/][/\d+\.?\d+/].to_f
      @carbo = image_text[/炭水化物(.{0,3}\d+\.?\d+)/][/\d+\.?\d+/].to_f
      @data = { protein: @protein, fat: @fat, carbo: @carbo }
    end
    respond_to do |format|
      format.html
      format.json
    end
  end

#~後略~

json.jbuilder

上記のコントローラーで処理したデータをjQueryで使えるようにします。

upload.json.jbuilder
json.data do |data|
  data.protein @data[:protein]
  data.fat @data[:fat]
  data.carbo @data[:carbo]
end

jQuery

再度jQueryファイルに戻ります。
data.data.protein等にするとデータを取り出せます。

upload.js
$(function(){
  if(document.URL.match(/\/foods\/new/)) {
 //~中略~
    $(document).on('change', 'input[type= "file"]',function(e) {
 //~中略~
      e.preventDefault();
      var formData = new FormData();
      formData.append("image",$('input[type=file]')[0].files[0]);
      $.ajax({
        type:'POST',
        url: '/foods/upload',
        data: formData,
        dataType:'json',
        processData: false,
        contentType: false
      })
      .done(function(data){
        $('#food_protein').val(data.data.protein)
        $('#food_fat').val(data.data.fat)
        $('#food_carbo').val(data.data.carbo)
        alert(`画像の読み込みに成功しました! たんぱく質:${data.data.protein}g 脂質:${data.data.fat}g 炭水化物:${data.data.carbo}g`)
      })
      .fail(function(){
        alert('画像の読み込みに失敗しました')
      })
    })
  }
})

完成です

9
3
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
9
3