OpenCVをC++ではなくC#(.NET Framework)からわざわざ利用する最大のメリットは何か。単純に言語・開発環境的な理由(書きやすいとか)を挙げる人も多いでしょうが、おそらく本質的に最も大きいのは、.NET Frameworkが持つ膨大なクラスライブラリ・周辺技術等を活用できるというところではないでしょうか。
ということで、ここらで.NET Frameworkの真価を発揮したいと思いまして、ASP.NET MVC 4でOpenCvSharpを動かしてみたいと思います。ローカルで動かすので、サーバの用意は必要ありません。
OpenCvSharpが動くことを最優先していますので、MVCのお作法などなどは、テキトーです。私もあまり慣れていないので、勉強がてら書いています。
つくるもの
画像ファイルを選択してリクエストを投げると、サーバでその画像をCannyエッジ検出して、返してくれるようなサービスを作ります。
今回は、普通に「ビュー」があるWebアプリケーションとして作ります。つまり、出来上がったものはブラウザで触って遊べるものということです。
トップは、ファイル選択と送信ボタンだけのごく単純なページです。送信するファイルとして1つ画像を選びます。ここではWindows7 サンプルピクチャのペンギンを指定しました。
そしてSubmitボタンを押すと、送信された画像に対しグレースケール化・Cannyエッジ検出をして、表示します。
環境構築
Microsoft Visual Studio Express 2013 for Web を使用する前提で、以降説明いたします。必要に応じて、導入してください。単純にインストーラにおまかせするのみです。
http://www.microsoft.com/ja-jp/download/details.aspx?id=40747
なお2013ではなく2012の環境がある方は、おそらくそれでも問題ありません。またProfessional以上のエディションであればWebも含まれています。
ASP.NET MVC Hello World
慣れている方は読み飛ばしてください。
HomeControllerをつくり、Indexのビューを作るまでです。
プロジェクトの作成
「Visual C#」のWebから、ASP.NET MVC 4 Web アプリケーションで新しいプロジェクトを作ります。名前は適当に。
次のダイアログでは、プロジェクトテンプレートを「空」とします。
テンプレートを使った方が早いのですが、初心者的には空の方がためになるはず。
コントローラー(Controller)の作成
MVCのCです。
ソリューションエクスプローラのControllersを右クリックして、コントローラーを選択して新規作成します。
名前は必ず、HomeControllerとしてください(もし変える場合は、RouteConfig.csの書き換えも必要です)。テンプレートは、空のMVCコントローラーです。
HomeController.csを作ると、このようなコードが自動生成されます。Indexというアクションメソッドを作ってくれました。これがいわゆるトップページの処理となります。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class HomeController : Controller { // // GET: /Home/ public ActionResult Index() { return View(); } } }
ビュー(View)の作成
MVCのVです。上のコントローラーでは何もせず return View(); していますが、何をViewするかまだ書いていませんので作成します。
- ソリューションエクスプローラのViewsの下に新しいフォルダーを作ります。名前は必ずHomeとしてください。
- 作成したHomeフォルダーを右クリックして、ビューを選択して新規作成します。名前は必ずIndexとしてください。その他の設定はそのままです。
この時点で、ソリューションエクスプローラはこうなっているはずです。
作成された Index.cshtml の中身はこうなっていると思います。これはRazorという構文で書かれていますが、ひとまず基本的にはHTMLです。<body>の中身という扱いで、いろいろと書くことができます。
@{ ViewBag.Title = "Index"; } <h2>Index</h2>
これでようやく、ページが表示されるようになりました。デバッグ実行してみましょう。ブラウザが自動的に立ち上がり、以下のように表示されるはずです。
そういえばMVCのVCは作ったけど、M(モデル)は?と思った方、するどいです。しかし今回は手抜きなのでモデルは作りません。ロジックは全部コントローラーに書いてしまいます。あしからず。
OpenCvSharpの導入 (NuGet)
ようやく本題です。その17の要領で、OpenCvSharpをNuGet Package Managerから検索し、インストールします。
注意点として、Windowsのアーキテクチャ(32-bit/64-bit)に関わらず、必ず「OpenCvSharp x86」の方を導入してください。
ちゃんと理由がわかっていないのですが、64-bitのWindowsでもx64ではだめっぽいです。普通のIISでは動作を32-bitモードにするかどうか、のような設定があったと記憶していますが、IIS Expressでどうなのかは、知識が足りません。
画像を送信するビュー(Index.cshtml)の作成
Views/Home/Index.cshtml にこのように書き足します。この記事の初めにスクリーンショットで示したような、ファイル送信機能を備えたフォームを作ります。
Html.BeginFormの第1引数がアクション名です。Cannyというアクションに飛ばします。このあと作ります。
第2引数がコントローラ名です。HomeControllerを作っていますので、それを指定しています。
@{ ViewBag.Title = "Index"; } <h2>Index</h2> @using (Html.BeginForm("Canny", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { <input type="file" name="imageData" accept="image/*" /><br /> <input type="submit" value="Submit" /> }
HomeControllerへのアクション(Canny)の追加
ビューでCannyというアクションへ投げるように設定しましたので、それを作ります。
Controllers/HomeController.csを以下のように書きます。
using System; using System.Collections.Generic; using System.Reflection; using System.Linq; using System.Web; using System.Web.Mvc; using OpenCvSharp; namespace MvcApplication1.Controllers { public class HomeController : Controller { // // GET: /Home/ public ActionResult Index() { return View(); } public ActionResult Canny(HttpPostedFileBase imageData) { // 入力画像からIplImageを読み込み using (var image = IplImage.FromStream(imageData.InputStream, LoadMode.Color)) { // グレースケール化・Cannyエッジ検出 using (var grayImage = new IplImage(image.Size, BitDepth.U8, 1)) using (var cannyImage = new IplImage(image.Size, BitDepth.U8, 1)) { Cv.CvtColor(image, grayImage, ColorConversion.BgrToGray); Cv.Canny(grayImage, cannyImage, 60, 180); // Canny画像をPNGエンコードでバイト配列に変換し、さらにBase64エンコードする byte[] cannyBytes = cannyImage.ToBytes(".png"); string base64 = Convert.ToBase64String(cannyBytes); // ビュー変数に設定 ViewBag.Base64Image = base64; } } return View(); } } }
アクションメソッドの引数名は、ビューでのフォームのパラメータ名と合わせます。そうするだけで、ビューで入力されたパラメータを得ることができます。
今回、画像ファイルは"multipart/form-data"で送っています。CannyアクションメソッドではそれをStreamとして受け取り、IplImageに変換しています。IplImage.FromStreamにより簡単にできます。
Cannyの画像は、IplImage.ToBytesでバイト配列に変換し、さらにそれをConvert.ToBase64StringでBase64文字列に変換しています。ここもすごく簡単に書けるところで、ちょっと感動して頂けると幸いです。
画像処理結果を見せるビュー(Canny.cshtml)の作成
最後に、Cannyアクションメソッドの結果を表示するビューを作りましょう。
Views/Home/Canny.cshtmlを新規作成し、このように書きます。
@{ ViewBag.Title = "Canny"; } <h2>Canny</h2> <img src="data:image/png;base64,@ViewBag.Base64Image" />
Cannyアクションメソッドで保存しておいた、画像のBase64文字列を、<img>タグのsrcに埋め込んでいます。このようにsrc属性を書くと、そのBase64文字列が表す画像を表示させることができます。