LineBotを使用してOCRで画像を文字にしてみる
前回はユーザが何かしらの言葉をつぶやくと、その言葉に対して連想されるURLを3つまで返してくれるLine Botを作成しました。Docomo 知識Q&AのAPIを使用しており、Line BotとAIを融合したアプリケーションでした。
今回は、画像データを入力としたアプリケーションを作成しようと思います。
単純に画像データを読み込ませただけでは芸がないので、LineBotで入力した画像に対してOCRにより文字おこしを行ってみます。
「読み上げるクマ」という言葉のうしろに、OCRで変換した文章が出てきます。
Line BotとGoogle App Scriptを使用して作成していきます。
アプリケーション構成図
次のサービスを組み合わせることでアプリケーションを作成します。
・Line Bot
・Google App Script
・GoogleDrive
① Lineからメッセージを送信し、Google App Scriptで受け取る
② GoogleDriveに対して画像データを送信する
③ 画像データをOCR変換し結果を返却する
④ Google App Scriptにて結果を整形してLineにメッセージを返却する
ソースコード
Google App Scriptのコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
// トークンの設定 var channel_access_token = "★LINEのアクセストークン★"; //LineBotからのメッセージ受信 function doPost(e) { var events = JSON.parse(e.postData.contents).events; events.forEach(function(event) { if(event.type == "message"){ if (event.message.type == 'text'){ } else if (event.message.type == 'image'){ ImageUrl = getImageUrlByLine(event.message.id) imageBlob = getImageBlobByImageUrl(ImageUrl); message = GetOcrTextByimageBlob(imageBlob) message = GetTransByText(message) } lineReply(event,message); } else if(event.type == "follow"){ /* 友だち追加・ブロック解除 */ } else if(event.type == "unfollow"){ /* ブロック */ } }); } //イメージ画像のURLを取得する function getImageUrlByLine(message_id) { var url = 'https://api.line.me/v2/bot/message/' + message_id + '/content'; return url; } //URLから画像を取り出す function getImageBlobByImageUrl(url){ var res = UrlFetchApp.fetch(url, { 'headers': { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer ' + channel_access_token, }, 'method': 'get' }); var imageBlob = res.getBlob().getAs("image/png").setName("temp.png") return imageBlob; } //画像をOCRで文字起こしを行う function GetOcrTextByimageBlob(imageBlob) { var resource = { title: imageBlob.getName(), mimeType: imageBlob.getContentType() }; var options = { ocr: true, }; var file = Drive.Files.insert(resource, imageBlob, options); var doc = DocumentApp.openById(file.id); var text = doc.getBody().getText(); return text } //メッセージを追加する function GetTransByText(text) { message = "読み上げるクマ" message += "\n" return message; } //Lineのメッセージを返却する function lineReply(event,message) { var postData = { "replyToken" : event.replyToken, "messages" : [ { "type" : "text", "text" : message } ] }; var options = { "method" : "post", "headers" : { "Content-Type" : "application/json", "Authorization" : "Bearer " + channel_access_token }, "payload" : JSON.stringify(postData) }; UrlFetchApp.fetch("https://api.line.me/v2/bot/message/reply", options); } |
ソースコードの詳細
トークンの設定
1 2 |
// トークンの設定 var channel_access_token = "★LINEのアクセストークン★"; |
★の箇所にLineのアクセストークンを設定してください
LineBotからのメッセージ受信
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//LineBotからのメッセージ受信 function doPost(e) { var events = JSON.parse(e.postData.contents).events; events.forEach(function(event) { if(event.type == "message"){ if (event.message.type == 'text'){ } else if (event.message.type == 'image'){ ImageUrl = getImageUrlByLine(event.message.id) imageBlob = getImageBlobByImageUrl(ImageUrl); message = GetOcrTextByimageBlob(imageBlob) message = GetTransByText(message) } lineReply(event,message); } else if(event.type == "follow"){ /* 友だち追加・ブロック解除 */ } else if(event.type == "unfollow"){ /* ブロック */ } }); } |
今回対象となるのは、メッセージ且つイメージです。
event.typeが"message"、event.message.typeが'image'です。
message.typeが'image'の場合は画像が入力されたということなので、画像データをOCRで文字おこしをおこなうために、以下の関数を起動します。
・getImageUrlByLine関数
・getImageBlobByImageUrl関数
・GetOcrTextByimageBlob関数
・GetTransByText関数
イメージ画像のURLを取得する
1 2 3 4 5 |
//イメージ画像のURLを取得する function getImageUrlByLine(message_id) { var url = 'https://api.line.me/v2/bot/message/' + message_id + '/content'; return url; } |
Lineで入力された画像データは、すぐに画像を取り出せるということではありません。いくつかの順番を経る必要があります。
①Lineに対して画像データが格納されているURLを教えてもらう
②教えてもらったURLに対してGETメソッドで画像の取得依頼を行う
ここでは①のLineに対して画像データが格納されているURLを教えてもらうという作業を行っています。
URLから画像を取り出す
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//URLから画像を取り出す function getImageBlobByImageUrl(url){ var res = UrlFetchApp.fetch(url, { 'headers': { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer ' + channel_access_token, }, 'method': 'get' }); var imageBlob = res.getBlob().getAs("image/png").setName("temp.png") return imageBlob; } |
画像をOCRで文字起こしを行う
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//画像をOCRで文字起こしを行う function GetOcrTextByimageBlob(imageBlob) { var resource = { title: imageBlob.getName(), mimeType: imageBlob.getContentType() }; var options = { ocr: true, }; var file = Drive.Files.insert(resource, imageBlob, options); var doc = DocumentApp.openById(file.id); var text = doc.getBody().getText(); return text } |
GoogleDriveに一旦画像データを保存して、OCRオプションをONにすることにより画像データをOCR変換することができます。文字おこしを行った文章はtextという変数に格納して返却しています。
メッセージを追加する
1 2 3 4 5 6 |
//メッセージを追加する function GetTransByText(text) { message = "読み上げるクマ" message += "\n" return message; } |
Lineのメッセージを返却する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//Lineのメッセージを返却する function lineReply(event,message) { var postData = { "replyToken" : event.replyToken, "messages" : [ { "type" : "text", "text" : message } ] }; var options = { "method" : "post", "headers" : { "Content-Type" : "application/json", "Authorization" : "Bearer " + channel_access_token }, "payload" : JSON.stringify(postData) }; UrlFetchApp.fetch("https://api.line.me/v2/bot/message/reply", options); } |
前回作成したDocomo 知識Q&Aを使用したアプリケーションのコーディングと比べるとコードが長くなってしまいました。入力された画像データに対して、URLの変換や画像の取得を行っているためです。
しかし、一つ一つ見てみると意外と単純だったのではないでしょうか?
今回、文字おこしを行うことができたので、次回は画像データから日本語に翻訳してくれる機能を追加したいと思います。