ちょっと調子に乗ってまたSwiftの話題です。
今のうちにSwiftのこと載せておけば、いずれ本とか出せるようになるのかなと思って!

今回はSwiftで顔認識です。

前回、SwiftでOpenCVをやったんでOpenCVの顔認識メソッド使えばいいんでしょうが、せっかくSwiftのこと書くんだからということでSwiftだけでやってみました。
まあすでにiOSのSDKには顔認識メソッドが標準であるんで、それをSwiftで使うだけの薄い内容のブログですけどね。

iOSのSDKにある認識メソッドの情報はこちらとかこちらです。

前回と同じようにxcode6でSwiftのプロジェクトを作成し、UIImageViewひとつだけのstoryboadを用意します。

で、もう書くこともないんですけど認識のコードはわずかこれだけです。
起動と同時にimageViewの画像内から顔を認識して赤枠で囲います。

ぶっちゃけるとほとんどが認識した位置に赤枠を表示させるための処理で、認識自体は3行で終わってます。
おそらくCIDetectorの引数であるCIDetectorTypeFaceを色々変えたら認識する対象が変えられるはずです。
CIDetectorTypeQRCodeってのがあったんでたぶんQRコードも簡単に認識できるんでしょうね。
本当画像処理エンジニア殺しなメソッド用意しやがってAppleめ…

そして実行画面がこちら。
ちゃんと認識ができました。

まあ、自分で学習データを用意できない?らしいので、おっ○い認識など夢が広がるものを認識させたいならやっぱりOpenCV使うに限りますね!

またソースをgithubにあげました。
1年以上ぶりですがまだ息してますよ、こんばんは。

転職しまして2014年の4月から東京で暮らしてます。
そのせいかあまり暇もなくなりOpenCVjsなにそれ状態です。
しかたねえので話題を変えて今回はAppleがくそ迷惑にも新言語Swiftを発表しやがったので、SwiftでOpenCV使えんの!?を検証しました。

結論から言うと出来ました。
そんなわけでSwiftでOpenCVを使うまでを解説します。

アメブロに全然慣れないんでいつまで経っても見辛いブログですが勘弁してください。


xcode6のダウンロードやらは色んなサイトに載ってるので省きます。
xcode6を立ち上げていつも通りに新しいプロジェクトを立ち上げると特に変わったことない画面が開きます。
いつも通りNextを押すといつも通りプロジェクト名とか聞かれますが、いつもと違って赤で囲ってるところがSwiftになってる!!!!!

a


ここでSwiftかObjective-Cか選択できます。
どうやらこれまでと同じくObjective-Cも使えるようでちょっと安心しました。

そのままNextでプロジェクトを開いた状態になるんですが、ここからswift感満載になります。

b


ひととおり「@がねえ!」とか「hファイルがねえ!」とか驚いたらxcode閉じます。

次にOpenCVを入れるんですがこれまでと変わらず、最近の流行らしいcocoapods様にお伺いをたててOpenCVを入れます。
cocoapods様がよく分からない人は俺も3ヶ月前に知ったばかりでよく分かってないのでググレカスです。
とりあえずOpenCVを入れるための雑なPodfileがこれ。

platform :ios, "6.0"
pod 'OpenCV'

このテキストを今回のxcodeprojファイルがあるフォルダに入れてターミナル立ち上げてPodfileのあるフォルダに移動してこんな感じでコマンド叩いたらOpenCV入っちゃうからステキ!

c



なんかxcworkspaceファイルとかいうのが出来上がってるのでそっちを開きます。

ではようやくここからコードを書いていきます。
まずSwiftのくそ野郎言語は直接OpenCVのコードを書けないようなので、結局Objective-C++のファイルを追加することになります。

とくにむずかしくなくファイルの追加をやってObjective-C File選べばよいですが、C++のコードを動かすのでファイル拡張しはmmとして保存します。
今回はTestOpenCV.mmとしました。

そうすると次に何かこんなの聞かれます。

d


よく分かりませんがSwiftとObjective-Cを連携してくれるヘッダファイルを作ってくれるみたいなのでYesにします。
そうするとTestOpenCV.mmとSampleSwift-Bridging-Header.hというふたつのファイルが追加されます。

e


ここで「TestOpenCV.h」じゃねえのかよ!と驚いたら何か適当にサンプル画像をプロジェクトに追加します。
それからSampleSwift-Bridging-Header.hにこれまで通りのObjective-Cのインタフェースを書きます。
今回は画像のエッジを検出するクラスメソッドひとつです。

h



それからTestOpenCV.mmに実装を書きます。

ここでもう普通にOpenCVのコードが書けます。



f


で、いよいよstoryboadやらswiftやらとつないでいきますが、これまでとなんざ変わりません。
storyboadを開いて、対応するViewController.swiftも開いてドラッグ&ドロップでいつも通り線をつなぐだけでした。
やってることはstoryboadにUIImageViewとUIButtonを載せてswiftコードにUIImageViewのプロパティとUIButtonを押した時のアクションを設定してるだけです。


g



そして肝心のswiftちゃんなんですがとくに何もすることなくいきなりTestOpenCVで実装したメソッドが呼び出せました。
赤枠で囲ってる部分です。


i


そして実行画面がこんな感じで

mae

ボタンを押すとこんな感じ!!

ato


Swiftちゃんは出来る子だった!!!
とりあえず10数ヶ月ぶりにgithubにソースあげてみました。
寝る前に書き出したんで、肝心の後半になるほどすげえ雑なブログになりましたが以上です。

超ひっさびさ!!!

javascript画像処理するブログの14回目?
数ヶ月放置でしたが何もしていなかったわけではなく、ちびちびとOpenCVjsの機能を追加しようとしては挫折をするという迷走をしていました。

ここ数ヶ月は顔認識やらに使われる機械学習の学習をしておりその機能がようやく実装されたので調子のってブログ更新です。

しばらく僕が歩んだ苦難の道を書いてるだけなので、さっさとコードが見たい人は読み飛ばして下さい。

とりあえず機械学習を学ぶにあたって参考にした本やリンクはこんな感じ。
はじめてのパターン認識/森北出版
¥3,150
Amazon.co.jp

機械学習の「」の字も知らん僕にはここからすでに読むの苦労しましたが雰囲気掴むには良かった気もします。
しかしこれを読むだけでは数年前から流行のサポートベクターマシン(SVM)とかいうのが全く実装できず、やむなく翻訳がダメだダメだと噂の次の赤本も読んでみました。

サポートベクターマシン入門/共立出版
¥4,200
Amazon.co.jp
うん、まあ、噂通り読みづらいわこれw
単純に前から読んでいったらあっという間に挫折するとこだったのをこちらのブログに救われました。

SVMの定番入門書「サポートベクターマシン入門(赤本)」の読み方

上の赤本の挫折しない読み方を記載してくれています。
リンク先の通りに読めばまぁ1~2日長く粘って挫折できます。
んで、まあ赤本の付録のコードとか読んでもいまいちすっきりせず、結局さらに次のブログを読んでようやくJSに移植できたような気になれてSVMが分かった気になりました

SVMコード

いやもうホント色んな人に感謝です。

ほんじゃようやく機械学習の説明!!今回学習させるデータはこれ!

学習データ


なんのこっちゃよく分からないでしょうけど、画像内の各点が学習データ座標を特徴量としてクラス分けされるようにします。

分かりづらいかもしれませんが左上にが集中してます。

ようやくサポートベクターマシンjavascriptコード!!



function SVM(imgId, iplImage){

var trainss = new Array(); //学習データの2次元配列
var answers = new Array(); //クラスデータ
//--------------------------(1)学習データの読み込み----------------------------
for(var i = 0 ; i < iplImage.height ; i++){
for(var j = 0 ; j < iplImage.width ; j++){
//各座標の画素を取得し赤クラスと青クラスに分類
var ji = (j + i * iplImage.width) * CHANNELS;
var r = iplImage.RGBA[ji];
var g = iplImage.RGBA[1 + ji];
var b = iplImage.RGBA[2 + ji];
var answer = 0;
if(r > 200 && g < 50 && b < 50) answer = 1;
else if(r < 50 && g < 50 && b > 200)answer = -1;
if(answer != 0){
//座標を学習データに代入
var trains = new Array(j/iplImage.width, i/iplImage.height);
trainss.push(trains);
answers.push(answer);
}
}
}
        //------------------------(1)ここまで------------------------------

        //-------------------(2)SVMの各種パラメータ設定----------------------------
//SVMクラスに読み込ませる終了条件クラスのインスタンスを生成
var termcriteria = new CvTermCriteria();
termcriteria.max_iter = 100000; //最大繰り返し回数
termcriteria.epsilon = 0.1; //C-SVMのイプシロン
//SVMクラスに読み込ませるパラメータクラスのインスタンスを生成
var cvSVMP = new CvSVMParams();
cvSVMP.kernel_type = CV_SVM_KERNEL_TYPE.POLY; //SVMのカーネルの種類
cvSVMP.degree = 4.0; //カーネルで使われるチューニングパラメータ1
cvSVMP.gamma = 1.0; //カーネルで使われるチューニングパラメータ2
cvSVMP.coef0 = 1.0; //カーネルで使われるチューニングパラメータ3
cvSVMP.C = 5; //C-SVMで使われるC
cvSVMP.term_crit = termcriteria; //終了条件クラスを代入
cvSVMP.tolerance = termcriteria.epsilon; //許容する計算誤差
cvSVMP.minLearnData = 10; //学習データの最低数
        //------------------------------(2)ここまで------------------------

         //---------------------------------(3)SVMで学習--------------------------
//SVMクラスのインスタンスを生成
var cvSVM = new CvSVM();
//学習
cvSVM.train(trainss, answers, null, null, cvSVMP);
//---------------------------------(3)ここまで---------------------------------

         //------------------------------(4)SVMで予測-----------------------------
//学習データを用いて画像の座標の色を予測する
for(var i = 0 ; i < iplImage.height ; i++){
for(var j = 0 ; j < iplImage.width ; j++){
//予測対象の座標を特徴量として配列に代入
var inputs = new Array(j/iplImage.width, i/ iplImage.height);
//予測
var predict = cvSVM.predict(inputs, trainss);
var r = 255; var g = 255; var b = 255;
//予測結果が1なら赤、0なら青とする
if(predict >0){
r = 255; g = 0; b = 0;
}
else{
r = 0; g = 0; b = 255;
}
//特徴量となった座標の色に代入
var ji = (j + i * iplImage.width) * CHANNELS;
iplImage.RGBA[ji] = r;
iplImage.RGBA[1 + ji] = g;
iplImage.RGBA[2 + ji] = b;
}
}
//------------------------------(4)ここまで-----------------------------

        //画像を出力
cvShowImage(imgId, iplImage);
}




例によってOpenCVjsを使ってますよ。

まあ書いてる通り、全体の概要は
(1)学習データの読み込み
(2)SVMの各種パラメータ設定
(3)SVMで学習
(4)SVMで予測
です。

実際に画像から学習データを作成し、その他の座標の色を予測したらこんな感じになりました。

推測結果


まぁなんとなくちゃんと非線形に学習できたかなぁって!
ただ学習処理の内部で乱数を使っており、毎回学習と予測結果が変わります
酷い時は全然ちゃんと学習してなかったり...
これについてはたぶん(2)SVMの各種パラメータ設定を何も考えずに調整しちゃったせいかなあと思ってますがどうなんでしょう?
パラメータの設定も交差検定?とかちゃんとした手法があるらしいですよ、まだ調べてないけど!

とりあえず見た目はつまらないですが画像認識の第一歩となりました!
あとは
HOGとか実装すればjavascript顔認識とかの画像認が出来るようになる…といいなあ…