写真から顔を自動認識して、簡単に目隠し加工する(前編)
ImageShowPage.xamlを展開して表示される、ImageShowPage.xaml.vbをダブルクリックしてリスト3のコードを記述します。
ロジックコードを記述する
リスト3 (ImageShowPage.xaml.vb)
Option Strict On Imports System.Xml.Linq
ImageInfoクラスに文字列型の「画像名」プロパティを定義しておきます。
Public Class ImageInfo Property 画像名 As String End Class Partial Public Class ImageShowPage Inherits PhoneApplicationPage Public Sub New() InitializeComponent() End Sub
ページがアクティブになった時の処理
新しいWebClientのインスタンスmyWebClientオブジェクトを作成します。WebClientクラスは、データの送受信用のメソッドを提供するクラスです。
String またはUriとして指定したリソースをダウンロードする、DownloadStringAsyncメソッドで、サーバー上のImageInfo.xmlをダウンロードします。キャッシュから読み込まないように、常に新しいデータを読み込むよう、引数に現在の時間、分、秒を指定しています。
AddHandlerステートメントで、非同期のリソース ダウンロード操作の完了時に発生するDwonloadStringCompletedイベントに、イベントハンドラを追加します。イベントハンドラ内では以下の処理を実行します。
ダウンロードが成功しなかった場合は、警告メッセージを出して、処理を抜けます。成功した場合は、XElement.Parseメソッドでダウンロードした結果(resultArgs.Result)を読み込みます。読み込んだ結果はmyDoc変数に格納されます。ImageInfoクラスの新しいリストであるimageListを作成します。Descendantsメソッドで、子孫要素であるすべての
Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs) Dim myWebClient As New WebClient
AddHandler myWebClient.DownloadStringCompleted, Sub(resultSender As Object, resultArgs As DownloadStringCompletedEventArgs) If resultArgs.Error Is Nothing = False Then MessageBox.Show("XMLファイルが見つかりません") Exit Sub Else Dim myDoc As XElement = XElement.Parse(resultArgs.Result) Dim imageList As New List(Of ImageInfo) For Each result In From c In myDoc.Descendants("fileName") Select c imageList.Add(New ImageInfo With {.画像名 = "ユーザーの専用サーバーのURL/ImageFileUpload/ImageData/" & result.Value}) Next ListBox1.ItemsSource = imageList End If End Sub myWebClient.DownloadStringAsync(New Uri(String.Format("ユーザーの専用サーバーのURL/ImageFileUpload/ImageData/ImageInfo.xml?myTime={0}", DateTime.Now.ToLongTimeString), UriKind.Absolute)) MyBase.OnNavigatedTo(e) End Sub
ListBoxから任意の画像が選択された時の処理
選択された画像のインデックスを引数に、後編で作成するFacialrecognitionPage.xamlページに遷移します。
Private Sub ListBox1_SelectionChanged(sender As Object, e As System.Windows.Controls.SelectionChangedEventArgs) Handles ListBox1.SelectionChanged NavigationService.Navigate(New Uri(String.Format("/FacialrecognitionPage.xaml?Index={0}", ListBox1.SelectedIndex.ToString), UriKind.Relative)) End Sub End Class
ASP.NETページの作成(ImageFileUpload)
VS2010のメニューから、[ファイル(F)/新規作成(N)/Webサイト(W)]と選択し、表示される画面から「ASP.NET Webサイト」を選択します。「webの場所(L)」に今回は「フォルダ名\ImageFileUpload」と指定し[OK]ボタンをクリックします。
ソリューションエクスプローラー内にImageDataというフォルダを作成し、
VS2010メニューの[Webサイト(S)/参照の追加(R)]と選択して、System.Xml.Linqを追加しておいてください。
ソリューションエクスプローラー内のDefault.aspxを展開して表示される、Default.aspx.vbにリスト3のコードを記述します。
※このコードをサーバーに配置した際の、アクセス権の設定やIISの設定は各自が行ってください。
ロジックコードを記述する
リスト3 (Default.aspx.vb)
Option Strict On Imports System.IO Imports System.Xml Partial Class _Default Inherits System.Web.UI.Page
ページが読み込まれた時の処理
Windows Phoneのプログラムから送られたfileNameを受け取って、変数fileNameに格納します。
サーバーの物理パスとImageDataフォルダとfileNameを連結して、変数filePathに格納しておきます。
FileStreamクラスの変数streamを用意し、File.Openメソッドで、filePathに指定したファイルを、Createモードで開きます。Createでは、新しいファイルが作成されます。既にファイルが存在する場合は上書きされます。4096バイトで初期化されたByte型の配列変数bufferを宣言します。POSTされたデータ(Request.InputStream)を取得し、Readメソッドで、リソースに格納されているストリームを読み取りFileStreamにWriteメソッドで書き込みます。これで、Windows PhoneのプログラムからPOSTされた、現在の「年月日時間分秒.jpg」ファイルが作成されます。InlineAssignHelperヘルパー関数(後述)を使っています。
次に、保存されたjpg画像の、ファイル名の一覧を記録するXMLファイル(ImageInfo.xml)に、jpg画像のファイル名を追加する処理を行います。
XElement.LoadメソッドでImageDataフォルダ内のImageInfo.xmlを読み込みます。Visual Basic の埋め込み式を用いて、
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load Dim fileName As String = Context.Request.QueryString("fileName").ToString Dim filePath As String = Server.MapPath("./") & "ImageData/" & fileName Using stream As FileStream = File.Open(filePath, FileMode.Create) Dim buffer As Byte() = New Byte(4096) {} Dim myByteRead As Integer While (InlineAssignHelper(myByteRead, Context.Request.InputStream.Read(buffer, 0, buffer.Length))) <> 0 stream.Write(buffer, 0, myByteRead) End While stream.Close() Response.Flush() End Using Dim xmldoc As XElement = XElement.Load(Server.MapPath("./") & "ImageData/ImageInfo.xml") Dim addXml As XElement = <fileName><%= fileName %></fileName> xmldoc.Add(addXml) xmldoc.Save(Server.MapPath("./") & "ImageData/ImageInfo.xml") End Sub
MSDNのドキュメントで下記のように定義されているInlineAssignHelperヘルパー関数
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T target = value Return value End Function End Class
次にVS2010メニューの[Webサイト(S)/新しい項目の追加(W)]と選択して、「Webフォーム」を作成します。「名前(N)」はDefault2.aspxのままにしておきます。ソリューションエクスプローラー内のDefault2.aspxを展開して表示される、Default2.aspx.vbにリスト4のコードを記述します。
このDefault2.aspx.vbは、Windows Phoneで選択されたjpgファイルを削除する処理です。
ロジックコードを記述する
リスト4 (Default2.aspx.vb)
Option Strict On Imports System.IO Imports System.Xml.Linq Partial Class Default2 Inherits System.Web.UI.Page
ページが読み込まれた時の処理
StreamReaderクラスでPOSTされたデータ(Request.InputStream)を取得し、reader変数で参照します。StreamReaderクラスは、特定のエンコーディングのバイトストリームを読み込むTextReader を実装するクラスです。
取得したデータの内容をReadToEndメソッドで読み取り、変数readStrに格納しておきます。readStrの値を数値に変換してmyIndex変数に格納します。readStrにはWindows Phoneから送られた、選択されたjpgファイルのインデックスが格納されています。
インデックスに該当する.jpg画像ファイルと、ImageInfo.xml内で該当する.jpgファイルの記録されている、
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load Dim reader As New StreamReader(Me.Request.InputStream(), System.Text.Encoding.UTF8) Dim readStr As String = reader.ReadToEnd Dim myIndex As Integer = Integer.Parse(readStr) Dim doc As XElement = XElement.Load(Server.MapPath("./") & "ImageData/ImageInfo.xml") Dim deleteData = doc.Descendants("fileName")(myIndex) Dim delImage As String = doc.Descendants("fileName")(myIndex).Value File.Delete(Server.MapPath("./") & "ImageData/" & delImage) deleteData.Remove() doc.Save(Server.MapPath("./") & "ImageData/ImageInfo.xml") End Sub End Class
前編は以上で終わりです。次回は後編として、サーバーから読み込んだJPG画像に、FUJIFILMが提供している「顔検出WebAPI」を使用して、「目隠し」の処理を行う方法を紹介します。
「写真から顔を自動認識して、簡単に目隠し加工する」サンプルプログラム