17
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

はじめに

LINEとGoogle Cloud Vision API を使用して 画像解析を行うBOTを作成しました。
cv_1.png

cv_2.png

Google Cloud Vision API

  • Google Cloud Platform(GCP)が提供する画像認識サービスです。
  • GCPで新しくプロジェクトして、Cloud Vision APIを有効にしてトークンを発行します。

事前準備

詳しくはこちら

  1. GoogleDriveにてGoogleAppsScriptを開いて、以下のスクリプトを実装します。
  • LINE_CHANNEL_TOKENにLINE Messaging APIで発行したトークンを指定します。
  • GOOGLE_API_KEYにGoogle Cloud Vision APIで発行したトークンを指定します。
  • SSIDにスプレッドシートのIDとSSN_USERにシート名を指定します。
main.gs
/**
 * 画像解析BOT
 */
const LINE_CHANNEL_TOKEN = '*****'; // LINE NOTIFYのアクセストークン
const GOOGLE_API_KEY = '*****';
const SSID = '*****';
const SSN_USER = 'user';

フォロー登録

詳しくはこちら

フォロー解除

詳しくはこちら

リプライ

ユーザーが画像を入力するとLINE Messaging APIからGASにPOSTが通知されます。GASでは、画像を取得して、GoogleCloudVisionに解析依頼を行います。その後、解析結果をLINE Messaging APIにPOSTで返します。

main.gs
/**
 * メッセージイベント処理
 * @param {Object} reqEvent 
 */
function executeMessage(reqEvent) {
    let msgList = [];
    let user = getUser(reqEvent.source.userId);
    if (user) {
        switch (reqEvent.message.type) {
            case 'image':
                let content = getLineContent(reqEvent.message.id);
                let result = getAnnotate(content.getBlob());
                console.log(result);

                for (let i in result.responses) {
                    let retObj = result.responses[i];
                    for (let key of Object.keys(retObj)) {
                        let msg = null;
                        let value = retObj[key];
                        switch (key) {
                            case 'webDetection':
                                msg = getMsgWebDetection(value);
                                break;
                            case 'labelAnnotations':
                                msg = getMsgLabelAnnt(value);
                                break;
                            case 'textAnnotations':
                                msg = getMsgTextAnnt(value);
                                break;
                            case 'landmarkAnnotations':
                                msg = getMsglandmarkAnnt(value);
                                break;
                            case 'logoAnnotations':
                                msg = getMsglogoAnnt(value);
                                break;
                        }
                        if (msg) {
                            msgList.push({
                                'type': 'text',
                                'text': msg,
                            });
                        }
                    }
                }
                if (0 < msgList.length) {
                    console.log(JSON.stringify(msgList).replace('\n', ''));
                    sendLineReply(reqEvent.replyToken, msgList);
                }
                break;
        }
    }
}

/**
 * WEB検出のメッセージを取得する
 * @param {Object} value 
 */
function getMsgWebDetection(value) {
    let msg = `【WEBの検出】\n\n`;
    for (let i in value.webEntities) {
        let item = value.webEntities[i];
        msg += `- ${LanguageApp.translate(item.description, 'en', 'ja')}\n`;
    }
    for (let key of Object.keys(value)) {
        switch (key) {
            case 'fullMatchingImages':
                msg += `\n<< 完全一致 >>\n`;
                for (let j in value[key]) {
                    let item = value[key][j];
                    msg += `[${parseInt(j) + 1}] ${item.url}\n`;
                }
                break;
            case 'partialMatchingImages':
                msg += `\n<< 部分一致 >>\n`;
                for (let j in value[key]) {
                    let item = value[key][j];
                    msg += `[${parseInt(j) + 1}] ${item.url}\n`;
                }
                break;
            case 'visuallySimilarImages':
                msg += `\n<< 類似 >>\n`;
                for (let j in value[key]) {
                    let item = value[key][j];
                    msg += `[${parseInt(j) + 1}] ${item.url}\n`;
                }
                break;
        }
    }
    return msg;
}

/**
 * ラベル検出のメッセージを取得する
 * @param {Array} value 
 */
function getMsgLabelAnnt(value) {
    let msg = '【ラベルの検出】\n\n';
    for (let i in value) {
        let item = value[i];
        msg += `- ${LanguageApp.translate(item.description, 'en', 'ja')}\n`;
    }
    return msg;
}

/**
 * 文字検出のメッセージを取得する
 * @param {Array} value 
 */
function getMsgTextAnnt(value) {
    return `【文字の検出】\n\n${value[0].description}\n`;
}

/**
 * 場所検出のメッセージを取得する
 * @param {Array} value 
 */
function getMsglandmarkAnnt(value) {
    let msg = '【場所の検出】\n\n';
    for (let i in value) {
        let item = value[i];
        msg += `- ${LanguageApp.translate(item.description, 'en', 'ja')}\n`;
        for (let j in item.locations) {
            let loc = item.locations[j];
            msg += `https://www.google.com/maps?q=${loc.latLng.latitude},${loc.latLng.longitude}\n`;
        }
        msg += `\n`;
    }
    return msg;
}

/**
 * ロゴ検出のメッセージを取得する
 * @param {Array} value 
 */
function getMsglogoAnnt(value) {
    let msg = '【ロゴの検出】\n\n';
    for (let i in value) {
        let item = value[i];
        msg += `- ${item.description}\n`;
    }
    return msg;
}

/**
 * Googleに画像を送信する
 * @param {Object} file ファイル
 */
function getAnnotate(file) {
    let url = `https://vision.googleapis.com/v1/images:annotate?key=${GOOGLE_API_KEY}`;
    let options = {
        'method': 'get',
        'headers': {
            'Content-Type': 'application/json; charset=UTF-8',
        },
        'payload': JSON.stringify({
            requests: [{
                image: {
                    content: Utilities.base64Encode(file.getBytes())
                },
                features: [{
                        type: 'WEB_DETECTION', // WEBの検出
                        maxResults: 5
                    },
                    {
                        type: 'LABEL_DETECTION', // ラベルの検出
                        maxResults: 5
                    },
                    {
                        type: 'TEXT_DETECTION', // 文字の検出
                        maxResults: 5
                    },
                    {
                        type: 'LANDMARK_DETECTION', // 場所の検出
                        maxResults: 5
                    },
                    {
                        type: 'LOGO_DETECTION', // ロゴ検出
                        maxResults: 5
                    },
                ],
            }]
        })
    };
    let response = UrlFetchApp.fetch(url, options);
    return JSON.parse(response.getContentText('UTF-8'));
}

/**
 * LINEからコンテンツを取得する
 * @param {String} messageId メッセージID
 */
function getLineContent(messageId) {
    let url = `https://api.line.me/v2/bot/message/${messageId}/content`;
    let options = {
        'method': 'get',
        'headers': {
            'Content-Type': 'application/json; charset=UTF-8',
            'Authorization': `Bearer ${LINE_CHANNEL_TOKEN}`
        }
    };
    return UrlFetchApp.fetch(url, options);
}
  • execute関数では、LINE Messaging APIからの通知内容により、処理を振り分けしています。messageの場合は、メッセージの内容を解析します。
  • getLineContent関数でLINEに入力された画像を取得して、getAnnotate関数でGoogle Cloud Vision APIに画像を送信します。検出できる内容はこちら
  • 検出した内容ごとにメッセージを作成してsendLineReply関数でLINE Messaging APIにPOSTします。

参考リンク

さいごに

ソースコードをGitHubに公開しています。

以上です。

17
6
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
17
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?