Microsoft Emotion APIを使ってみる

Microsoft Emotion APIを使ってみる

最近使ってみようと調べていたのでメモ(かなり雑ですみません)

マイクロソフトのProject Oxfordというプロジェクトの成果とかそういうのは他のサイトでみればいいのでググってください。最近はいっぱい情報がでているのでそれを参考にしてみいいかもしれません。

サービスへの登録

まずはサービスに登録してAPIのキーを取得します。 公式サイトに行きましょう。EmotionAPIはMicrosoftのCognitiveServiceに含まれています。

www.microsoft.com

上記のURLにアクセスすると以下のような画面になります。

f:id:ueponx:20161016230611j:plain

中ほどにある【Get Started for Free】というボタンをクリックします。すると次のような画面に遷移します。

f:id:ueponx:20161016231409j:plain

画面の中ほどにある【Lets go】ボタンをクリックするとMicrosoft アカウントのログインを求められますのでログインをします。 予めログインが完了しているとボタンは表示されない画面になります。ログイン画面は表示されません。

ログインが完了するとどのサービスの試用をするか、選択する画面になります。

f:id:ueponx:20161016232442j:plain

この画面内のリストで使用するAPIにチェックをしていくことになります。(かなり多くのサービスを試用することができます。)

f:id:ueponx:20161016232740j:plain

そのなかで今回はEmotionAPIを試用するので以下のようにチェックを付けます。 以下のものにチェックをつけてください。

  • Emotion - Preview 30,000 transactions per month, 20 per minute.
  • I agree to the Microsoft Cognitive Services Terms and Microsoft Privacy Statement.

f:id:ueponx:20161016233306j:plain

f:id:ueponx:20161016233302j:plain

チェックを行うと【Submit】ボタンがアクティブになりクリックできるようになりますのでクリックします。

f:id:ueponx:20161016233525j:plain

すると、EmotionAPIの試用が可能になります。試用制限は画面にも書いてありますが

30,000 transactions per month, 20 per minute.

なので20回/分で月に30000回の試用が可能になっています。

試用してみる

先程のページでKey1とKey2の2つがありますが、そのうちのKey1の下辺りにあるCopyをクリックします。これでAPIに必要なキーがクリップボードにコピーされます。

f:id:ueponx:20161016234444j:plain

つづいて、EmotionAPIのページに移ります。

www.microsoft.com

f:id:ueponx:20161017000521j:plain

画面内にある【API Reference】をクリックします。 クリックするとEmotion APIのリファレンスページに遷移します。

f:id:ueponx:20161017000734j:plain

リファレンスページがとても優秀なのでAPI制限やRequestURL、HTTPヘッダー、HTTPレスポンス、主要言語のソースコードも載っています。

とりあえず、動作を確認するには中ほどにある【Open API Testing Console】のボタンをクリックします。すると次のようなAPIをWebページ上でテストできるようなページに遷移します。

f:id:ueponx:20161017001215j:plain

ページ中ほどにある【Ocp-Apim-Subscription-Key】の入力ボックスに先程入手したキーをペーストします。そして【Request body】のボックスにAPIの解析対象になる画像のURLをJSON形式で入力します。今回は画像処理でよく使用されているレナさんを対象にしたので以下のようにしてみました。

{ "url": "http://www.cs.cmu.edu/~chuck/lennapg/len_top.jpg" }

入力が完了すると以下のようになると思います。

f:id:ueponx:20161017002713j:plain

入力が完了したら【Send】ボタンをクリックします。クリックするとResponse同じ画面の下の方に表示されます。

f:id:ueponx:20161017002849j:plain

Pragma: no-cache
apim-request-id: b47957e8-4dc7-4d32-8b35-97165b6bde41
Cache-Control: no-cache
Date: Sun, 16 Oct 2016 15:23:03 GMT
X-Powered-By: ASP.NET
Content-Length: 257
Content-Type: application/json; charset=utf-8
Expires: -1

[
  {
    "faceRectangle": {
      "height": 68,
      "left": 177,
      "top": 85,
      "width": 68
    },
    "scores": {
      "anger": 3.3987697E-05,
      "contempt": 0.000354579,
      "disgust": 2.710808E-07,
      "fear": 3.346522E-06,
      "happiness": 0.00406290637,
      "neutral": 0.995369,
      "sadness": 6.767311E-05,
      "surprise": 0.000108244079
    }
  }
]

Responseの内容はJSONで帰ってきます。scoresの中にあるパラメータが解析結果となります。一番大きい値が解析された感情になります。今回はneutralの値が一番大きいので自然な表情だったことがでたようです。

終わりに

MicrosoftのCognitiveServiceの一つである、EmotionAPIの登録と試用をやってみました。ソースコードもあるのでとても親切なサービスのようです。今後はRaspberryPiなどでも実験して見る予定です。

RaspberryPiで複数のWiFiのアクセスポイントで固定IPの設定を登録する

RaspberryPiで複数のWiFiアクセスポイントで固定IPの設定を登録する

RaspberryPiを家で使用している時には固定IPで運用しているのですが、ハッカソンなどにいくと会場に設営されたWiFiに接続したり、個人持ち込みのPocketWiFiで運用したりとなり、最初にネットワークの設定で手間取ることが多くてRaspberryPiを使用した作品の制作から少し離れてしまうことが多くありました。(デモで機器が使えないのは正直キツイです)

そこで自宅でも、出先でも固定IPで使用できるようにしようと思いました。


参考にしたのは以下になります。ただ、少し古いためwheezベースになっていたので少し変更する必要がありました。

www.1ft-seabass.jp


アクセスポイントの情報を取得する

この部分は1つのアクセスポイントであっても同じですが、設定する可能性のあるアクセスポイントすべての情報を取得します。 結果部分にはパスフレーズの暗号化されていないものも含まれていますが、不要なので削除して使います。

$ sudo wpa_passphrase 【SSID】 【パスフレーズ】
network={
  ssid="【SSID】"
  #psk="【パスフレーズ】(入力値)"
  psk=【パスフレーズ(暗号化された値)】
}

使用する可能性のあるアクセスポイントの情報が取得できたら次のステップに進みます。

設定ファイルを編集する

今回編集するのは/etc/wpa_supplicant/wpa_supplicant.conf/etc/network/interfacesの2つのファイルです。どちらもアクセスポイントが1つの時にも設定するファイルなのでそれほど気にしなくても良いかなと思います。

/etc/wpa_supplicant/wpa_supplicant.confの編集

以下で編集を行います。(可能であればオリジナルファイルのバックアップをとっておきます。)

$ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf 

以下のように編集します。

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="【家で使用する1つ目のアクセスポイントのSSID】"
    psk=【パスフレーズ(暗号化された値)】
    key_mgmt=WPA-PSK
    priority=0
    id_str="HOME"
}

network={
    ssid="【外出時に使用する2つ目のアクセスポイントのSSID】"
    psk=【パスフレーズ(暗号化された値)】
    key_mgmt=WPA-PSK
    priority=1
    id_str="OUTSIDE"
}

アクセスポイントが1つの時と異なるのはpriorityとid_strになります。設定値通り優先順位と設定の識別になります。id_strは家で使用する設定をHOME、外で使用するPocketWiFiの設定をOUTSIDEとしました。

/etc/network/interfacesの編集

以下で編集を行います。(可能であればオリジナルファイルのバックアップをとっておきます。)

$ sudo vi /etc/network/interfaces

以下のように編集します。実際にはauto lo以下の行になります。 今回は家で使用するIPアドレス体系をを192.168.0.xとし、RaspberryPiのアドレスを192.168.0.200とし、外で使用するPocketWiFiのIPアドレス体系を192.168.179.xとし、RaspberryPiのアドレスを192.168.179.200としています。

 interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo

iface lo inet loopback
iface eth0 inet dhcp

auto wlan0
allow-hotplug wlan0

iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

iface HOME inet static
address 192.168.0.200
netmask 255.255.255.0
gateway 192.168.0.1

iface OUTSIDE inet static
address 192.168.179.200
netmask 255.255.255.0
gateway 192.168.179.1

複数のアクセスポイントを使う設定として特徴のある点は /etc/wpa_supplicant/wpa_supplicant.confで設定したid_strifaceの設定として与えている部分とWiFiの設定ファイルの呼び出し部分を(旧)wpa-conf /etc/wpa_supplicant/wpa_supplicant.confから(新)wpa-roam /etc/wpa_supplicant/wpa_supplicant.confとしている部分になります。


実験

設定画終了したので念のためリブートをしてみたところ、一応アクセスができるようになりました。ただ、両方のアクセスポイントがあると設定に時間がかかってしまうようです。(相当時間はかかるのですが、その後両方のアクセスポイントのIPアドレスが使えるようになるようです。) とはいえ、アクセスポイントが共存することはなかなか無いかなと思うのでこれで良しとします。

まとめ

一応、複数のアクセスポイントが固定IPでも使用できるように設定ができました。これで、少しはRaspberryPiの作成のハードルも低くなるかなと思います。 ただ、インターフェースにIPが複数割り当てられるのが気になります、これってどういう状況なんでしょうか。

BitBalloonの使い方メモ

BitBalloonの使い方のメモ

今回にエントリーは内容が薄いので読まなくてもいいかなと思います。

ぜひ参照先をみてください。

blog.mlkcca.com

先日(といっても一ヶ月ほど立ってしまいましたが)、Milkcocoaのハンズオンに参加してきました。 Milkcocoaのサービスは少しかじっていましたが、ちゃんとした説明を受けたことがなかったので、いい刺激になりました。 その中で可視化するための仕組みでどうしてもWebサイトらしきものを作って見ないといけないことがあるので、その部分に関しては 敷居が少しあるなと感じていた(これ見ておいてって言う感じでメールを投げにくいかった)のですがハンズオンの中でBitBalloonという サービスの紹介があり、これには結構驚きました。

すでに一ヶ月も前のことでもあるので、備忘録としてメモを取っておこうと思います。多分、名前さえ覚えておけばこのメモも不要なぐらいに簡単だと思います。

BitBalloonとは

簡単に言うとhtmlなサイトを超簡単にホスティングしてくれるサービスになります。

サイト作成

以下にアクセスします。

www.bitballoon.com

f:id:ueponx:20160916120547j:plain

サインアップしろという内容がありますが、今回はテストとしてなので気にせず、右側にある「Drag Your Site Folder Here」にHTMLやJavascriptなどのファイルをドロップしてみます。

今回使ったのはMilkcocoaさんのChatサンプルのデータとなります。

f:id:ueponx:20160916120809j:plain

ファイル構成としては上のような3つのファイルからの構成になります。文面としてはFolderをドロップしない行けないように見えますが、使用するファイルすべてドロップしても問題はないみたいです。

ドラッグ&ドロップすると処理が開始します。

f:id:ueponx:20160916121102j:plain

ファイルが少なければものの数十秒で処理が完了し、サイトへアクセスできるようになります。

f:id:ueponx:20160916121333j:plain

URLなども生成してくれるので、これに対してアクセスをすると 以下のように使用ができるようになります。

f:id:ueponx:20160916121636j:plain

ちゃんとJavaScriptからMilkcocoaへのデータのやり取りもできるので短時間でサイトを作らないといけないときや、一時的にチェックしたい用途には便利そうです。

サイトの削除

管理画面の下にある【Delete the site】をクリックすると

f:id:ueponx:20160916122158j:plain

削除用のダイアログが開くので、入力ボックスに作成したサイトの名前を入力し【Delete】ボタンをクリックすれば削除が行われます。

f:id:ueponx:20160916122557j:plain

所感

すでにバックエンドが完成していて、フロントエンドをなんとしないと行けない場合には、かなりいい感じでしょうか。ハッカソンなどで短時間にサービスを作る場合にはかなり役に立つかなと思います。ある程度セキュリティの担保も行いたい場合にはパスワードなどもかけられるようなので、ちゃんとログインしてつかうことはいうまでもありませんけど。

しあし、FTPなどではなく、ドラッグ・アンド・ドロップでもういい時代は結構きているんだなと関心しました。

ちなみに

画像などの静的ファイルだけを置こうとすると

f:id:ueponx:20160916123146j:plain

index.htmlは必須だよと怒られます。index.htmlと一緒にドラッグ・アンド・ドロップを行えばいいようですが、その時はフォルダとしてドロップしないと処理が完了しないようです。成功すれば静的ファイルのURLをダイレクトに指定すれば参照は可能のようです。

Windows 10 IoT Coreのタイマー関係を調べてみる(追記)

Windows 10 IoT Coreのタイマー関係を調べてみる(追記)

前回のエントリーの続編となります。

uepon.hatenadiary.com

前回のエントリーでmsecレベルのdelayは難しいのかなと思っていたのですが、Facebook上でMatsuokaさんからコメントで

「sw.ElapsedMilliseconds がNG」

というコメントをいただき

ソースもいただけました。ありがとうございます。

以下のようにすればμsec単位のdelayができるということでやってみました。

private static void xDelay(int microSeconds)
{
    var ticks = (long)(microSeconds * Stopwatch.Frequency / 1e6);

    var sw = new Stopwatch();
    sw.Restart();
    while (sw.ElapsedTicks <= ticks)
    {
        // Nothing.
    }
}

Ticksを使うっていうのはあながち間違っていなかったようなのですが、System.Diagnostics.Stopwatch.FrequencyでTicksの周波数をμ秒の単位に合わせて Ticksの値が該当の値になるようにすることでうまくできるようです。

https://msdn.microsoft.com/ja-jp/library/system.diagnostics.stopwatch.frequency(v=vs.110).aspx

上の例ではμ秒なので1e6=1000000で割ることで1マイクロ秒あたりのTicksを計算しています。

このxDelay()メソッドを使って以下のようにコードを書いて実験をすると

private string delay(int msec)
{
    var times = 0;

    s.Restart();
    for (times = 0; times < 1000; times++)
    {
        if (pin.Read() == GpioPinValue.High)
        {
            pin.Write(GpioPinValue.Low);
        }
        else
        {
            pin.Write(GpioPinValue.High);
        }
        xDelay(msec*1000); //引数はμsec単位なので1000倍してmsec単位にしています
    }
    s.Stop();

    return msec.ToString() + "msec->" + s.ElapsedMilliseconds / (double)times + "ms" + Environment.NewLine;
}

f:id:ueponx:20160819233559j:plain

このようになります。GPIOの処理も行っているので少し負荷がかかっていると思いますが以前に比べると大きく処理が改善しています。 RaspberryPi2で実行していますが、RaspberryPi3でも同じような結果になるそうです。

以下がダメダメだった時の結果。

f:id:ueponx:20160813170143j:plain

誤差の1msec以下なのでかなりいい感じになっています。これならかなりいい感じで使用できそうです。 Matsuokaさん、アドバイスありがとうございました。

Windows 10 IoT Coreのタイマー関係を調べてみる

Windows 10 IoT Coreのタイマー関連を調べてみる

【注】このエントリーの情報は誤りがありますので追記も必ず御覧ください。

uepon.hatenadiary.com

Arduinoとかmbedなんかのソースを移植するときにmicros()とかsleep()とかdelay()とかがあるんで、Windows10 IoT Coreではどの程度の精度が出るのか調べてみました。

delay()の代わりになるもの

以前のエントリーでも使ってますが、await Task.Delay()を使う感じでしょうか。(Thread.Sleep()でもいいのかも)

private async Task<string> delay(int msec)
{
    var times = 0;

    s.Restart();
    for (times = 0; times < 1000; times++)
    {
        if (pin.Read() == GpioPinValue.High)
        {
            pin.Write(GpioPinValue.Low);
        }
        else
        {
            pin.Write(GpioPinValue.High);
        }
        await Task.Delay(TimeSpan.FromTicks(10 * 1000 * msec));
    }
    s.Stop();

    return msec.ToString() + "msec->" + s.ElapsedMilliseconds / (double)times + "ms" + Environment.NewLine;
}

こんな感じのメソッドを考えてみました。引数で与えた秒数間隔でGPIOでLチカを行い、1000回実行して平均値をとっています。

引数にTimeSpan.FromTicks(10 * 1000 * msec)を入れたのはミリ秒以下のものを試せるようにする意味だったのですが、結果を知ってしまうと無駄です。普通に値を入れてしまえばいいと思います。ちなみにTickは100ナノ秒とのことです。

これを使って実行すると

f:id:ueponx:20160813161053j:plain

あー。

もしかしてGPIOのLチカが影響しているのかもと思ったのですが

f:id:ueponx:20160813161042j:plain

夢でした。ありがとうございます。

これでは秒単位でなければ使い物にならないのかも…そういう用途なの?

別の手段を考えてみた

これではソースの移植なんかもできないかなと思い、別の手段を考えてみました。というか、処理時間の計算に使っていたSystem.Diagnostics.Stopwatch()を使っているだけです。ストップウオッチのように使えるのですが、タイマーを動かしながらでも値の取得ができるのでそれでDelayする値がくるまでループをぶん回しているだけです。

private string myDelay(int msec)
{
    var times = 0;

    var sw = new System.Diagnostics.Stopwatch();
    sw.Restart();

    s.Restart();
    for (times = 0; times < 1000; times++)
    {
        if (pin.Read() == GpioPinValue.High)
        {
            pin.Write(GpioPinValue.Low);
        }
        else
        {
            pin.Write(GpioPinValue.High);
        }
        var old = sw.ElapsedMilliseconds;
        while ((sw.ElapsedMilliseconds - old) <= msec)
        {
        }
    }
    s.Stop();
    sw.Stop();
    return msec.ToString() + "msec->" + s.ElapsedMilliseconds / (double)times + "ms" + Environment.NewLine;
}

実行すると以下のようになります。

f:id:ueponx:20160813162403j:plain

上がawait Task.Delay()を使用、下がSystem.Diagnostics.Stopwatch()を使用したものになります。

だいぶ値的には使える範囲まで来ているかなと思います。 同様の考え方で、Arduinoのmicros()にはならないもののmsec単位の値を取ることもできます。

まとめ

await Task.Delay()ではasync/awaitのコストが結構きいているのかなと思います。秒単位、分単位ならこれでもいいかなと思いますし、UI関連が絡むのであれば選択肢としてありかなとも思えます。 ただ、Arduinoやmbedの移植を考えた時にはシングルタスクで動いていると思われるのでSystem.Diagnostics.Stopwatch()をつかってループをぶん回してもいいのかなと思います。 本当はもっといい方法があるのかもしれません。むしろ教えてほしい・・・。

追記

ネットをみてたら、こういう記事があった。

https://devhammer.net/blog/thread-sleep-equivalent-uwp/

await Task.Delay(1)Task.Delay(1).Wait()変えるって話らしい。

f:id:ueponx:20160813170143j:plain

値は変わらない・・・

/* -----codeの行番号----- */