顔認識APIを使って写真に黒縁メガネをかける

2013年3月15日(金)
薬師寺 国安

※前ページからの続きです。

GridViewから任意の画像が選択された時の処理

リストであるmyImageList(要素の内容テキストを保持している)内の、GridViewから選択されたインデックスに該当する画像名を変数selectImageに格納します。選択された画像名をサーバーにアップしておいたASP.NETファイルのImageDataフォルダーと連結した文字列を作成して、変数selectImageUriに格納します。
640×480サイズのImageのSourceプロパティに、Uriクラスとして作成した、SelectImageUriを指定します。Image1に実寸の画像が表示されます。[黒縁メガネ]ボタンの使用を可能にします。

1Private Sub GridView1_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles GridView1.SelectionChanged
2  Dim selectImage As String = myImageList(GridView1.SelectedIndex)
3  selectImageUri = "ユーザーのサーバー名/ImageFileUpload/ImageData/" &selectImage
4  Image1.Source = New BitmapImage(New Uri(selectImageUri, UriKind.Absolute))
5  glassesButton.IsEnabled = True
6End Sub

[黒縁メガネ]ボタンがクリックされた時の処理

API へのリクエストは、apikeyや画像のurlなどの条件を下記のような URL で指定します(REST)。

apikeyには「認証キー」を指定します。urlには作成したメンバ変数selectImageUriオブジェクトを指定します。
Dim imageUri As String = String.Format("https://kaolabo.com/api/detect?apikey={0}&url={1}", AppID, selectImageUri)

新しいHttpClientのインスタンスmyHttpClientオブジェクトを作成します。HttpClientクラスは、URIで識別されたリソースにHTTP要求を送信し、そのリソースからHTTP応答を受信するためのクラスです。

GetStringAsyncメソッドで、指定したURIにGET要求を送信し、非同期操作で応答本体を文字列として返し、変数resultに格納します。
このままだと、名前空間が付加されていて、うまくXMLの内容を取得できませんので、ルート要素とその内容だけのXMLに、Replaceメソッドで書き換えます。
一人だけの顔を認識して返されるデータは図5のようなデータです。

図5:一人を認識して返されたXMLデータ(クリックで拡大)

書き換えた結果XMLを、XElement.Parseメソッドで読み込みます。

Descendantsメソッドで、子孫要素であるすべての要素(図5参照)のコレクションに対して、各要素を変数myResultに格納しながら、顔の高さや左右の目の”x”、”y”属性の値を取得し、数値に変換して各変数に格納します。

Ellipseの新しいインスタンスmyEllipseRight(右目のメガネ)を作成します。
顔の高さ”height”属性の値が100より小さかった場合、大きかった場合の、メガネの位置を調整する数値を変数に格納しておきます。

myEllipseRightをGrayで塗りつぶします。
SetValueメソッドでLeftPropertyとTopPropertyに値を指定して、メガネを表示する右目の位置を設定します。メガネの直径は顔の高さの1/4の大きさとしています。
メガネの縁を黒縁にし、縁の太さを2に設定します。Opacityに0.8を指定して半透明化しておきます。

次に左目のメガネを作成します。右目の設定とまったく同じです。

myCanvasとい名前のCanvasにAddメソッドでmyEllipseRight(右目のメガネ)とmyEllipseLeft(左目のメガネ)を追加します。これで、人物上の両目に半透明のグレーで黒縁のメガネが表示されます。

非同期処理で行われるため、メソッドの先頭にAsyncを追加します。Asyncが追加されていると、その処理が非同期で行われることを意味します。

01Private Async Sub glaseesButton_Click(sender As Object, e As RoutedEventArgs) Handles glassesButton.Click
02  Dim imageUri As String = String.Format("https://kaolabo.com/api/detect?apikey={0}&url={1}", AppID, selectImageUri)
03  Dim myHttpClient As New HttpClient
04  Dim result = Await myHttpClient.GetStringAsync(New Uri(imageUri, UriKind.Absolute))
05  result = result.Replace("<results version=" &ChrW(34) & "1.0" &ChrW(34) & " xmlns=" &ChrW(34) & "http://xmlns.kaolabo.com/detect" &ChrW(34) & ">", "<results>")
06  Dim readXmldoc As XElement = XElement.Parse(result)
07  Dim x_no As Integer = 0
08  Dim y_no As Integer = 0
09  For Each myResult In From c In readXmldoc.Descendants("face") Select c
10    Dim left_eyeX = CInt(CInt(myResult.Element("left-eye").Attribute("x").Value))
11    Dim left_eyeY = CInt(CInt(myResult.Element("left-eye").Attribute("y").Value))
12    Dim faceHeight = CInt(myResult.Attribute("height").Value)
13    Dim right_eyeX = CInt(CInt(myResult.Element("right-eye").Attribute("x").Value))
14    Dim right_eyeY = CInt(CInt(myResult.Element("right-eye").Attribute("y").Value))
15 
16    myEllipseRight = New Ellipse
17 
18    If faceHeight<= 100 Then
19      x_no = 20
20      y_no = 15
21    Else
22      x_no = 20
23      y_no = 40
24    End If
25    With myEllipseRight
26      .Fill = New SolidColorBrush(Colors.Gray)
27      .SetValue(Canvas.LeftProperty, right_eyeX - x_no)
28      .SetValue(Canvas.TopProperty, right_eyeY - y_no)
29      .Width = CInt(faceHeight / 4)
30      .Height = CInt(faceHeight / 4)
31      .Stroke = New SolidColorBrush(Colors.Black)
32      .StrokeThickness = 2
33      .Opacity = 0.8
34    End With
35 
36    myEllipseLeft = New Ellipse
37    With myEllipseLeft
38      .Fill = New SolidColorBrush(Colors.Gray)
39      .SetValue(Canvas.LeftProperty, left_eyeX - x_no)
40      .SetValue(Canvas.TopProperty, left_eyeY - y_no)
41      .Width = faceHeight / 4
42      .Height = faceHeight / 4
43      .Stroke = New SolidColorBrush(Colors.Black)
44      .StrokeThickness = 2
45      .Opacity = 0.8
46    End With
47    myCanvas.Children.Add(myEllipseRight)
48    myCanvas.Children.Add(myEllipseLeft)
49  Next
50End Sub

[クリア]ボタンがクリックされた時の処理

左目のEllipseと右目のEllipseを非表示にします。

1  Private Sub clearButton_Click(sender As Object, e As RoutedEventArgs) Handles clearButton.Click
2    myEllipseLeft.Visibility = Xaml.Visibility.Collapsed
3    myEllipseRight.Visibility = Xaml.Visibility.Collapsed
4  End Sub
5End Class

今回はここまでです。ありがとうございました。

  • 顔認識APIを使って写真に黒縁メガネをかけるアプリサンプル

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています