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

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

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

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

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

  Private Sub GridView1_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles GridView1.SelectionChanged
    Dim selectImage As String = myImageList(GridView1.SelectedIndex)
    selectImageUri = "ユーザーのサーバー名/ImageFileUpload/ImageData/" &selectImage
    Image1.Source = New BitmapImage(New Uri(selectImageUri, UriKind.Absolute))
    glassesButton.IsEnabled = True
  End 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が追加されていると、その処理が非同期で行われることを意味します。

  Private Async Sub glaseesButton_Click(sender As Object, e As RoutedEventArgs) Handles glassesButton.Click
    Dim imageUri As String = String.Format("https://kaolabo.com/api/detect?apikey={0}&url={1}", AppID, selectImageUri)
    Dim myHttpClient As New HttpClient
    Dim result = Await myHttpClient.GetStringAsync(New Uri(imageUri, UriKind.Absolute))
    result = result.Replace("<results version=" &ChrW(34) & "1.0" &ChrW(34) & " xmlns=" &ChrW(34) & "http://xmlns.kaolabo.com/detect" &ChrW(34) & ">", "<results>")
    Dim readXmldoc As XElement = XElement.Parse(result)
    Dim x_no As Integer = 0
    Dim y_no As Integer = 0
    For Each myResult In From c In readXmldoc.Descendants("face") Select c
      Dim left_eyeX = CInt(CInt(myResult.Element("left-eye").Attribute("x").Value))
      Dim left_eyeY = CInt(CInt(myResult.Element("left-eye").Attribute("y").Value))
      Dim faceHeight = CInt(myResult.Attribute("height").Value)
      Dim right_eyeX = CInt(CInt(myResult.Element("right-eye").Attribute("x").Value))
      Dim right_eyeY = CInt(CInt(myResult.Element("right-eye").Attribute("y").Value))

      myEllipseRight = New Ellipse
 
      If faceHeight<= 100 Then
        x_no = 20
        y_no = 15
      Else
        x_no = 20
        y_no = 40
      End If
      With myEllipseRight
        .Fill = New SolidColorBrush(Colors.Gray)
        .SetValue(Canvas.LeftProperty, right_eyeX - x_no)
        .SetValue(Canvas.TopProperty, right_eyeY - y_no)
        .Width = CInt(faceHeight / 4)
        .Height = CInt(faceHeight / 4)
        .Stroke = New SolidColorBrush(Colors.Black)
        .StrokeThickness = 2
        .Opacity = 0.8
      End With

      myEllipseLeft = New Ellipse
      With myEllipseLeft
        .Fill = New SolidColorBrush(Colors.Gray)
        .SetValue(Canvas.LeftProperty, left_eyeX - x_no)
        .SetValue(Canvas.TopProperty, left_eyeY - y_no)
        .Width = faceHeight / 4
        .Height = faceHeight / 4
        .Stroke = New SolidColorBrush(Colors.Black)
        .StrokeThickness = 2
        .Opacity = 0.8
      End With
      myCanvas.Children.Add(myEllipseRight)
      myCanvas.Children.Add(myEllipseLeft)
    Next
  End Sub

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

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

  Private Sub clearButton_Click(sender As Object, e As RoutedEventArgs) Handles clearButton.Click
    myEllipseLeft.Visibility = Xaml.Visibility.Collapsed
    myEllipseRight.Visibility = Xaml.Visibility.Collapsed
  End Sub
End 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メルマガ会員のサービス内容を見る

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