Optimizing Collectionsを読んだ

Swift情報満載のobjc.ioで販売されている電子書籍のこちらを読みました。

www.objc.io

内容

Swiftで次のデータ構造を順に実装しながら、各種操作のパフォーマンスとその最適化方法について解説されています。

  • ソート済み配列 (Sorted array)
  • 順序集合 (Ordered set)
  • 赤黒木 (Red black tree)
  • B木 (B tree)

図やグラフもあって理解を助けてくれました。

特徴

Attabenchというツールを使って実際に計算時間を測定しながらパフォーマンスの遷移を確認しているので、その改善過程がわかりやすいです。アルゴリズム以外にもCPUのキャッシュなどによる影響についても触れられています。

また、各データ構造を実装するに当たりCopy On Writeも満たすように実装しているため、その部分でも勉強になりました。

その他学んだこと

CustomStringConvertibleプロトコル

CustomStringConvertibleプロトコルのdescriptionプロパティを実装しておくと、printなどでわかりやすく表示させることができます。

extension SortedSet {
    public var description: String {
        let contents = self.lazy.map { "\($0)" }.joined(separator: ",")
        return "[\(contents)]"
    }
}

同様にCustomPlaygroundQuickLookableプロトコルの実装により、Playgroundでの表示をわかりやすく変更できます。

Collectionプロトコル

Swiftで独自オブジェクトをコレクションとして扱うには、Collectionプロトコルに準拠する必要があります。 具体的には以下の実装が最低限必要です。

これだけで、for-inでの列挙やmap、filterなどの便利な処理が使えるようになります。

// 単純なコレクション
struct MinimumCollection {
    var values: [Int] = []
    
    init() {}
    init(values: [Int]) { self.values = values }
}

// Collectionプロトコル準拠
extension MinimumCollection: Collection {
    var startIndex: Int {
        return 0
    }
    
    var endIndex: Int {
        return values.count
    }
    
    subscript(i: Int) -> Int {
        return values[i]
    }
    
    func index(after i: Int) -> Int {
        return values.index(after: i)
    }
}

// 使用例
var c = MinimumCollection(values: [1, 2, 3, 4, 5, 6, 7])

print("First value is \(c.first!)")
print("Number of collection is \(c.count)")

for v in c {
    print("value: \(v)")
}

c.filter { $0 % 2 == 0 }
    .map { print("\($0) is even number.") }

isKnownUniquelyReferenced

書籍ではCopy On Writeを実装するために利用されていました。

この関数では、ある変数が参照しているオブジェクトが複数の参照を持つかを確認できます。関数がtrueを返す場合、その変数のみが参照していることを示します。その為、そのオブジェクトを直接変更しても他への影響がないことを確認できます。 もし他の変数からも参照されている場合(falseが返る場合)、オブジェクトを直接変更してしまうと、他の変数からも参照しているオブジェクトが変更されてしまうことになります。そのため、変更を行う際には予めそのオブジェクトをコピーしてから変更することで、Copy On Writeを満たすことになります。

Firebaseを使ってみた

GoogleFirebaseを利用したiOSアプリを作ってみました。

Willead

Willead

  • Tatsuyuki Kobayashi
  • 仕事効率化
  • 無料


ブラウザなど他のアプリで表示している記事を一時的に保存しておいて、後で読めるようにするアプリです。
記事を表示している時に標準のアクションボタンf:id:gibachan03:20171125191659p:plain:w25から保存できます。
f:id:gibachan03:20171125190836j:plain:w150 f:id:gibachan03:20171125190843j:plain:w150
iOSのShare extensionとして作成しています。まだまだ機能不足ですが自分のモチベーションが続いているうちにある程度の形にして公開しました。


私はiPhoneでの情報収集にこれらのアプリをよく活用させて頂いているのですが、これらでも利用できるようになっています。

カメリオ

カメリオ

  • 白ヤギコーポレーション
  • ニュース
  • 無料


ソースコードもこちらで公開しています。
github.com


その他

  • Firebaseは簡単に認証やデータベースを利用できてすごく便利。機能が多すぎて全然把握できてないけど、モバイルアプリに必要なことはなんでもできそう。もうしばらく遊んでみようと思う。
  • ライセンス表記のためにLicensePlistを使わせて頂いたのですが、こちらも何にも考えずにいい感じのリストになって楽だった。
  • Swift楽しい!

React & Flummoxチュートリアル

Flummoxは、いくつもあるFlux実装のうちの1つです。

ドキュメントにはいくつかの特徴が挙げられていますが、 Isomorphicであること(サーバとクライアントのどちらでもOK!)、ES6記法に対応していることなどがあります。

今回は、簡単なTODOアプリを作りながらFlummoxの使い方を紹介しようと思います。

このチュートリアルでは、ReactやFluxの初心者を対象にしています。簡単な概要ぐらいは知っているけど、これから始めるために簡単なサンプルが欲しいというような人にちょうど良いと思いますが、React全く初めてでも順を追えばなんとなくやっていることがわかると思います。

ソースコードこちらです。

<完成イメージ>

f:id:gibachan03:20150429140911p:plain

準備

コードを書き始める前にいくつか必要となるツールがありますので紹介します。

Gulp

よく使われているタスクランナーです。この後でコードを変換する必要が出てくるので、このツールを使ってその処理を自動化させます。

こちらはグローバルな環境にインストールしておく必要があるので、無い場合は次のようにインストールしましょう。

npm install -g gulp

Browserify

JavaScriptでモジュール管理をするためのツールです。JavaScriptのファイルを複数に分けておき、必要なモジュールをrequireで取得できるようにしてくれます。

Babel

ここではJavaScriptをES6記法で記述していくのですが、実際にブラウザで動作させるにはES5に変換する必要があります。Babelはその変換をしてくれるツールです。

面倒ですが、これらのツールを使ってコードを書く準備をしましょう。 まずはnpmでReactとFlummoxをインストールし、別に開発に必要となるツールを開発環境用にインストールします。

mkdir flummox-excersize && cd flummox-excersize

npm init

npm install --save react flummox

npm install --save-dev babelify browserify gulp vinyl-source-stream

babelifyはBrowserifyでBabelの変換をしてくれるモジュールで、vinyl-source-streamは、最終的に1つのJavaScriptファイルにまとめるためのモジュールです。

インストールが済んだら、gulpfile.jsを作成し、Gulpで実行する作業を書きます。

gulp

詳細に説明はしませんが、これでコマンドにgulpと打つだけでコードの変換が行われます。 今の時点ではファイルが無いのでエラーになります。

React - Hello World -

まずはReactでブラウザにHello Worldを表示させましょう。

Appコンポーネント

アプリのルートとなるコンポーネントを/components/App.jsxとして作成します。

import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div>
        <h1>Hello World</h1>
      </div>
    );
  }
}

export default App;

ES6記法で書いています。そのためReactのバージョンが0.13以上である必要があります。

app.js

次に、このコンポーネントを使用して描画するコードをapp.jsに書きます。

import React from 'react';

import App from './components/App.jsx';

React.render(<App />,
  document.getElementById('app'));

こちらもES6記法である以外は問題無いと思います。

index.html

最後にブラウザで表示されるindex.htmlを書きます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Flummox TODO</title>
</head>
<body>
  <div id="app"></div>

  <script src="build/bundle.js"></script>
</body>
</html>

ここで読み込んでいるbundle.jsは、gulpで変換して出力されるファイルです。

gulp

ブラウザでindex.htmlを開いて、"Hello World"が表示されたら成功です。

次からFlummoxを使って行きます。また、次からスペースの都合上コードは全て掲載しません。 必要であればサンプルコードをダウンロードしてご覧ください。

Action

Actionはビュー(Component)等で発生したイベントに応じて動作します。 モデル(Store)はActionを監視するので、Actionが動作したらそれに応じて内部のデータを変化させます。

ここではTODOアプリを作るので、TODOの新規作成、削除、終了フラグの切り替えのActionを定義します。

actions/Actions.js

class TodoActions extends Actions {
  // Todo新規作成
  createTodo(text) {
    return text;
  }

  // Todo削除
  deleteTodo(id) {
    return id;
  }

  // Todo終了フラグの切り替え
  toggleTodo(id) {
    return id;
  }
}

ActionsはFlummoxのActionsクラスを継承します。

Store

Storeはモデル(データ)を格納し、その状態を管理します。 Storeは、Actionsからの操作によりその状態を変化させ、その他からの影響は受けません。 また、Storeの状態が変化するとビュー(Component)がそれに応じて更新されます。

stores/TodoStore.js

import { Store } from 'flummox';

class TodoStore extends Store {
  ...
}

export default TodoStore;

StoreはFlummoxのStoreを継承します。

まずコンストラクタで、ActionとStoreの関連付けを行います。

constructor(flux) {
  super();

  // fluxインスタンスからActionsを取得
  const todoIds = flux.getActionIds('todo');

  // ActionとStoreメソッドを関連付け
  this.register(todoIds.createTodo, this.handleCreateTodo);
  this.register(todoIds.updateTodo, this.handleUpdateTodo);
  this.register(todoIds.deleteTodo, this.handleDeleteTodo);
  this.register(todoIds.toggleTodo, this.handleToggleTodo);

  // Storeの初期状態(初期データ)
  this.state = {
    todos: {}
  };

Actionが発生した場合、StoreはSetState状態を変化させます。

handleCreateTodo(text) {
  ...

  // 状態を変化
  this.setState({ todos });
}

setStateを呼ぶと状態が変化し、それがComponentへ伝えられる仕組みになっています。

Flux

ActionsとStoreを作ったので、これらを元にFluxインスタンスを作成します。

app.js

class Flux extends Flummox {
  constructor() {
    super();

    this.createActions('todo', Actions);
    this.createStore('todo', TodoStore, this);
  }
}

const flux = new Flux();

FluxはFlummoxを継承します。

fluxインスタンスを作成したらAppのComponentにインスタンスを渡します。

React.render(
  <FluxComponent flux={flux}>
    <App />
  </FluxComponent>,
  document.getElementById('app'));

ここで、FlummoxのFluxComponentというComponentを使用しています。 このComponentは、その配下のComponent(App)にFluxインスタンスを渡す役割があります。 つまり次のように書くのと同じイメージです。

<App flux={flux} />

ですがFluxComponentは便利な機能を持っています。 例えばAppの配下に子Componentがあり、その子ComponentもFluxインスタンスを必要とするのであれば、毎回このようにFluxインスタンスを渡してあげる必要があります。 ですがFluxComponentを使うとその記述を省くことができるようになります。 このような機能については次以降で確認できます。

Component

ComponentはStoreの状態を監視し、Storeの状態が変わったらComponentを更新します。 また、ボタンクリック等のユーザ操作に応じてActionを発生させます。

ここではComponentの階層構造を次のように考えます。

App
  - TodoEdit : Todo新規追加フォーム
  - TodoList : Todoリスト
    - TodoListItem

まず、components/App.jsxを書き換えます。

class App extends React.Component {
  ...
  render() {
    return (
      <div>
        <h1>Todo list</h1>
        <FluxComponent>
          <TodoEdit />
        </FluxComponent>
        <FluxComponent connectToStores={['todo']}>
          <TodoList />
        </FluxComponent>
      </div>
    );
  }
}

ここで、TodoEdit Componentの親としてFluxComponentを指定しています。 これにより、App Componentからfluxインスタンスが自動的に渡され、TodoEdit内でthis.props.fluxの形で使用できるようになります。

components/TodoEdit.jsx

...
handleSubmit(e) {
  e.preventDefault();
  if (this.state.newTodo.length === 0) return;

  // fluxインスタンスからActionsを取得し、Actionsを発生させる
  this.props.flux.getActions('todo').createTodo(this.state.newTodo);

  this.setState({
    newTodo: ''
  });
}
...

handleSubmitは新規Todo作成フォームのSubmitイベントハンドラです。 この中でActionを発生させ、その結果Storeの状態が変化することになります。

また、TodoList Componentの親のFluxComponentにはconnectToStoresの指定をしています。 これにより、'todo'で識別されるStore(TodoStore)がTodoListのpropsに展開されます。

components/TodoList.jsx

render() {
  var todos = this.props.todos;
  ...
}

結果

動作を確認しましょう。

gulpを実行した後にindex.htmlを開くとTodoアプリが動きます。 f:id:gibachan03:20150429140911p:plain

確認して頂きたいのはデータやイベントが常に1方向に流れていることです。

  • Todo新規作成 (ユーザがテキストを入力、ボタンクリック) => TodoActions(ceateTodo) => TodoStore => TodoList => TodoListItem

  • Todo削除 TodoListItem => (ユーザが削除ボタンクリック) => TodoActions(deleteTodo) => TodoStore => TodoList

このような構造でアプリを作る考え方がFluxというアーキテクチャであるということです。 より詳細な説明は公式をご確認ください。

まとめ

Reactを触りだすとFluxという概念が出てきます。初めてみると結構複雑そうで面倒な印象を持つかもしれません。 ですが、使ってみるとそれほど難しくないことがわかります。 なので、このチュートリアルがFlummoxもしくはReact/Fluxの最初の一歩として、ちょっとでも何かの参考になれば嬉しいです。

あと何か不足や間違いなどありましたらご連絡頂けるととてもありがたいです。 => Twitter@gibachan03

Flux入門してみた

Fluxとは?

Fluxはアプリケーションアーキテクチャの1つです。要は"こんな構造でアプリを構成すると見通しが良くなるよ"というような方針みたいなものですね。

元々はFacebookが提唱した考え方で、Reactと共に用いられるアーキテクチャです。

Reactでアプリを構築する際に、ある程度アプリが複雑になってくるとデータやイベントの流れが判りにくくなるので、Fluxの考え方を利用することで綺麗にまとめられるようになります。

こちらの記事にも少し詳しく紹介されています。最初見た時はちょっと複雑そうで拒否反応が起こりましたが、実際触ってみるとそんなでもないので大丈夫です。

で、Fluxの考え方を実際にコードに落とした実装はいくつもあり、どれを使うか迷います。 今回はわかり易そうだったFluxxorRefluxJSを使って簡単なアプリを作ってみました。

つくってたもの

B-Viewer はてなブックマークのホットエントリを閲覧するためのChrome拡張機能です。Fluxxorを使用しています。

f:id:gibachan03:20150406164038p:plain

piccheck 画像ファイルに埋め込まれているEXIFのデータを閲覧するWebアプリです。Refluxを使用しています。

f:id:gibachan03:20150406164033p:plain

感想

Fluxの考え方ではデータやイベントの流れが常に一方向に流れます。

データの流れ  : Store -> View
イベントの流れ:          View -> Action -> Store 

(かなり簡略化しています。詳しくは上記の記事をご覧下さい)

これが意識できるとアプリの構造をシンプルに考えられます。ReactはVirtualDOMについて良く取り上げられてるみたいですが、React & Fluxでアプリの構造全体がシンプルに記述できるところが個人的に気に入りました。

FluxxorもRefluxJSも基本的には考え方は同じだし、正直どちらも簡単なアプリだったので、あんまり比較はなりませんでしたね。 個人的にはRefluxの方がActioins等が簡略的に書けるので好みです。 ただRefluxJSについてはネット上の情報が少ないようです。 せっかくなので、後で使い方の解説みたいなものを書けたらと思っています。

もしこれから始めてみようという方の参考になればと思い、ここで公開しておきます。

Backbone.jsを使ってみて気になったこと

書籍の新着情報をチェックするWEBサービスmybookifyを作った時に、クライアントサイドのフレームワークとしてBackbone.jsを使用しました。

その時に気になったことがいくつかあったので、ここでまとめてみました。Backbone.jsの経験は少ないのでおかしな点があるかもです。何か気づいたことがありましたら教えてもらえると嬉しいです。

ここで使用したBackbone.jsのバージョンは1.1.2でした。

Model初期化時に引数を渡したい

Modelのメンバのデフォルト値は、defaultsを設定してあげれば良いです。

var Book = Backbone.Model.extend({
  defaults: {
    'title': 'MyBook'   // デフォルト値
  }
});

var book = new Book(); // => Object {title: "MyBook"}

ですが、インスタンス化するタイミングで値を設定したい時には次のようにオブジェクトを渡してあげます。

var Book = Backbone.Model.extend({
  defaults: {
    'title': 'MyBook'   // デフォルト値(この値は無視される)
  }
});

var book = new Book({
  'title': 'NewMyBook'
});
console.log(book.toJSON()); // => Object {title: "NewMyBook"}

ビューが2つあるとき、片方のビューで発生したイベントに対してもう片方のビューで処理したい時

これにはこちらで紹介されている方法が良さそうでした。

異なるビュー間のイベントを、どちらのビューからもアクセスできる別のオブジェクト(mediator)を経由する方法です。 次の例では、ViewAとViewBがある時に、ViewAでクリックされたイベントに対してViewBで処理を行っています。

// mediatorを定義
mediator = {};
_.extend(mediator, Backbone.Events);

// ViewAの定義
var ViewA = Backbone.View.extend({
  el: '#ViewA',

  events: {
    'click': 'OnViewAClick'            // 自分のビュー内のイベントを補足する
  },

  OnViewAClick: function() {
    mediator.trigger('OnViewAClick');  // mediatorにイベントを伝える
  }
});

// ViewBの定義
var ViewB = Backbone.View.extend({
  el: '#ViewB',

  initialize: function() {
    this.listenTo(mediator, 'OnViewAClick', this.OnViewBClick); // mediatorから伝わるイベントを拾う
  },

  OnViewBClick: function() {
    console.log('Hit!');
  }
});

ModelとREST APIとの連携

REST APIと対応付けるためには、Modelを次のように定義します。

var Book = Backbone.Model.extend({
  urlRoot: '/mybook-api',   // APIのurl

  idAttribute: '_id',       // ModelインスタンスのID
});

これによりGET、POST、PUT 、DELETEのリクエストを発行できるようになります。

発行先は/mybook-api/(_idの値)となり、それぞれ次のメソッドが対応しています。

var book = new Book();
// インスタンスがIDを持っていない時
console.log(book.isNew());  // => true

book.fetch();     // GET  .../mybook-api
book.save();      // POST .../mybook-api
book.destroy());  // リクエストは発行されない

// インスタンスがIDを持っている時
book.set('_id', 'myid');    // 仮にIDをmyidとしておく
console.log(book.isNew());  // => false

book.fetch();     // GET  .../mybook-api/myid
book.save();      // PUT .../mybook-api/myid
book.destroy();   // DELETE  .../mybook-api/myid

また、それぞれのメソッドではリクエスト成功時と失敗時の処理をコールバックで受け取ります。詳しくはドキュメントを確認して下さい。そしてこれらのメソッドは内部でsyncメソッドを呼んでいます。リクエストを細かくカスタマイズしたい場合はsyncメソッドを自分で再定義することになります。

続いて、モデルにparseメソッドを定義しておくと、サーバから返ってくるレスポンスを自分好みに処理できます。

var Book = Backbone.Model.extend({
    urlRoot: '/mybook-api',

    idAttribute: '_id',

    parse: function(response, options) {
      // レスポンス例: response == { status: 'success', book: { 'title': 'mybook' } }

      // レスポンスを処理して、モデルオブジェクトを返す
      return response.book;
    }
  });

複数のViewからアクセスしたいModelの持ち方(未解決)

BackboneではModelまたはCollectionはViewと1:1の関係になると思っています。

var MyModel = Backbone.Model.extend({});
var MyView = Backbone.View.extend({ model: MyModel });

var myModel = new MyModel();
var myView = new MyView({
  model: myModel
});

でも、Viewを越えて別のModelを参照したい時にはどうするのが良いのかわかりませんでした。

例えばAというModelとBというModelがあります。そしてViewAとViewBという、それぞれに対応するViewがあります。 このとき、ViewBでBを描画する際に、Aの値によって表示を変えるとします。

こんなときにどのような構造にすれば良いかわかりませんでした。 現状はAをグローバルなオブジェクトにして、どこからでもアクセスできるようにして対応しているのですが、あんまり綺麗じゃないような気がする。。。

取り敢えずこんなところです。まだちょっと思考錯誤しながらBackboneを使ってコードを綺麗にまとめられる方法を模索してます。もしかしたらAngularとか別のフレームワークに手を出したほうが良いのかなぁ?

ニコニコ動画のiPhoneアプリ作ってみた

初めてSwiftでアプリを作りました。せっかく作ったのでここで公開しときます。
試行錯誤しながらコツコツ頑張りました。

App Storeには公開するつもりはありません。著作権の問題がありそうですしね...
(よくわかんないけど個人で楽しむ分にはOKかな?)

機能

ニコニコ動画の「歌ってみた」カテゴリの動画をよく見るので、「歌ってみた」に特化したアプリです。
動画をダウンロードし、オーディオファイルに変換していつでも楽しめるようしています。
ミュージックプレイヤとしては基本的な機能しか実装できていないのですが、最初なのでここまでやれば取り敢えずいいかなぁと。

f:id:gibachan03:20141218213130p:plain f:id:gibachan03:20141218213137p:plain f:id:gibachan03:20141218213142p:plain

ソース

一応コードをgithubにあげておきます。swiftでの書き方に不安があるので、誰か奇特な方がダメ出しをしてくれるといいなぁ・・・
gibachan/NicoMusic · GitHub

Swift + OpenCVでリアルタイムに顔認識してみた2

前回に引き続き、今回はOpenCVを使って顔認識を行います。

分類器

画像データの中から顔を検出するための分類器となるファイルを用意します。
Githubからこちらをダウンロードします。
ダウンロードしたデータの中から、data/haarcascades/haarcascade_frontalface_alt.xmlファイルを取り出し、プロジェクトに追加します。

顔認識

OpenCVの処理はC++で書く必要があります。そのためにObjective-Cでラップしてあげます。
まずXcodeで「New File」から「Objective-C」のファイルを追加します。すると「Would you like to configure an Objective-C bridging header?」と聞かれるのでYesとします。 作成された.mファイルの名前を変更して.mmファイルとするとC++が使用できます。

では処理を書いていきます。

OpenCVSample-Bridging-Header.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface Detector: NSObject

- (id)init;
- (UIImage *)recognizeFace:(UIImage *)image;

@end

Detector.mm


#import "OpenCVSample-Bridging-Header.h"
#import <opencv2/opencv.hpp>
#import <opencv2/highgui/ios.h>

@interface Detector()
{
    cv::CascadeClassifier cascade;
}
@end

@implementation Detector: NSObject

- (id)init {
    self = [super init];
    
    // 分類器の読み込み
    NSBundle *bundle = [NSBundle mainBundle];
    NSString *path = [bundle pathForResource:@"haarcascade_frontalface_alt" ofType:@"xml"];
    std::string cascadeName = (char *)[path UTF8String];
    
    if(!cascade.load(cascadeName)) {
        return nil;
    }
    
    return self;
}

- (UIImage *)recognizeFace:(UIImage *)image {
    // UIImage -> cv::Mat変換
    CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
    CGFloat cols = image.size.width;
    CGFloat rows = image.size.height;
    
    cv::Mat mat(rows, cols, CV_8UC4);
    
    CGContextRef contextRef = CGBitmapContextCreate(mat.data,
                                                    cols,
                                                    rows,
                                                    8,
                                                    mat.step[0],
                                                    colorSpace,
                                                    kCGImageAlphaNoneSkipLast |
                                                    kCGBitmapByteOrderDefault);
    
    CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage);
    CGContextRelease(contextRef);
    
    // 顔検出
    std::vector<cv::Rect> faces;
    cascade.detectMultiScale(mat, faces,
                             1.1, 2,
                             CV_HAAR_SCALE_IMAGE,
                             cv::Size(30, 30));

    // 顔の位置に丸を描く
    std::vector<cv::Rect>::const_iterator r = faces.begin();
    for(; r != faces.end(); ++r) {
        cv::Point center;
        int radius;
        center.x = cv::saturate_cast<int>((r->x + r->width*0.5));
        center.y = cv::saturate_cast<int>((r->y + r->height*0.5));
        radius = cv::saturate_cast<int>((r->width + r->height));
        cv::circle(mat, center, radius, cv::Scalar(80,80,255), 3, 8, 0 );
    }
    
    
    // cv::Mat -> UIImage変換
    UIImage *resultImage = MatToUIImage(mat);
    
    return resultImage;
}

@end

イニシャライザで分類器を読み込んでおきます。
recognizeFaceで受け取ったUIImageをOpenCVで扱うデータ構造のcv::Matへ変換し、顔検出の処理を行ったあと、最後にまたUIImageへ変換して返しています。

実は、UIImage->cv::Mat変換ではcvMatFromUIImageメソッドがあり、簡単に変換できるようなのですが、何度か繰り返しこのメソッドを実行していくと不意に実行時エラーとなってしまいました。原因不明だったので、その処理を置き換えています。

最後にカメラからの画像データを変換する処理を次のように変更して終わりです。

    // 顔検出オブジェクト
    let detector = Detector()

   // ---------- 省略 ---------- //


    // 毎フレーム実行される処理
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!)
    {
        dispatch_async(dispatch_get_main_queue(), {
            // UIImageへ変換
            let image = CameraUtil.imageFromSampleBuffer(sampleBuffer)
            
            // 顔認識
            let faceImage = self.detector.recognizeFace(image)
            
            // 表示
            self.imageView.image = faceImage
        })
    }

これで実行すると、カメラに写した顔の位置に丸が描かれるはずです。
(何にも場所に反応されるとちょっとビビります・・・)

たぶん顔認識の処理のところで工夫すると、パフォーマンスをあげられるんだろうけど良く分かりません!!
どなたか教えてくださいませませ。

Githubにソースを上げておきます。

参考

OpenCV iOS - Image Processing

2014/11/30 追記

上記のコードにはメモリ処理上の問題があることを教えていただきました!
[自在]OpenCVかCIDetectorを使ってiOSで顔認識してみよう!

dispatch_asyncをdispatch_syncに変更で、明らかにメモリ使用量が改善します。

感謝感謝!