KLab若手エンジニアの これなぁに?

KLab株式会社の若手エンジニアによる技術ブログです。phpやRubyなどの汎用LLやJavaScript/actionScript等のクライアントサイドの内容、MySQL等のデータベース、その他フレームワークまで幅広く面白い情報を発信します。

2010年07月

社内向けOpenCV勉強会を公開しちゃいます!

はじめまして、makki_dです。 四月に新卒として入社したばかりの、若手どころかひよっこの技術者見習いです。 ある日、社内のメーリングリストでOpenCVという単語を出したところ、「ちょっと使ってみたいという人も多いみたいだから、集めて勉強会開かない?」という流れになり、あれよあれよという間に主催することになってしまいました。 KLabでは毎週のように社内勉強会が行われています。このOpenCV勉強会もそんな社内勉強会のひとつです。今回、KLabをもっと広く知ってもらうための試みとして、社外の方をこの社内勉強会に招待することになりました!OpenCVを一緒に勉強してみたい方、KLabに興味のある方、あるいは森タワーの中を見てみたいという方は、ぜひご応募ください。 ※募集を締め切りました (7/30追記) たくさんのご応募ありがとうございました。応募いただいた方には通知のメールをお送りいたします。
テーマ:
OpenCV初心者向け勉強会
開催日時:
2010年8月6日(金) 18:00~21:00
場所:
六本木ヒルズ森タワー20F KLab株式会社 会議室
演題(予定):
  1. ゼロからはじめるOpenCV
  2. 画像ってなぁに?
  3. Pythonデモ使えるOpenCV
  4. OpenCV+Python+物理エンジン=!?
  5. haar-like特徴分類
定員:
5名程度 (先着順)
参加費:
無料 (懇親会を除く)
応募方法:
rd-workshop(_at_)klab.org 宛てに氏名、電話番号(勉強会当日の緊急連絡用)、所属(勤務先、学校等)をお知らせください。その際、タイトルに「OpenCV勉強会参加希望」を含めてください。
※(_at_)をアットマーク@に置き換えてください
その他:
勉強会後に懇親会(自由参加)を予定していますが、こちらは20歳以上に限らせていただきます。 先着順になりますので、参加を希望される方はお早めにご応募ください。
質問等はコメント欄や応募先メールアドレスで受け付けています。遠慮なくお尋ねください。

iPhoneをアナログゲームコントローラにしてみる(2)

こんにちは、ponpoko1968です。 前回の続きです。

ボタンを追加する

前回はコントローラの左右の動きを加速度センサーを用いて検知する部分を説明しました。 今回は「前進」「後進」「A」「B」ボタンを追加します。比較的ありがちな部分なのでさらっと説明します。 まず、AnalogRemoteViewControllerクラスにボタンを追加します。

@interface AnalogRemoteViewController : UIViewController {
...
  UIButton* buttonForward;
  UIButton* buttonBackward;
  UIButton* buttonA;
  UIButton* buttonB;
  NSArray* buttongs;
  unsigned char   buttonState;
}
...
@property(nonatomic, retain) IBOutlet  UIButton* buttonUp;
@property(nonatomic, retain) IBOutlet  UIButton* buttonDown;
@property(nonatomic, retain) IBOutlet  UIButton* buttonA;
@property(nonatomic, retain) IBOutlet  UIButton* buttonB;
ViewDidLoadメソッドが呼ばれるタイミングで、作ったボタンをNSArrayに格納し、コントローラの状態更新時に使います。

 buttons =  [NSArray arrayWithObjects:buttonForward,buttonBackward,buttonA,buttonB,nil];
  [buttons retain];
buttonStateはビット単位で各ボタンの押下状態を保持します。NSArrayへの格納順に、下位ビットから、「前進」「後進」「A」「B」の順に格納します。 このような処理を行う理由は、リアルタイムに、なおかつ極力正確に、リモートマシンへコントローラの状態を送信するためです。後ほど詳述します。 下図のように、InterfaceBuilderでビューにボタンを貼り付けて、 4つ全てのボタンの下記イベントを、
  • Touch Down  -- ボタンが押された
  • Touch Up Inside -- ボタンが離された(ボタン領域の内側で)
  • Touch Up Outside -- ボタンが離された(ボタン領域の外側で)
- (IBAction)respondToButton:(id)sender forEvent:(UIEvent*)event メソッドに反応させるようにします。 またこのとき、AnalogRemoteViewControllerクラスに定義した各ボタンオブジェクトと、Interface Builder上のGUIボタンを結びつけることを忘れないようにしてください。

コントローラの状態を更新する

ボタンにタッチされた際、離された際の動作を記述します。

- (IBAction)respondToButton:(id)sender forEvent:(UIEvent*)event {
  NSUInteger buttonId;
  // イベントの送信元オブジェクトを同定
  if( (buttonId = [buttons indexOfObject:sender]) != NSNotFound ){
  // イベントの種類を判別(押下か、離されたのか)
    UITouch* touch = [[event touchesForView:buttons[ buttonId ]] anyObject];

  // ボタン状態のビットフィールドを更新
    if( touch.phase == UITouchPhaseBegan ) { // 押下
      buttonState |= 1 << buttonId;
    }else if( touch.phase == UITouchPhaseEnded ) { // 離された
      buttonState &= ~(1 << buttonId);
    }
  }
}

サーバに接続する

ここからGame Kitを用いた通信の説明です。Game Kitは名前から連想されるようなゲームを作るためのライブラリではなく、無線LANもしくはBluetoothをもちいてiPhone/iPad同士で簡単にP2P通信が出来るようにするフレームワークです。 くわしくは、 Game Kitプログラミングガイドを参照して下さい。 今回は、GKPeerPickerという便利クラスをつかってみます。このクラスは通信相手を探し出してGUI表示し、相手との接続までをサポートする便利クラスです。 AnalogRemoteViewControllerの宣言部で、GKPeerPickerControllerDelegate,GKSessionDelegateプロトコルを追加します。また、通信セッション関連の2つのメンバを追加します。
@interface AnalogRemoteViewController : UIViewController {
...
  
  //  Game Kit関連
  GKPeerPickerController* picker;
  GKSession       *gameSession;
  NSString        *gamePeerId;
}

...
@property(nonatomic, retain) GKSession   *gameSession;
@property(nonatomic, copy)   NSString    *gamePeerId;
プロパティの宣言部で、gamePeerIdは代入時の動作として、「copy」を指定していることに注意してください。これは、通信セッションが切れてしまった場合に、gameSessionはリリースされてしまいますが、接続先を表すgamePeerId文字列をクラス側でコピーして保持しておくことで再接続を試みることに使う事を意図しています。 さらに、viewDidLoadメソッドの呼び出しに、

  picker = [[GKPeerPickerController alloc] init];
  picker.delegate = self;
  picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
  [picker show];
ここで、"GKPeerPickerConnectionTypeNearby"と指定しているのは、Bluetoothによる接続を意味します。 この記事の執筆時点ではGKPeerPickerはBluetooth接続のみサポートしているようなので、無線LANを用いて複数のiPhone/iPadが参加するような比較的大がかりな通信を行いたい場合には、GKSessionDelegateでサポートされているメソッドを実装して、通信相手の選択などのGUIを作成する必要があります。 上記のコードのうち、 [picker show]の実行で下図のような画面が出ます。 次にGKPeerPickerからのデリゲートメソッドに対応するコードを記述します。 まず、これからはじめる通信セッションの識別情報を聞いてきます。

- (GKSession *)peerPickerController:(GKPeerPickerController *)picker sessionForConnectionType:(GKPeerPickerConnectionType)type { 
  GKSession *session = [[GKSession alloc] initWithSessionID:@"KLabRemoteSample" displayName:nil sessionMode: GKSessionModePeer]; 
  return [session autorelease];
}
initWithSessionID:”@"KLabRemoteSample"の部分で、セッションを識別する文字列を指定します。GameKitはここで指定した文字列と同じ文字列をつかって作成された通信セッションで待ち受けているサーバを探します。 上記コードはGameKitのサンプルどおりですが、最後の行で、[session autorelease]としています。コメントにもあるように、GKPicker側がsessionを保持するため、ユーザ側のクラスでは保持する必要がないことを意味します。この後、Game Kit通信セッションの確立後のデリゲートメソッドの引数としてユーザ側に渡されるため、このタイミングでsessionへの参照を保持する必要はあまりないでしょう。 サーバとの接続が確立すると、下記のメソッドが呼ばれます。


- (void)peerPickerController:(GKPeerPickerController *)_picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session { 
  self.gamePeerId = peerID;
  
  self.gameSession = session; 
  self.gameSession.delegate = self; 
  [self.gameSession setDataReceiveHandler:self withContext:NULL];
  
  // GKPeerPickerのダイアログを消去
  [picker dismiss];
  picker.delegate = nil;
  [picker autorelease];
}

データを送信する

コントローラの状態が変更されるタイミング、すなわちボタンの押下とリリース、加速度センサーの更新時にデータを送信するメソッドを実装します。Game Kitで送信するデータはNSDataクラスに格納してフレームワークに渡します。


- (void) sendControllerStatus {
  if( gamePeerId ){
    NSUInteger state[2];

    memcpy(state,&angleValue,sizeof(angleValue));
    state[0] = htonl(state[0]);
    state[1] = htonl( buttonState );
   
    NSData* data = [NSData dataWithBytes:state length:sizeof(state) ];
    NSError *error;
    NSArray* peers = [NSArray arrayWithObject:gamePeerId];
    [gameSession sendData:data toPeers:peers withDataMode: GKSendDataUnreliable error:&error];
ここで、withDataMode: GKSendDataUnreliableと指定しています。直訳すると「信頼性のない送信」という意味ですが、Game Kitから出力されるログの内容やマニュアルから推測すると、Game KitはBluetoothネットワーク上に構築されたIPネットワークを使用しているようで、結局の所UDPによる送信を行っているようです。UDPを使用した場合、その仕組み上、サーバ側がパケットを確実に受け取ることや、正しい順序でサーバにパケットの到着することが保証されません。そのかわり、通信にかかるコストが低いため、リアルタイム性は高まります。今回はコントローラの状態(傾き・ボタンの押下の有無)をほぼ定期的に、全て送信する事で、これらのメリット・デメリットに対応することにします。 次回はiPad上で動作するコントローラの状態を受信するサーバを作ってみます。
注)この記事の執筆中、筆者が開発に用いているiPhoneとxcodeをiOS4対応にバージョンアップしてしまいました。サンプルをiOS3.1.2で実行される方は、xcodeでターゲットのビルド設定を戻して試してみてください。
サンプルをダウンロード

iPhoneをアナログゲームコントローラにしてみる(1)

こんにちは、精神年齢は若手以下かもしれないponpoko1968です。 このたび、弊社ではiPhoneとiPadを連携させて、パーティなどで多人数で楽しめるゲームを開発し、見事IVS LaunchPadの第4位に輝いたのですが、似たようなスキームで、iPhoneをiPad上のリアルタイムゲームのリモートコントローラとして用いることが出来ないか試してみました。 今回は、iPhoneの加速度センサー機能を使って、デバイスの傾きを検出し、iPad上で動作するサーバに送信するアプリを作ってみました。 仕様としては、
  • 傾きで左右の方向決定
  • 4つのボタン(タッチ)で前進、後進、Aボタン、Bボタン
  • Game Kitをつかってサーバの検索と表示
  • サーバにコントローラの状態を送信してアプリをコントロール

テンプレートの生成

今回は単一画面のシンプルなアプリなので、「View based application」で作ります。 [caption id="" align="alignnone" width="677" caption="view-based application"]
view-based application


[/caption] 今回は「AnalogRemote」というアプリ名で作成します。 ドライビングゲームなど、傾き検出を用いるアプリでは、iPhoneをホームボタンが右に来るように横にして使うのが一般的らしいので、Info.plistの「initial interface orientations」という項目を「Landscape (right home button)」に設定することで、横画面で起動させます。


また、画面の向きを認識させるため下記のメソッドをオーバライドします。

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

加速度センサーによる傾きの検出

UIAccelerometerの使い方

傾きの検出には、 UIAccelerometerというクラスを用います。このクラスは、 sharedAccelerometerというクラスメソッドを用いることでシングルトンインスタンスを得ます。 UIAccelerometerはUIAccelerometerDelegateというプロトコルを通じて対象オブジェクトにデバイスの傾きを伝えるため、対象オブジェクトはUIAccelerometerDelegateプロトコルをサポートする必要があります。 今回は、唯一のビューコントローラクラスである、 AnalogRemoteViewControllerに UIAccelerometerDelegateをサポートさせます。 AnalogRemoteViewController.hを編集して、

@interface TanksControllerViewController : UIViewController<UIAccelerometerDelegate> {

...

@end
とします。 次に、AnalogRemoteViewControllerインスタンスのビューのローディングが終了したときに呼ばれるメソッドloadで、 UIAccelerometerの設定を行います。

- (void)viewDidLoad {

[super viewDidLoad];

// 0.1秒間隔で状態を通知

[[UIAccelerometer sharedAccelerometer] setUpdateInterval:0.1];

// デリゲート通知を自分(このインスタンス)に向けさせる

[[UIAccelerometer sharedAccelerometer] setDelegate:self];

...

}
デリゲート通知を設定されたクラスは、下記のメソッド

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
を実装することで、setUpdateIntervalで設定された時間間隔で、加速度センサーの状態が通知されます。

デバイスの傾きを検出する

加速度センサーはX,Y,Zの3軸をもちいてデバイスの状態を検知します。


下図のように、iPhoneを横に向けた状態では、地球から作用する重力、つまり下向きの力が作用するため、X軸が約−1の値を示します。


横に向けて、さらに傾けると、下図のように、X軸とY軸の両方に力が分散されます。傾きによって、X軸とY軸にかかる力の配分が変わるため、iPhoneの傾きを検出することができます。例えると、iPhoneの重心から重しを付けた糸を垂らしているイメージを思い浮かべて頂けるとわかりやすいかと思います。糸とiPhoneの角度を調べれば、iPhoneの傾きが求まると言うわけです。


加速度センサーの状態を表示する

デバッグ用に加速度センサーの状態をリアルタイムで見るために、画面に表示するようにします。 AnalogRemoteViewControllerのメンバにx,y,z軸の数値を表示するためのUILabelを追加します。

@interface AnalogRemoteViewController : UIViewController<UIAccelerometerDelegate> {

UILabel* x;

UILabel* y;

UILabel* z;

...

}

// Interface Builder連携のためプロパティとして定義

@property(nonatomic, retain) IBOutlet  UILabel* x;

@property(nonatomic, retain) IBOutlet  UILabel* y;

@property(nonatomic, retain) IBOutlet  UILabel* z;

...

@end
プロパティx,y,zのセッター・ゲッターを定義するため、 AnalogRemoteViewController.mに、下記のように追加します。

@implementation AnalogRemoteViewController

@synthesize x,y,z;
interface builderでビューにラベルを貼り付けて、UILabelと結びつけます。 デリゲートメソッド - (void) accelerometer:didAccelerate:を実装します。

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {

x.text  = [NSString stringWithFormat:@"%10.2f",acceleration.x];

y.text  = [NSString stringWithFormat:@"%10.2f",acceleration.y];

z.text  = [NSString stringWithFormat:@"%10.2f",acceleration.z];

}

X軸とY軸の逆正接を求め、角度を割り出します。


  float _angle;

  if( fabs(acceleration.x) > fabs(acceleration.z)){
    _angle = atan2(acceleration.y,-acceleration.x);

  }else {
    _angle = atan2(acceleration.y,-acceleration.z);
  }

※今回のコードでは、iPhoneがY軸を中心として一定以上地面に水平に傾いている場合には、X軸とZ軸の角度を求めるようにしています。 これで、傾きを検出することが出来ました。次回は他のボタン操作の検知と、サーバ(iPad)との通信について説明します。 サンプルをダウンロード [続く]

【LAMPで作るソーシャルアプリの負荷対策 ~アプリとインフラの調和のテクニック~】 

opt様が主催されている、ソーシャルアプリコンテストタイアップセミナーにKLabの森本が登壇しました。
森本 隼  KLab株式会社 プロジェクトマネジメント部 リーダー 2006年KLab株式会社にプログラマーとして入社。 自社メディア事業、SNS事業の開発リーダーを経験し、現在ソーシャルアプリ開発のPMとして活躍中。


  セミナーのテーマは 【LAMPで作るソーシャルアプリの負荷対策 ~アプリとインフラの調和のテクニック~】。現在ソーシャルアプリ周りで最もホットな高負荷対策について、KLabの取り組みを紹介しました。
セミナー風景


会場は満員御礼で立ち見もちらほら。おおよそ150人程度の方に聴講頂きました(感謝!)。 以下のとおり当日の資料を公開しました。(ソーシャルアプリに限らず)高負荷にお困りの方は必見です!


  同セミナーは当日Ustreamでも配信されました。ちょっと途中で途切れたりしたので3つに別れてしまいましたが雰囲気は伝わると思います。 タイアップセミナーのハッシュタグ#sac2010も盛り上がりましたのでそちらも合わせてご覧ください。

Web開発者のための大規模サービス技術入門 読んでみた

yoshida-kです。 社内で仙石CTOより、「このの本を読んでみたい人いないー?」っとの メールが社内に流れたため、条件反射で手を上げちゃいましたw
表紙
yoshida-kは、最近負荷対策を行ったりすることが多く、「大規模サービス」だったり 「データ構造、メモリ、DB」などのキーワードに敏感に反応してみたりします。 この本は、株式会社はてな様のサマーインターンで、学生向けに行った講義内容を 元にかかれて、大きく分けて3つの話題が書かれています。 1.大規模サービスにおいて発生する「悩み」と悩みに対しての「考え方」の概論 2.大規模サービスの「悩み」に対しての「実践」と「実例」 3.大規模サービスを「運用」する上でのインフラ基礎知識 といった感じでしょうか? それぞれをピックアップすると
1.では、データが肥大化していく事により、メモリにデータが乗らなくなった事によるdisk IOがmemory IOよりどれくらい重いものか?どれくらい速度が違うのか?なぜ違うのか?といった内容を、図解を含めて解りやすく説明されていたり、OS自体がどのような工夫をしてくれているかなどが解説されています。 (例:diskとmemoryのIOの違いや、OSのページキャッシュについて) さらに、実際にメモリに乗らなくなった場合に、どうやって対処するのか?や、対処する際の注意点がコレも図解や順序だてたわかりやすい文章で示されています。

2.では、1の内容を踏まえた上で、はてなブックマークのデータを利用した「データ圧縮」や「全文検索」 のプログラムを実際に書きながら「体験」することで「実践」を学んだ上で、必要性や重要性が語られます。

3.では、Webサービスにおける「スケーラビリティ」や「冗長性」、「Webサーバーの効率」についてアプリ開発者が、普段あまり触れることのないインフラ的な知識が語られており、前著の「24時間365日 サーバ/インフラを支える技術」の基礎知識編といった感じです。 また、「クラウド/リアルサーバ」やmemcached、TokyoTyrantなどの「KeyValueストレージ」、「OSの仮想化技術」などの、近年話題となっている技術のメリット、デメリットが語られています。

読んでみた感想ですが、今後KLabに入ってこられる新卒の開発者の方や若手のアプリ開発者にぜひとも一度読んでいただきたい!! とりあえずWebアプリは作れるが、負荷対策とかはさっぱりデスヨーーって方は特に! なぜか? その理由はいくつか(いくつも?w)あります。 1.大規模の規模感の説明、そこから発生する問題の大きな部分から話が始まり、それぞれの問題を一つ一つブレイクダウンした形で解説されていく構成になっており、大規模サービスの負荷の全体像をつかみながら問題を理解していける本の構成 2.ヒットするかどうかが博打的なWebサービスにおいて、開発コストやスピードと安定性のトレードオフが存在する「現実」を前提として書かれているため、知識本で有りながら実用的な内容である点 3.ハードウェア・OSなどのプログラムを書くだけならばあまり気にしないが、高負荷サイトの開発時には気を配らなければならない点が、図解を添えて、どういう動作をしているから、こういう負荷になるといった形でOSやハードウェアに対しての知識がない人にも解るように書かれている点 この辺りが特に気に入った点でしょうか。 普段は慣例だったり、先輩方に教えていただいたknow-howなどでdisk readを避けたり、cacheを利用したりするコードを書いていたyoshida-kですが、この本を通して「なぜ早くなるか」、「なぜ必要か」といった知識を得れたことはとても大きい収穫でした。 あと、急いで読んじゃって中にあった課題にまだチャレンジできていません。 せっかくなのでチャレンジして、またブログに書かせていただこうと思います。 yoshida-k
 KLab若手エンジニアブログのフッター