Cisco Merakiカメラで3密を避ける 〜 混雑した飲食店にいる人を外に誘導しよう 〜 

#はじめに

この記事はシスコの有志による Cisco Systems Japan Advent Calendar 2020 (1枚目）の 23日目です。
2017年版: [https://qiita.com/advent-calendar/2017/cisco](https://qiita.com/advent-calendar/2017/cisco)
2018年版: [https://qiita.com/advent-calendar/2018/cisco](https://qiita.com/advent-calendar/2018/cisco)
2019年版: [https://qiita.com/advent-calendar/2019/cisco](https://qiita.com/advent-calendar/2019/cisco)
2020年版 1枚目: [https://qiita.com/advent-calendar/2020/cisco](https://qiita.com/advent-calendar/2020/cisco) <---こちら
2020年版 2枚目: [https://qiita.com/advent-calendar/2020/cisco2](https://qiita.com/advent-calendar/2020/cisco2)

レストランやカフェなど、物理的に人が集まって食事をする場所を要する商業施設やイベント会場で、
新型コロナウィルスの環境下でも密閉空間/密集場所/密接場面の「3密」を避けながら活動できるように、
「Merakiカメラで3密を避けるソリューション」を Cisco有志メンバーで考案しました。

本記事は、「Merakiカメラで3密を避けるシリーズ」の第三弾となります。
第一弾：[Cisco MerakiカメラのAPIで遊ぶ 〜 COVID-19 対策, カメラのAPIを活用して楽しく部屋の３密を回避しよう 〜](https://qiita.com/naixia/items/b110def990cd69377d07 "Cisco MerakiカメラのAPIで遊ぶ 〜 COVID-19 対策, カメラのAPIを活用して楽しく部屋の３密を回避しよう 〜")
第二弾：[Cisco Merakiカメラで3密を避ける 〜 空いている飲食店へ人を誘導しよう 〜](https://qiita.com/syoshina/items/908f9e9dd6e3f22f5a10 "Cisco Merakiカメラで3密を避ける 〜 空いている飲食店へ人を誘導しよう 〜")

#今回やりたいこと
「Merakiカメラで3密を避けるシリーズ」では、Merakiカメラを使って人の流れをコントロールし、飲食店の3密を避ける仕組みをご提案しています。第三弾では混雑している飲食店にいるお客様を**飲食店の外に誘導**します:+1:

<dl>
<dt>[誘導手順]</dt>
<dd>Step1: Merakiカメラで<strong>混雑を検知</strong></dd>
<dd>Step2: Azure face APIで<strong>年齢を特定</strong></dd>
<dd>Step3: その場に<strong>多い年代向けのイベント情報をサイネージに表示</strong>し、レストランの退店を促す</dd>
</dl>

今回のソリューションを使えば、40代が多い場合にはワインの試飲、20代が多い場合はSNSの撮影キャンペーンの案内など、年代にあったサイネージを表示することで、効率良く、お客様をレストランの外に誘導できるようになります。

#デモ動画　〜家族連れで混雑している飲食店〜
今回は、**子供が増えると、ピカチュウのイベント情報がサイネージに自動で表示される仕組み**を実装しました。

<dt>[ポイント]</dt>
<dd>(1) レストランに<strong>子供が溢れて混雑した時だけ</strong>、ピカチュウの居場所が飲食店のサイネージに通知される。</dd>
<dd>(2) ピカチュウは空いている場所から、Teamsを使って、子供達に居場所を教えることができる。</dd>
<dd>(3) サイネージからピカチュウの居場所を知った子供達は、飲食店を出る。</dd>
<dd>　　→ ピカチュウがいる(混雑していない)場所へ人が移動し、<strong>飲食店の混雑が解消</strong>される。</dd>
</dl>
それでは、ピカチュウをサイネージに表示させ、混んでいる飲食店の退席を促すデモを御覧ください。
<a href="https://youtu.be/T1hImUA4Tcw" rel="nofollow noopener" target="_blank"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/2de04a28-38af-cd40-bd30-a2a518dded24.png"></a>

<dl>
<dt>[以下、デモの説明コメント]</dt>
<dd>レストランが空いている時のサイネージには、イベント情報が表示されています。
さて、レストランがたくさんの子供達で混雑しはじめました。

Merakiカメラが店内の人数が一定数を超えたことを検知し、Azure face APIがカメラに写っている人々の年齢の分析を開始します。
その結果、サイネージにピカチュウのイベント情報が表示されました。
年齢分析の結果子供が多かったため、子供が惹かれるピカチュウの情報を表示したのです。

ピカチュウはWebex Teamsを持って施設内の人の少ない場所を移動し続けています。
移動先で「いまココに居るよ」と居場所をTeamsにコメントすると、Webex Teams REST APIがそのメッセージが混んでいるレストランのサイネージに表示します。多くの子供はピカチュウにあうために急いでレストランを出ていきます。
これにより、人を混雑したレストランの外へ誘導し、3密を回避します。
</dd>
</dl>

#仕組み

デジタルサイネージサーバーは、定期的にMeraki MV sense APIで人の数を取得し、飲食店が混雑していない時は、イベントの広告を表示しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/cd64d176-febf-21a2-a439-0832fd80baf3.png)

<dl>
<dt>飲食店が混雑してくると、以下の手順で3密を回避します</dt>
<dd>1. サイネージサーバーは、Meraki snapshot APIでスナップショットを取得する</dd>
<dd>2. Azure Face APIで人の年齢を取得する</dd>
<dd>3. 飲食店を退店させたい人の平均年齢に最も関連性の高い広告(今回はピカチュウの現在地)を表示</dd>
<dd>4. Webex TeamsのREST APIでピカチュウのメッセージをサイネージに表示</dd>
</dl>
店内に子供が多い場合は、サイネージに、ピカチュウがTeamsから送った最新のメッセージ
「僕は○○にいるよ！」のコメントが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/d8776f4a-e92d-a4ab-9627-c65651ccb3bb.png)

##Azure Face API解説
はじめに、スナップショットから人の年齢を識別する、「Azure Face API」について解説します。
>カメラの画像(スナップショット)を生成しその画像のURLを返す方法(Meraki Snapshot API)については[「3密を避けるシリーズ」第二弾](https://qiita.com/syoshina/items/908f9e9dd6e3f22f5a10"「3密を避けるシリーズ」第二弾")の解説が詳しいので、そちらをご参照ください:smiley:

「Azure Face API」はMicrosoft Azureが提供している顔認識ソフトウェアです。今回は年齢の分析に使用しますが、同一人物である確率を算出したり、性別、姿勢、ひげなどの顔関連の属性を抽出できます。
下記の[公式ページ](https://azure.microsoft.com/ja-jp/services/cognitive-services/face/ "公式ページ")より、画像をアップロードして各機能を試せます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/dde16cd9-7e51-abdf-93cc-d02ed230e87e.png)


###Azuru Face APIの使い方

<dt>顔関連の属性を抽出する「Azuru face API」をPythonから使用するための手順をご紹介します</dt>

<dd>1.<a href="https://azure.microsoft.com/ja-jp/services/cognitive-services/face/">公式ページ</a>の"無料で始める"から会員登録</dd>
<dd>2.会員登録が完了したら、”Build in the portal”からポータルに移動し「cognitive services」を検索し選択</dd>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/2d7b6010-e4a4-c786-3a22-88b55c02b385.png)

<dd>3.「追加」をクリックすると、「Marketplace」に移動するので、そこで「Face」と検索</dd>
<dd>4.「Face」が出てきたら「作成」をクリック</dd>
<dd>5. 必要情報を入力する画面が出てくるので名前・場所・リソースグループなどを適宜入力
<dd>   （今回のように分析を行うだけであれば、価格レベルは無料で全く問題ありません）</dd>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/a8b2c69d-47e4-c2b4-9bd4-2c087a973544.png)

<dd>6. 入力が完了したら、「作成」をクリック（Face APIが利用できるように準備を始める）</dd>
<dd>7. 準備が終わったら、メニューから「キー」をクリック</dd>
<dd>8. 以下に記載されているサブスクリプションキー1を使用します。(キーは2つありますが「キー2」は予備）</dd>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/04121370-7513-5c9f-ab13-921f0210e90a.png)

###PythonからAzure Face APIを使う
[公式マニュアル](https://docs.microsoft.com/ja-jp/azure/cognitive-services/face/quickstarts/client-libraries?tabs=visual-studio&pivots=programming-language-rest-api"公式マニュアル")を参考にしてPythonからAzuru Face APIを動かし、Meraki MV Sence APIが取得したスナップショットの画像から年齢を分析します。

```python:face.py
import requests
import json
from snapshot import snapshot
from config import settings
from collections import Counter
import time

＃スナップショットから年齢を分析
def detectface(url):
    face_api_url = 'https://cisco.cognitiveservices.azure.com/face/v1.0/detect'
    headers = {'Ocp-Apim-Subscription-Key': サブスクリプションキー（キー1）}
    params = {
        'returnFaceId': 'false',
        'returnFaceLandmarks': 'false',
        'returnFaceAttributes': 'age',
        #'returnFaceAttributes':'age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise',
    }
    time.sleep(5)
    response = requests.post(face_api_url, params=params, headers=headers, json={"url": url})
    list = []
    for i in response.json():
        list.append(i['faceAttributes']['age'])
    return list
```
##Cisco Webex Teams REST API解説
ピカチュウがTeamsに書いたコメントをサイネージに表示する時に、Cisco Webex TeamsのREST APIの[List Messages](https://developer.webex.com/docs/api/v1/messages/list-messages:"List Messages")を使用しています。以下のようにGUIから動作確認も可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/5eaa251e-7dbd-5f1e-2a25-57296e630b82.png)

###Cisco Webex teams REST APIの使い方
詳しい使い方は過去のQiitaの記事をご覧下さい。
[Cisco Webex Teams API(旧Cisco Spark API)の基本とREST API](https://qiita.com/thrzn41/items/355dcc370187136541a2
"Cisco Webex Teams API(旧Cisco Spark API)の基本とREST API")
###PythonからCisco Webex Teams REST APIを使う
飲食店に子供が多い場合は、
サイネージ（Sinage.html）に、ピカチュウのイベント情報（teamsのメッセージ）を表示します。

```python:app.py

@app.route('/signage')
def signage():
    ＃Meraki MV Sence APIで人数をカウント(detect.py)
    num_of_person = personcount()
    people = num_of_person[0]
    print('The number of people =', people)
    
    if people > 10:
　　    ＃レストランに10人以上、人が集まるとスナップショットを取得(shapshot.py)
        img_url = snapshot()
        ＃スナップショットを分析し(face.py)、年齢を表示
        ages_list = face.detectface(img_url[0])
        print('The age of people =', ages_list)
        age_c = Counter(ages_list)
        age_str = [str(int(i / 10)) for i in age_c]
        age_d = Counter(age_str)
        age = int(age_d.most_common()[0][0])
        msg = ''
　　　　　＃9歳以下の場合、Teamsのメッセージをサイネージに表示する
        if age < 1:
            msg = teams.message()
    else:
　　　　　＃10歳以上の場合は、Teamsのメッセージを使わない
        msg = ''
        age = 10
　　＃signage.htmlにメッセージ、人数、年齢の情報を渡す
    return render_template("signage.html", msg=msg, people=people, age=age)

if __name__ == "__main__":
    app.run(debug=True, use_reloader=True)
```
app.pyから受け取ったメッセージ、人数、年齢をベースに、サイネージ（Sinage.html）が表示されます。

```html:signage.html
<!DOCTYPE html>
    <html>
    <head>
            <meta charset="utf-8">
            <meta http-equiv="refresh" content="30; URL=">
            <link rel="stylesheet" href="">
    </head>
    <body>
      {% if people < 10 %}
      <hr>
<div align="center"><img width=900 height=100 src="static/images/top1.png"></div>
      <hr>
<!--        <h1>Map & Event Schedule Here </h1> -->
  <div align="center"><img width=900 height=350 src="static/images/signage_map.png"></div>
      {% elif age < 1 %}
      <h1>{{msg}}</h1>
      <div align="center"><img src="static/images/Pikachu.gif"></div>
      {% else %}
      <hr>
      <div align="center"><img src="static/images/sushi_header.png"></div>
      <hr>
      {% endif %}
    </body>
</html>
```

#動作確認
Merakiカメラに、子供達で賑わう飲食店の写真を映します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/f80b2a0f-2ecb-5af3-2e9c-e548ee09ada4.png)

Azure Face APIが画像を分析した結果（年齢）が、プロンプトに表示されます。

```
The age of people = [24.0, 1.0, 3.0, 22.0, 4.0, 6.0, 1.0]
```
子供が多いので、サイネージがイベント情報→ピカチュウ情報に変わります。
この時、ピカチュウがTeamsに入力したコメントも同時に表示され、ピカチュウの居場所が分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/73ecaf1f-92d5-a4a6-ec78-8d94cf8b28ee.png)
子供達は飲食店を出て、ピカチュウがいる場所に移動します。
子供達が飲食店から居なくなると、サイネージはピカチュウ情報→イベント情報に戻ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/e59ca1d2-5606-9e51-9f69-ccac6b7ba338.png)
以上により、Merakiカメラを使って、飲食店の混雑を避けることができました:clap:

#終わりに
<dt>「Merakiを使って3密を避けるシリーズ」では、3密を回避するソリューションを3つご紹介しました。</dt>
<dd>・空いている飲食店に人を呼び込む　　　　→　ダイナミックプライシングクーポン（第二弾）</dd>
<dd>・混んでいる飲食店から人を追い出す　　　→　イベント広告のダイナミック掲示（第三弾）</dd>
<dd>・混雑すると扇風機を回して換気をする　　→　PoE扇風機（第一弾）</dd>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324859/1027da30-b13d-5e20-ce8e-3d080c04396f.png)

このソリューションは飲食店だけなく、野球場やショッピングモールのような大型商業施設でも活用できます。コードを含めた詳しい情報を下記に掲載しておりますので、よろしければCisco Merakiカメラと合わせてご活用ください。

Code Exchange
https://developer.cisco.com/codeexchange/github/repo/ayamazak/Avoid-the-3Cs_via_Meraki-Camera
GitHub
https://github.com/ayamazak/Avoid-the-3Cs_via_Meraki-Camera


#免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。