食べ物の画像にモザイクをかける API と Chrome 拡張を作ってみた [Project Oxford Vision API]
飯テロ対策として、食べ物の画像にモザイクをかける API と Chrome 拡張を作ってみました。
Microsoft Project Oxford の Vision API を利用したもので、API 制限等からきちんと公開はしていませんが、API を試したり、コードを見たりはできます。先日話題になった How-Old.net は、Project Oxford の提供する API のうち Face API を利用しています。
Chrome 拡張
食べ物の画像にモザイクをかける Web サービス
画像 URL を指定すると、食べ物の画像の場合、モザイク処理された画像が返ってきます。
http://foodtero.azurewebsites.net/api/?url=http://upload.wikimedia.org/wikipedia/ja/thumb/f/fc/Soy_ramen.jpg/260px-Soy_ramen.jpg
利用している Visio API は、1分に20回、月に5,000回までの制限があるので、エラーになった場合は、そのままの画像を返します。皆さん自身で API Key を取得して実装してみてください。
Vision API
Vison APIs は、以下の機能があります。
- 画像認識
- サムネイルの生成
- OCR
今回は、画像認識を利用して、画像のカテゴリーが「食べ物」場合、モザイクをかけて返すという Web サービスにしてみました。Vison API では、86のカテゴリーに分類できます。
公式のデモはこちら。
アダルトコンテンツ、Racy コンテンツ(水着とか)の判別、背景・前景のカラーやアクセントカラー抽出などもできます。
Vision API を使ってみる
現在 Beta 版で無料で利用できます(呼び出し制限を緩和しようとも、無料版しかないのでできません)。また、Azure Market での購入が必要で、Azure アカウントが必要です。API は、RESTful API で、プラットフォームを選びません。
リクエスト URL: https://api.projectoxford.ai/vision/v1/analyses[?visualFeatures]
詳細は、Microsoft Project Oxford API Reference 参照。
Azure Marketplace でサービスの選択
Azure ポータルから、Marketplace の Vision API を追加します。
Key の取得
https://dev.projectoxford.ai/Developer にアクセスして、Key を取得します。
SDK のダウンロード、コードサンプル
.NET/Android の SDK が用意されています。その他の言語も ドキュメント のサンプルコードなどを見れば簡単に使えます。
Visual Basic で、SDK のライブラリを利用すれば、画像認識は次のように書けます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Dim client = New VisionServiceClient("**key**") | |
Dim result = Await client.AnalyzeImageAsync("画像 URL") ' 画像の Stream も指定可能 | |
If result.Categories IsNot Nothing AndAlso result.Categories.Any AndAlso | |
result.Categories.First.Name.StartsWith("food_") Then | |
' (画像のカテゴリーが食べ物の場合) | |
End If |
Web サービスを作る
ASP.NET で Web サービスを作ります。
コントローラーのコードです。ルーティングを変更する以外は、他に書くコードはありません。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Imports System.Drawing | |
Imports System.Net | |
Imports Microsoft.ProjectOxford.Vision | |
Public Class ApiController | |
Inherits System.Web.Mvc.Controller | |
Async Function Index(url As String) As Threading.Tasks.Task(Of ActionResult) | |
If url Is Nothing Then | |
Return New HttpStatusCodeResult(HttpStatusCode.BadRequest) | |
End If | |
Dim result As Contract.AnalysisResult | |
Try | |
' API 呼び出し | |
Dim client = New VisionServiceClient("0b1ff4ab7a634bb0a6f7d532659f5d77") | |
If Uri.IsWellFormedUriString(url, UriKind.Absolute) Then | |
result = Await client.AnalyzeImageAsync(url) | |
Else | |
Return New HttpStatusCodeResult(HttpStatusCode.BadRequest) | |
End If | |
Catch cEx As ClientException | |
Return FileStream(url) | |
Catch ex As Exception | |
Return FileStream(url) | |
End Try | |
If result.Categories IsNot Nothing AndAlso result.Categories.Any AndAlso | |
result.Categories.First.Name.StartsWith("food_") Then ' 画像のカテゴリーが食べ物 | |
' モザイク画像作成 | |
Dim webClient = New WebClient | |
Dim inBmp = New Bitmap(webClient.OpenRead(url)) | |
Dim tmpBmp = New Bitmap(inBmp.Width \ 10, inBmp.Height \ 10) | |
Dim outBmp = New Bitmap(inBmp.Width, inBmp.Height) | |
Using g = Graphics.FromImage(tmpBmp) | |
g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor | |
g.DrawImage(inBmp, 0, 0, tmpBmp.Width, tmpBmp.Height) | |
End Using | |
Using g = Graphics.FromImage(outBmp) | |
g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor | |
g.DrawImage(tmpBmp, 0, 0, outBmp.Width, outBmp.Height) | |
End Using | |
Response.ContentType = "image/png" | |
outBmp.Save(Response.OutputStream, Imaging.ImageFormat.Png) | |
Return New EmptyResult | |
Else | |
Return FileStream(url) | |
End If | |
End Function | |
Private Function FileStream(url As String) As ActionResult | |
Try | |
Dim req = HttpWebRequest.CreateHttp(url) | |
Dim res = DirectCast(req.GetResponse, HttpWebResponse) | |
Response.ContentType = res.ContentType | |
res.GetResponseStream.CopyTo(Response.OutputStream) | |
Catch ex As WebException | |
If ex.Status = System.Net.WebExceptionStatus.ProtocolError Then | |
Dim r = DirectCast(ex.Response, System.Net.HttpWebResponse) | |
Response.StatusCode = r.StatusCode | |
End If | |
End Try | |
Return New EmptyResult | |
End Function | |
End Class |
Chrome の拡張を作る
試しに Chrome 拡張を作ってみます。img の URL を、作った API の URL に差し替えます。
フォルダーに、custom.js、manifest.json、jquery.min.js を作ります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$(function() { | |
$('img').each(function(){ | |
this.src = "http://foodtero.azurewebsites.net/api/?url=" + encodeURIComponent(this.src); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"manifest_version": 2, | |
"name": "食べ物の画像にモザイクをかける拡張", | |
"version": "1.0", | |
"content_scripts": [{ | |
"matches": [ "<all_urls>" ], | |
"js": [ "jquery.min.js", "custom.js" ], | |
"run_at": "document_start" | |
}] | |
} |
Chrome のアドレス欄に「chrome://extensions/」を入力。「デベロッパーモード」にチェックを入れて「パッケージ化されていない拡張機能を読み込む」ボタンから、作成したフォルダーを指定すれば、拡張を追加できます。
以上で完成です。ただし、モザイク画像がロードされるまで、元の画像が見えるという欠点と、API 制限にすぐひっかかります。お遊びということで。あと、Data URI(data:image で始まる URL)にも対応できていません。
わざわざ Web サービスを作りましたが、Vison API は、JavaScript からも利用できるので、Chrome 拡張のみで完結も可能です。