PR

顔認識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

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

Think IT会員限定特典
  • 顔認識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のWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

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