Wi-Fiのスキャン

ここ数日、色んな所でWi-Fiのスキャンを行ったりした内容を記載しておく。

■ 一般的なWiFiの仕様
あまりWiFiの仕様に詳しくなかったけど、ここ最近で色々と調べてなるほどね!!と分かってきたりして、簡単な説明ついでに。まず一般的なWiFiで利用できる電波帯域と仕様は次に別れている。

2.4GHz帯域
802.11 b/g/n

5GHz帯域
802.11 a/n/ac

よく無線ルータを買ってくると、802.11 a/b/g/n/ac対応とかって謎の文字が書いてあったりする。そんな仕様をアピールしても一般ユーザに何も響かない気もするけど、仕様は色々とある。ザックリ説明するとこんな感じ。

pic1

2.4GHz帯は昔からある仕様で、他に使っている物はおなじみのBluetoothやZigbee、そして電子レンジとか。他にもコードレス電話とか、2.4GHzを使っている物は沢山ある。このBluetoothや電子レンジがクセもので、知らずに2.4GHzでWiFiやBluetoothを使ったコントローラが影響を受けたという人もいるかも。(希有な方が、2.4G無線LAN電子レンジ影響調査という素敵な資料を作っていました。)

そして、5GHz帯はわりと最近からの仕様で、特にacはiPhone6に入ってきたことで「一部の層で」話題になったと思う。こちらは制限があるものの(チャネル数に)屋外でも使える。Bluetoothとか普及している他の影響をあまり受けないから、サクサク使えると思う。

あと、それぞれ、802.11 なんちゃらを使った場合の最大帯域は、こんな感じ。(アンテナの本数増やしたり、a/nとかの組み合わせは省いている)

802.11 b : 11Mbps
802.11 g : 54Mbps
802.11 n : 144Mbps

802.11 a : 54Mbps
802.11 n : 300Mbps
802.11 ac: 1300Mbps

 

■ WiFiがつながりにくいぜ!!
よくあるのが「WiFiがつながりにくいぜ!!」とか、つながっても「ネット使えねーよ!!」みたいな話で、特に人が密集している所ではよく発生する。
原因の一つでよく言われるのが、WiFi同士の電波干渉。イメージ的には、水面に一つだけ石を投げた時は綺麗に波が伝わるけど、いっぱい放り投げると波同士が合成(干渉)されて増幅・打ち消し合ったりして新しい波が出来る事が想像できると思う。お互いが影響しあって情報を送受信しあう電波が使えないぜ!!とった状態になる。

特に2.4GHz帯域は昔からあるから、多くのスマホや身の回りの環境(電子レンジ、コードレス電話、Bluetooth)で電波を発生する物があるから、干渉しまくりで使えないぜ!!という事が多々ある。今はみんなスマホ持ち歩いているから、WiFiとBluetoothで2.4GHzの影響が倍増(w)して、ちょっと人が集まるとろくに使えない状態になる。

逆に5GHzの方は割とサクサク使える。新しい仕様といっても、殆どのPCやスマートフォンの無線の機能としては入っているし、他の環境機器の影響を避けたいなら5GHzの方を使うのはオススメ。凄まじく人が居る状態でも経験した感じでは、あまり干渉を受けずに使えると思われ。

 

■ 色んな所でWiFiをスキャンしてみた結果
断っておくと、スキャンはWiFiオンにすれば行われるから良いにしたって、勝手に接続するのは絶対ダメです。

WiFiのスキャンはWiFi Explorerという物を使っています。結果はこんな感じで見れる。
AP名、BSSIDは消しています。あと、下のグラフにはAP名とチャネル、干渉状態を見る事が出来る素敵なアプリです。あと結果は場所によって変わってくるので。

 

■ みなとみらい
ここはタバコを吸う灰皿があって、ここでスキャンしてみた。駅を出て地上に出てすぐの所。

何故か一瞬で110個ものAPが出てきた。屋外にはみ出ているAPも多数(w)
単位は個数で。

Total : 110
2.4GHz    : 65
5Ghz         : 45
Key無       : 12

2.4GHz
802.11b             :    4
802.11g             :    1
802.11b/g        : 14
802.11b/g/n   : 36
802.11 g/n       :    3
802.11 n            :    7

5GHz
802.11a             :    7
802.11n            :    2
802.11a/n       :  35
802.11ac          :    1

 

■ 中華街
ちょっと足を運んで中華街へ。休日なだけあって、人が凄まじい…

特徴的な気がしたのはがキー無しAPの割合が多い。飲食店で「WiFiがすぐ使えますよー」といって提供している所が多いせいだとは思う。とはいっても、みなとみらいと大差ないけど。

Total : 60
2.4GHz    : 42
5Ghz         : 18
Key無       : 16

2.4GHz
802.11b             :    0
802.11g             :    0
802.11b/g        : 12
802.11b/g/n   : 25
802.11 g/n       :    0
802.11 n            :    5

5GHz
802.11a             :    1
802.11n            :    0
802.11a/n       :  17
802.11ac          :    0

 

■ 大桟橋
ちょっとあまりにも沢山のAPが出てきまくるので、桟橋の先端まで行ってみたら、WiFiを検知出来なくなったりするのかしら?という単純な理由で桟橋の先に行くことに。

APの量は圧倒的に少なくなるけど電波って飛んでくるのね。あとショッキングな事が、テザリングをオンにして歩いている方がいらっしゃるのか、「にーさとのiPhone」みたいな感じで名前付きでAPが出てきた…

Total : 26
2.4GHz    : 19
5Ghz         : 7
Key無       : 11

2.4GHz
802.11b             :    0
802.11g             :    0
802.11b/g        :    7
802.11b/g/n   :    8
802.11 g/n       :    1
802.11 n            :    3

5GHz
802.11a             :    1
802.11n            :    0
802.11a/n       :     6
802.11ac          :    0

■ おまけ
某数万人は来ると言われる某イベントでスキャンした内容。IT寄り(?)のイベントで。2.4GHz帯なんか使い物にならないし、WiFiって何ぞや?と思える感じでもある環境ですね。Key無しのAPが激減しているのは、そうですよね…って感もするし、古めの仕様の率も低くなる。街中とかとは全然違う。

Total : 103
2.4GHz    : 47
5Ghz         : 56
Key無       : 2

2.4GHz
802.11b             :    2
802.11g             :    0
802.11b/g        :    8
802.11b/g/n   :  27
802.11 g/n       :    1
802.11 n            :    9

5GHz
802.11a             :    1
802.11n            :    0
802.11a/n       :   50
802.11ac          :     5

本当はこういう各ポイント毎で無線がどんだけ立ってるのー?とか可視化されたら良いと思うんだけど、宅内で立てても外にダダ漏れして街中じゃカオス状態になっていたりするし、難しいんだろうなぁ…とは思う。あと、最低限でもキーは付けた方が良いと思われ。ノーガードは無いっしょ。

iPhone6 802.11ac Test

iPhone6の新機能で注目な、802.11ac 5GHzのWiFi。今年になってIEEEで承認されたホットな仕様で自分の見通しだと、さすがにスマホに802.11acは乗ってこないと思いきや…乗ってきたので早速テスト。ルータにはPlanexのMZK-1200DHPを使った。上流は

こんな感じ。

このPlanexのルータ、802.11acが搭載されていてAmazonで3,778円で買える爆安さに惹かれた。ただ、このルータを起動してみて何故か11acに設定してみても接続できない。そう、ファームが1.30だと11acが使えなかった…orz ファームアップして、1.35にするとバッチリ接続できる。この点だけ要注意。

んで、早速、2.4GHzと5GHzで接続テスト!!テストにはRBB SEEDを使った。

次に、5GHz 11acで。

もちろんだけど、11acの方が全然早い。

MQTT Library for Spark Core

MQTT is lightweight pub/sub messaging protocol for IoT/M2M. MQTT target is large scale pub/sub system, used on Facebook Messenger and others(not for the message queue like a RabbitMQ/AMQP…etc).  MQTT for Arduino is already developed as pubsubclient, but Arduino like open source system “Spark.io” don’t have MQTT library.  So I made MQTT for Spark.io based on pubsubclient. Thanks for knolleary.

MQTT for Spark.

#include "MQTT.h"

void callback(char* topic, byte* payload, unsigned int length);
MQTT client("server_name", 1883, callback);

// recieve message
void callback(char* topic, byte* payload, unsigned int length) {
    char p[length + 1];
    memcpy(p, payload, length);
    p[length] = NULL;
    String message(p);

    if (message.equals("RED"))    
        RGB.color(255, 0, 0);
    else if (message.equals("GREEN"))    
        RGB.color(0, 255, 0);
    else if (message.equals("BLUE"))    
        RGB.color(0, 0, 255);
    else    
        RGB.color(255, 255, 255);
    delay(1000);
}


void setup() {
    RGB.control(true);
    
    // connect to the MQTT server
    client.connect("sparkclient");

    // publish/subscribe
    if (client.isConnected()) {
        client.publish("outTopic","hello world");
        client.subscribe("inTopic");
    }
}

void loop() {
    if (client.isConnected())
        client.loop();
}

Kinect v2とopenFrameworksをイベントで使う

社内のファミリーデーでKinect v2を使った出し物をやった構成。アプリ的には、

・トラッキングした人だけ取って正面に投影
・天井にはトラッキングした人の位置の上に色んなタイプの紋様をクルクル回したり・大きさを変えながら投影
・手をグーにすると、電撃(複数人でグーにしていると、グー同士を電撃がつないでみんなでビリビリ)
・手をパーにすると、色が変化するパーティクルを物理係数をかけてパラーっと床まで落とす
・手をチョキにすると、ビームみたいに飛ばす
・落ちたパーティクルは足で蹴っ飛ばしたり踏みつけて消していく

こんな感じ

流れ的にはKinect v2用SDKの細かい処理はバックグラウンドスレッドで実行して、フロントではバックグラウンドスレッドで取得したデータ処理を行う感じ。色んな方のソースをつまみ食い参考にさせてもらって、マルチスレッド用のロックをちょこちょこ入れている。メモに近いコードだけど、まぁ普通に使ってこんな感じの電気ビリビリ&パーティクルパラパラとかもサクっと出来る感じ。

使ったモノはこんな感じ

– PC
VAIO Duo 11, Core i5-3317U, Mem 4Gbyte/Windows 8 64bit
Macbook air Mid 2011, Core i5 1.6GHz, Mem 4Gbyte/OS X 10.9.4

– プロジェクタ
BenQ MS616ST
EPSON EP-1751

– Network
Planex MZK-RP150N

– 3Dセンサ
Kinect v2

– Software
openFrameworks 0.8.3(Win VC++ 2012/Mac Xcode), Kinect v2 SDK
素材作成用(Inkscape, Gimp), フリー音源

機材を雑然と全部つなげたのがこんな感じ

そろそろ最新のMacbook Airが欲しい。けど、今の手持ちのMid 2011のでも十分性能も出ているし、Core i7・16G memを積んだMacbook ProはOculus用で使っちゃったのもあって、手持ちの物を使うことに。Planex MZK-RP150Nは通称「ちびファイ」。旅先でも重宝する割と好きなアイテムだったりする。

 

ファミリーデーで最新で面白い事をヨロピク、ということで真っ先に思いついたのがv2を使うことに。まだ出始めのv2だったら一般的(?)には最新かなと。あと、子供向けというのもあって、あんまり激しいギーク寄りにするとドン引きするし、そっち方向は止めようと。ただ、最初に色々と考えたのは、

– 当初案とボツ案
・部屋の正面・天井・左右面の全部に投影しようとしたけど、広さもあって止めた。
・アミッドスクリーンを複数面に配置して、それぞれちょっとづつ違う像を投影して空間的に面白い像をトラッキングしながら映そうと思った。プロジェクタの条件も出て来るから手持ちの範囲にすることに。
・床に投影したかったけど、天井にプロジェクタを付けられるよーに穴あけからするのはさすがに言えなかった(w
・よく最初のKinect Hack時にあった透明人間とかにしようかなと思ったけど、子供向けにウケがどうかしら、と思ってやめた。
・投影している天井に手を上げるとオブジェクトが出てきて、正面の投影に何かアイテムを落としたり、その逆も楽しいかな。けど、事前に何人かに見せたらあまり天井見ないのよね…正面の方がインパクトあるし、結局天井にフワフラ浮かばせる事にした。
・夜の渋谷の窓から見える風景を写真に撮って、それを投影しながらジェスチャーで星でも降らせても良いかも。何か簡単そうだから止めた。
・Arduino/ジャイロ/Xbee/LEDなアイテムを持ってもらって、それを振ったり動かして遊ぶモノにしようかな…PS/Wiiとかでそういうの遊んでるだろうし、作ってみてやっぱり止めた。
・トラッキング&投影した人に、手を使って落書きとか絵を書くのもありかなー。と思って自分でやってみたら、あんまり面白く無くって止めた…書いた状態でプリントアウトして渡す感じにすればアリだったかな。
・手の所に常時、幾何的な大小様々なキラキラを表示させておこうかしら…と表示してみたら割と綺麗で良い感じだった。

何と言うか、Arduinoとかの端末も用意してその場で作りながら考えるパターンで。部屋の机・椅子の運び出しとかの準備、採光が強いのもあって暗幕の手配とかしてくれて感謝です。プログラムとかはgithubの方にアップしてあるもので。センサーを部屋に配置して、空間全体をセンシングな状態にしてみたいとかはあるけど機会があったら。

ウケ自体は割と良い感じでした。ずっと走り回ったり、手から色々と出して遊んでいたり、午後からはずっと誰かしら遊んでいたですね。自分もずっと説明で体をたっぷり動かして良い運動になった感じ。

openFrameworksでKinect v2

ちょっとサンプルと実際に使う感じで整理したクラスをアップした。プラグインって程でもなく、サクット使える感じで。Visual Studioの設定とかはこっちを参照

kinectv2sample

流れ的にはKinect v2用SDKの細かい処理はバックグラウンドスレッドで実行して、フロントではバックグラウンドスレッドで取得したデータ処理を行う感じ。色んな方のソースをつまみ食い参考にさせてもらって、マルチスレッド用のロックをちょこちょこ入れている。メモに近いコードだけど、まぁ普通に使ってこんな感じの電気ビリビリ&パーティクルパラパラとかもサクっと出来る感じ。

(続)8pinoを使ってみる

8pinoを使ってみるに続いて、8pinoを使ってArduinoっぽいことをしてみる。まず最初に…ブレッドボードに指せるように8pinoにピンヘッダを付ける。これはわりと決断が必要になる。いや、作業自体はサクッと出来るんだけど、AgICにくっ付けたみたいに、このめちゃ小さい&薄い8pinoにピンヘッダを付けて良いものかどうか…しかも1stの8個のうちの1個をゲットしたのに、ピンヘッダを付けて大きくする事はこの小ささに反する行為なのでは無いか…という決断力が必要になる。そう、自分の判断が正しいのかどうか?という心の葛藤が…

ブレッドボードに差したいという欲求は、直撃でハンダ付けするよりお手軽に試せるという所もあって…まぁ、あとでピンヘッダはハンダを取って外しちゃえば良いっか!!と思って、ピンヘッダを付けちゃうことに><

まずは、リセットボタンとユニバーサル基板になっている部分を切離して、

まずはブレッドボードにピンヘッダを差しといて、この上に8pinoを置いてハンダ付けをする。

差しといたピンヘッダに8pinoを置いて…ちょちょっとハンダを付けて…

かんりょー!!8pinoが小さすぎて、iPhoneのカメラだとピンぼけしまくる素敵っぷりwww

続いて動作確認。USBを差してバッチリ動く。

んで、これから実際のセンサーを使ってみる。ここでは、目の前にあったGP2Y0A21YK(赤外線距離センサー)とLEDを使って、距離に応じてLEDの光をPWMで強弱を付ける感じの物を作ることに。
Arduino IDEでサクッと書けるから、ちょーーーー簡単!!!!以下な感じでバッチリ動く。

スケッチはめちゃシンプル。[len*2]ってしているのは、GP2Y0A21YKが距離が60-80cmくらいまでしか取れないから、2倍してPWM(0-255)に合わせて光の強さを変えている。

void setup() {
  pinMode(0, OUTPUT);
  pinMode(1, INPUT);
}

void loop() {
  int val = analogRead(1);
  int len = 18618/val;
  
  if (len * 2 <= 255)
    analogWrite(0, len * 2);
  delay(10);
}

8pinoを使ってみる

品モノラボに行ってきた。何気に自分、行くのが2回目という(いつも行こうと思ってはいるですが…)。いやー、刺激的っすねー。Web系でもあまり聞かないようなブッ飛び系のアイディアの話を聞いたりして、率直にモノ系以外の人でも参加してみたらメッチャ面白いと思う。

そして…8/8とくれば、8pinoにドキドキしていたら、田中さんよりジャンケン大会で限定8個の争奪戦と!!オイラ、ジャンケン大会とかめっちゃ弱いというか自信のひとかけらも無かったけど、勝っちゃいました。この場で勝負運を発動できたようで、ホントまぢで嬉しいぃぃぃ。

その場でまずは開封の儀を。まずは包装はこんな感じでカッコイイ。

中身をあけると…梱包物一覧は。

ちっちぇぇぇぇー!!早速、その場でマイクロUSBの端子をお借りしてチカチカーっと!!

この小ささに反比例して、むっちゃテンション上がりまくり。深爪な自分の指先ほどの大きさ。
Arduino IDEでの使い方は8pinoにアップされている通りで、自分はMacOS/Windows7のどちらでもArduino IDEからソースを焼け込めた。Windows7の方は追加でドライバを入れれば問題無し。MacはTrinketのIDEを入れて即使える。以下、Macでのやり方は…

Arduino IDEをサイトからダウンロードしたら書いてある通りに、まずはマイコンボードで「Trinket 8MHz」を選択。

次に「USBtinyISP」を選択

これで完了。ちなみに、Arduino IDEから書き込みの時、”Could not find USBtiny device (0x1781/0xc9f)”なんて書き込み失敗が出ると思うけど、8pinoとUSBの抜き差しがリセットという事は…そう、8pinoのUSBを抜き差しした10秒間が書き込みのとき。抜き差しした時にIDEから書き込みをポチっとすれば、すんなり書き込み完了する。

そして、8pinoをマイクロUSBにつけてLチカのコードをサクッと書き込んで終了!!LEDのピンを挟む感じで付けると特にハンダも使わないで動確できる。こんな感じでLEDのピンでキュッと挟んで。

チカチカー!!

そしてAgICとコラボってみる

薄っすーぃ!!ペラッペラで紙と一体化してるよw
サクッと折り紙にして仕込んじゃえるね。

AgICのは、最初の8個という事で、いつもの勢いでしょっぱなからハンダ付けするのは忍び無さ過ぎる…と思ってAgICを使って紙に書くことにした。ATTINY85と一緒な感じでPWMもバッチリー。ちょぴーっとだけ、ハンダ付けしちゃおっかなー。ピンヘッダを付けてブレットボードに刺せるのは合わせてみたらバッチリ出来るのを確認したし、あとはハンダ付けしちゃおーかしらーってオイラの心ひとつ。折角AgIC使って載せられたから、紙の上にセンサー載せちゃおーかしら。指先に8pinoを載せて、何かセンサー反応させて指先ピカピカー!!とか。

Arduino IDEでプログラムをサクッと書いて、この小ささに収めて動かせるというのは、かなり可能性を感じる。Makerやモノ寄りな人だけじゃなく、アートや音系、クリエイターの方でもArduinoを使った作品はよく見るし、この極小サイズは考えること&想像力(妄想力)が膨らみまくると思う。

追記) ピンヘッダの取り付けと、GP2Y0A21YK(赤外線センサ)を一緒に使ってみた内容はこちら。(続)8pinoを使ってみる

openFrameworks 0.8.3 and Kinect v2

環境は以下
– Windows 8.0
– VS 2012
– openFrameworks 0.8.3(x86)

まずMSのサイトからKinect SDKをダウンロードしてきてインストール。

1. Includeに$(KINECTSDK20_DIR)¥inc;を追加

2. Libに$(KINECTSDK20_DIR)¥lib¥x86;を追加

3. DependenciesにKinect20.libを追加

4. コードを書く
Kinect for Windows v2 Developer Preview入門 ― C++プログラマー向け連載をほぼコピってof向けに整形しただけですが…

ofApp.h

#pragma once

#include "ofMain.h"
#include "ofxOpenCv.h"
#include <kinect.h>
#include <Windows.h>

using namespace cv;

template
inline void SafeRelease( Interface *& pInterfaceToRelease )
{
	if( pInterfaceToRelease != NULL ){
		pInterfaceToRelease->Release();
		pInterfaceToRelease = NULL;
	}
}

class ofApp : public ofBaseApp{
	public:
		void setup();
		void update();
		void draw();

		bool initializeKinectv2();

		IKinectSensor* pSensor;
		IDepthFrameSource* pDepthSource;
		IColorFrameSource* pColorSource;
		IBodyFrameSource* pBodySource;

		IColorFrameReader* pColorReader;
		IBodyFrameReader* pBodyReader;
		IDepthFrameReader* pDepthReader;

		IFrameDescription* pDepthDescription;
		IFrameDescription* pColorDescription;

		ICoordinateMapper* pCoordinateMapper;


		// buffer
		ofxCvGrayscaleImage grayscaleImage;
		ofxCvColorImage colorscaleImage;

		// 
		int depthWidth, depthHeight;
		unsigned int depthBufferSize;

		int colorWidth, colorHeight;
		unsigned int colorBufferSize;

};

ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
	ofSetVerticalSync(true);
	ofBackground(255, 255, 255);
	// ofSetFullscreen(true);
	ofEnableAlphaBlending();
	ofEnableSmoothing();
	ofSetBackgroundAuto(true);

	if (!this->initializeKinectv2())
		exit();
}

bool ofApp::initializeKinectv2() {
	HRESULT hResult = S_OK;

	// Open Kinect
	hResult = GetDefaultKinectSensor( &this->pSensor );
	if( FAILED( hResult ) ){
		std::cerr << "Error : GetDefaultKinectSensor" << std::endl;
 		return false;
 	}
 	hResult = this->pSensor->Open( );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::Open()" << std::endl;
 		return false;
 	}

 	// Open Source
 	hResult = this->pSensor->get_ColorFrameSource( &this->pColorSource );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::get_ColorFrameSource()" << std::endl;
 		return false;
 	}
 	hResult = this->pSensor->get_BodyFrameSource( &this->pBodySource );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::get_BodyFrameSource()" << std::endl;
 		return false;
 	}
 	hResult = pSensor->get_DepthFrameSource( &this->pDepthSource );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::get_DepthFrameSource()" << std::endl;
 		return false;
 	}
 	// Open Reader
 	hResult = this->pColorSource->OpenReader( &this->pColorReader );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IColorFrameSource::OpenReader()" << std::endl;
 		return false;
 	}
 	hResult = this->pBodySource->OpenReader( &this->pBodyReader );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IBodyFrameSource::OpenReader()" << std::endl;
 		return false;
 	}
 	hResult = this->pDepthSource->OpenReader( &this->pDepthReader );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IDepthFrameSource::OpenReader()" << std::endl;
 		return false;
 	}
 	// get descriptions
 	hResult = pDepthSource->get_FrameDescription( &this->pDepthDescription );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IDepthFrameSource::get_FrameDescription()" << std::endl;
 		return false;
 	}
 	hResult = pColorSource->get_FrameDescription( &this->pColorDescription );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IColorFrameSource::get_FrameDescription()" << std::endl;
 		return false;
 	}
 	// get coordinate mapper
 	hResult = this->pSensor->get_CoordinateMapper( &this->pCoordinateMapper );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::get_CoordinateMapper()" << std::endl;
 		return false;
 	}
 	this->pDepthDescription->get_Width( &depthWidth ); // 512
	this->pDepthDescription->get_Height( &depthHeight ); // 424
	this->depthBufferSize = depthWidth * depthHeight * sizeof( unsigned short );

	this->pColorDescription->get_Width( &colorWidth );
	this->pColorDescription->get_Height( &colorHeight );
	this->colorBufferSize = colorWidth * colorHeight * 4 * sizeof( unsigned char );

	this->grayscaleImage.allocate(depthHeight, depthWidth);
	this->colorscaleImage.allocate(colorHeight, colorWidth);

}

//--------------------------------------------------------------
void ofApp::update(){

	// get depth frame
	Mat bufferMat( depthHeight, depthWidth, CV_16SC1 );
	Mat depthMat(depthHeight, depthWidth, CV_8UC1 );

	cv::Mat colorBufferMat( colorHeight, colorWidth, CV_8UC4 );
	cv::Mat colorMat( colorHeight, colorWidth, CV_8UC4 );

	// Frame
	IDepthFrame* pDepthFrame = nullptr;
	HRESULT hResult = pDepthReader->AcquireLatestFrame( &pDepthFrame );

	if(SUCCEEDED( hResult )){
		hResult = pDepthFrame->AccessUnderlyingBuffer( &depthBufferSize, reinterpret_cast<UINT16**>( &bufferMat.data ) );
		if( SUCCEEDED( hResult ) ){
			bufferMat.convertTo(depthMat, CV_8U, -255.0f / 4500.0f, 255.0f);
			grayscaleImage.setFromPixels(depthMat.data, depthWidth, depthHeight);
		}
	}
	SafeRelease( pDepthFrame );


	// get color frame
	cv::Vec3b color[6];
	color[0] = cv::Vec3b( 255,   0,   0 );
	color[1] = cv::Vec3b(   0, 255,   0 );
	color[2] = cv::Vec3b(   0,   0, 255 );
	color[3] = cv::Vec3b( 255, 255,   0 );
	color[4] = cv::Vec3b( 255,   0, 255 );
	color[5] = cv::Vec3b(   0, 255, 255 );

	IColorFrame* pColorFrame = nullptr;
	hResult = pColorReader->AcquireLatestFrame( &pColorFrame );
	if( SUCCEEDED( hResult ) ){
		hResult = pColorFrame->CopyConvertedFrameDataToArray( colorBufferSize, reinterpret_cast<BYTE*>( colorBufferMat.data ), ColorImageFormat_Bgra );
		/*
		if( SUCCEEDED( hResult ) ){
			cvtColor(colorBufferMat, colorMat, CV_BGR2RGB);
			colorscaleImage.setFromPixels(colorMat.data, colorWidth, colorHeight);
		}
		*/
	}
	SafeRelease( pColorFrame );

	// get body frame
	IBodyFrame* pBodyFrame = nullptr;
	hResult = pBodyReader->AcquireLatestFrame( &pBodyFrame );
	if( SUCCEEDED( hResult ) ){
		IBody* pBody[BODY_COUNT] = { 0 };
		hResult = pBodyFrame->GetAndRefreshBodyData( BODY_COUNT, pBody );
		if( SUCCEEDED( hResult ) ){
			for( int count = 0; count < BODY_COUNT; count++ ){
 				BOOLEAN bTracked = false;
 				hResult = pBody[count]->get_IsTracked( &bTracked );
				if( SUCCEEDED( hResult ) && bTracked ){
					Joint joint[JointType::JointType_Count];
					hResult = pBody[ count ]->GetJoints( JointType::JointType_Count, joint );
					if( SUCCEEDED( hResult ) ){
						// Left Hand State
						HandState leftHandState = HandState::HandState_Unknown;
						hResult = pBody[count]->get_HandLeftState( &leftHandState );
						if( SUCCEEDED( hResult ) ){
							ColorSpacePoint colorSpacePoint = { 0 };
							hResult = pCoordinateMapper->MapCameraPointToColorSpace( joint[JointType::JointType_HandLeft].Position, &colorSpacePoint );
							if( SUCCEEDED( hResult ) ){
								int x = static_cast( colorSpacePoint.X );
								int y = static_cast( colorSpacePoint.Y );
								if( ( x >= 0 ) && ( x < colorWidth ) && ( y >= 0 ) && ( y < colorHeight ) ){ 									if( leftHandState == HandState::HandState_Open ){ 										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 128, 0 ), 5, CV_AA );
 									} else if( leftHandState == HandState::HandState_Closed ){
 										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 0, 128 ), 5, CV_AA );
 									} else if( leftHandState == HandState::HandState_Lasso ) {
 										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 128, 128, 0 ), 5, CV_AA );
 									}
 							        }
 							}
 						}
 						// Right Hand State
 						HandState rightHandState = HandState::HandState_Unknown;
 						hResult = pBody[count]->get_HandRightState( &rightHandState );
						if( SUCCEEDED( hResult ) ){
							ColorSpacePoint colorSpacePoint = { 0 };
							hResult = pCoordinateMapper->MapCameraPointToColorSpace( joint[JointType::JointType_HandRight].Position, &colorSpacePoint );
							if( SUCCEEDED( hResult ) ){
								int x = static_cast( colorSpacePoint.X );
								int y = static_cast( colorSpacePoint.Y );
								if( ( x >= 0 ) && ( x < colorWidth ) && ( y >= 0 ) && ( y < colorHeight ) ){
									if( rightHandState == HandState::HandState_Open ){
										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 128, 0 ), 5, CV_AA );
									}
									else if( rightHandState == HandState::HandState_Closed ){
										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 0, 128 ), 5, CV_AA );
									}
									else if( rightHandState == HandState::HandState_Lasso ){
										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 128, 128, 0 ), 5, CV_AA );
									}
								}
							}
						}

						// Joint
						for( int type = 0; type < JointType::JointType_Count; type++ ){
 							ColorSpacePoint colorSpacePoint = { 0 };
 							pCoordinateMapper->MapCameraPointToColorSpace( joint[type].Position, &colorSpacePoint );
							int x = static_cast( colorSpacePoint.X );
							int y = static_cast( colorSpacePoint.Y );
							if( ( x >= 0 ) && ( x < colorWidth ) && ( y >= 0 ) && ( y < colorHeight ) ){
								cv::circle( colorBufferMat, cv::Point( x, y ), 5, static_cast< cv::Scalar >( color[count] ), -1, CV_AA );
							}
						}
					}
				}
			}
			cvtColor(colorBufferMat, colorMat, CV_BGR2RGB);
			colorscaleImage.setFromPixels(colorMat.data, colorWidth, colorHeight);
		}
	}
	SafeRelease( pBodyFrame );

}

//--------------------------------------------------------------
void ofApp::draw(){
	colorscaleImage.draw(0, 0);
	grayscaleImage.draw(0, 0);
}

5. 実行

脳波で迷路@ヤミ市

迷路いっぱい出来ました。

個々人の迷路は32×32マスで作成して、生成には約1分で完了ですね。そして79人分全員の脳波データを集めて1個の大きな迷路を作成しました。こちらは120×120マスで生成した結果はこちらです。

こちらは、誰かが(脳波で)作成した個人の迷路です。

同じサイズで見ると、密度が全然違います。32マスの方は生成される迷路の総数は約40億、120マスの方は115京個くらいです。どちらも膨大なパターンです。

他の個々人で作成した迷路も「入り口・出口」を用意すると解けます。変な所に用意すると閉路になっている所もあるので。最後は持って行った光沢紙が無くって終了でした。

WordPressの高速化

自分がマジメにやる時のWPの高速化方法について。一応、色々と設定とかをして、仮想(お名前.com KVM, MEM 2GB, CPU:3)サーバ1台で 10,000 access/sec くらいは普通に捌けてCPU負荷もほとんど上がらない感じには出来る。つかキャッシュだけどねw
以下、全部やっても1時間もかからずサクっと出来るはず。

– 構成
NginX + WordPress(FastCGI/Apacheどっちでも) + MySQL
まぁ、普通の3層構成っすね。

– 路線
簡単なチューニングとNginXのキャッシュを使う。

– 方法
1. APCを使う
これはオンにすれば即完了。迷う事無し。

2. ngx_pagespeedを入れてみる
多少は変わる。気休めだと思うけど。

3. NginXでgzipを有効にする。
いわゆるコンテンツの圧縮転送。高速化というか、クライアント側にも優しくなれる。

4. NginXのキャッシュを使う
これが本質。普通にNginXのキャッシュを使うと、WP側で記事の更新をしてもキャッシュがクリアされるまで記事が更新されないという残念な事になる。また、WordPressのSuperCacheなる物も結局はAP層(WP)までアクセスが来るので、出来るだけNginX側で全て完結させる。流れ的には以下。

4.1. nginx cache purgeモジュールをNginXに導入する
4.2. Word Press側にNginx Proxy Cache Purge WordPressをプラグインからインストール
4.3. NginX側のconfig, WP側の設定をして終わり。

実際の個別の方法とかはググれば出てくるからそれを参照に。あとwp-adminをキャッシュ対象から外すのも忘れずに。基本的に全部NginX側でキャッシュ、記事やコメントとか変更があったらそのページだけPurgeするという素敵な感じになる。他に色々とプラグインを入れて重いぜ…って事もあんまり関係無くなる。
WordPress側のキャッシュを使う例がよく散見するけど、NginXを使っているならそこで完結させた方が良い。あとどーしても、ApacheでWord Pressを動かしたいぜ!!という理由があれば、Varnishを使うとかってのもあるけど、余計なプロセスは出来れば動かしたく無いからね。

– その他(備忘)
カーネルチューニングとかってのもあるけど、あんまり劇的には変わらんでしょう。他にDBのバッファを増やすとかも、ただ、ふつーのVPSのメモリ(2G-4G)でそれをやった所であんまり何かパッとしないもんね。
他に自分がよくやったりする手法では、PHPのプロセス事前生成& Persistenceを有効にしたり、NginX/Apacheの基本的な設定の確認・見直しとか。PHPってマルチスレッドとかじゃなく、1アクセスに対してforkされた1個のPHPプロセスが対応して動作するから、仮に1アクセスに1秒かかるプログラムの場合、同時100アクセスが瞬間にきたら100個プロセスが無いとあとはキュー待ちというか、backlogに回って順番待ちになる。つまり、FastCGI/Apacheでのプロセス数とAPの秒間の性能、更にCPU数(LoadAvgのキュー)といった感じで可視化される訳で、結局PHPみたいな1リクエストに対して1プロセスで応答する物って、アクセス数を捌くためには最終的にはプロセス数・メモリ・CPU数・サーバ数とリクエスト数の関係がスケールする事になる。ThreadingしたところでCPUリソースは結局消費される訳だけどね。それを避けるために、キャッシュとかを使って軽くするって感じー。