頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


カメラで得た画像にVision frameworkを使う

Vision.frameworkをObjective-Cでやってみた
↑この続き。

どうなんだろうな?と思って確認すると、顔画像が90度回転してたり上下逆さまだと認識しないっぽい。

横向きだと検出しない

これで何が困るかというとiPhoneのカメラから得られる画像を回転を意識せずにUIImageViewで表示すると横向きになる(デバイスの姿勢はportrait)のでカメラから得たデータを回転させる必要がある。Vision frameworkの顔認識処理に渡すのはCGImageなのでここから回転させないと具合悪い。
いろいろと調べて試してみた結果、
Ios rotate, filter video stream in ios - Stack Overflow
↑ここにあるコードを使うと意図通り回転させることができた。


↑これでカメラで得た画像に対して顔検出処理ができるとこまでOK。


↑iPhone 7 Plusのフロントカメラでリアルタイムでやってみたが、、、
顔検出処理に200msecほど必要だと測定してたから追従性はこんなもんだろうとは思っていたが、、、問題は期待ほど精度が高くないこと。顔の向きや光の具合でとんでもない判定が出ることが多い。それから動画にはないけどいわゆる変顔みたいな表情も苦手の様子。
リアルタイムではなくてもいいので正確に表情を検出したかったんだけど、これじゃ使えない感じ。ただ、こういう機械学習モノはどんどん精度が上がっていくだろうし、瞳が取得できない不具合も修正はされていくだろうから時々チェックするようにせねば。


機械学習におけるデータの範囲

最近またTensorFlowをいじってる。やったことメモ。

機械学習(TensorFlow)で位置計測っぽいことをやってみた
↑以前こういうのをやったんだけど、これを使って思い出しがてら気になってたデータの範囲について二つ確認。
1つは正解のラベルについて、もう一つは画像のデータについて。

(1)正解のラベル
この時は正解が無次元化された円の座標と半径で学習してる。座標は-1から1で半径は0超から0.5。この正解を得ようというネットワーク(CNN)だったんだが、この正解が無次元化されてなくてもいけんの?というのを確認しようとした。
座標が0から64.0の値を取る場合だと学習がうまく進まなかったので最後の出力層部分のコードをよくよく見ると、

y_conv=tf.nn.tanh(tf.matmul(h_fc2, W_fc3) + b_fc3

となってた。tan(θ)ってことは、-π/2 , π/2で発散するから-π/2 〜π/2の範囲を超えてるからか?ってことでtanhをreluに変えたらいけた。


(2)画像のデータ
画像のデータは0から1.0の値を取るとしてるんだけど、これが0〜255.0のfloatでもいいんじゃないの?といろいろと試してみたんだけど、結果から言うとなぜかできんかった。0〜2.0でもダメ。

tf.image.random_brightness(image, max_delta=0.4)
tf.image.random_contrast(image, lower=0.6, upper=1.4)

といった画像数水増し処理を特に考えず(作った時はどこかでサンプルを見つけたんだろうね)入れてたけど、これよく見ると場合によっては1.0を超えると思うんだ(すでにimageはtf.float32にキャストしてる)。もしかして今まではたまたま学習が進んだけど、実は悪さしてんじゃね?ってことで

tf.clip_by_value(image , 0.0 , 1.0 )

と言うclampと同じ処理を入れてみた。すると、どうよ。学習の進み具合がよくなってるやん!
不思議や。NNの処理をいくら見ても0〜1の範囲を超えるとまずそうな部分は俺には見つけられんのだが。いつか気付いたら追記するわ。







Vision.frameworkをObjective-Cでやってみた

最近ネット上でサンプルコードを見つけても大抵はSwiftで書かれてあるのでそれをObjective-Cにするにはどうするんだ?ってなることが多くええ加減Swiftやるか?って悪魔のささやきが聞こえたりもするけど、まだだ、まだその時では無い、、、、

そんなわけでObjective-CでVision.frameworkを使って顔の検出をしてみた。
[iOS 11] 画像解析フレームワークVisionで顔認識を試した結果 | Developers.IO
↑参考にしたのはこちら。ありがたいです。

こちらを参考にしつつFace Landmarksってのをやろうとしたんよ。顔の目や口の形状が取れるような絵があるので面白そう!ってことで。

上記リンクのコードを参考にしつつ引っかかったところをメモしておくと、、、
{
    struct CGImage *image = originalImage.CGImage;//—(1)

    VNDetectFaceLandmarksRequest *request = [VNDetectFaceLandmarksRequest new];
    NSDictionary *dictionary = [[NSDictionary alloc] init];

     VNImageRequestHandler *handler = [[VNImageRequestHandler alloc] initWithCGImage:image options:dictionary];

    [handler performRequests:@[request] error:nil];

    for(VNFaceObservation *observation in request.results) { //—(2)
        if (observation){
            NSLog(@"%@",observation);//—(3)
        }
    }
}
originalImageはUIImageオブジェクト。CGImageは(1)で取れる。
(2)の部分は取得した顔の数だけループ。一人なら一回。
(3)でやりたい処理を記述すればOK。
参考記事にもあるけどUIViewなどとは原点位置が違うので要注意。
後、Landmarksに関して
{
    VNFaceLandmarks2D *landmarks = observation.landmarks;
    VNFaceLandmarkRegion2D *outerLips = landmarks.outerLips;
}
↑こんな感じで二次元の正規化された座標を得ることができるんだけど、この場合は元画像ではなくobservation.boundingBoxに対しての位置なので注意。

landmarks結果

↑outerLipsだけやってみた結果。
得た座標を繋いでいくと閉じないので最初と最後のデータを繋いで閉じるようにしてる。リファレンスには何も記述はないけどまあそういうことなんだろう。

iPhone 7 Plus実機で実行したら検出部分でおよそ200msecほどかかってる。画像サイズを小さくしても180msec弱くらいでさほど変わらない感じ。
1秒間に5フレーム程度か、、、(-_- ;

となると先日のiPhone X発表時にあったデモみたいなスムーズな顔面のトラッキング&表示はしんどそう。

keynoteのiPhoneXデモ

↑これね、誰だかわかんないけどフェデリギさん。
iPhone Xは新しいセンサーとかあるからできるんだろうとは思うけど、そう考えるとすでに同じようなことができてるMSQRDアプリはすごいよな。どういうアルゴリズムなんだろ?





iPhone X対応でSafeArea相当のviewを置いてみる

storyboardを使っていない古いアプリのiPhone X対応で苦労しているわけだが、、、

iPhone Xの画面の高さが667って出てしまう謎
↑ここでiPhone X対応でディスプレイのサイズをコードで取得したもののやっぱりコードで対応するのは面倒。せっかく強引にstoryboardを突っ込んだので利用してみることにした。

すでにあるsafe area

↑storyboardでデフォのview controllerを見るとすでにsafe areaってのが設定されてるのでこれを利用してみる。けど、このsafeAreaと同じサイズのviewはないので自作する。

constraintを設定

↑UIViewをドラッグ&ドロップで追加して、constraintを設定。幅、高さ、あとは上下左右がsafeAreaと隙間なしって奴の計6個。

outletを設定

↑このstoryboardのview controllerに対応するViewControllerクラス内で使うため準備しといて、、、

outlet接続

↑storyboard側からViewControllerクラスに参照を教えてやる(Referencing Outletsを指定)。

これでコード側から”安全な”UIViewオブジェクトを参照できる。


- (void)viewDidLoad {
[super viewDidLoad];

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 40)];
label.text = @"TopLeft";
//[self.view addSubview:label];
[safeView addSubview:label];
}

↑こんな感じでUILabelオブジェクトを画面左上に表示するのにself.viewではなくsafeViewに追加する。

iPhone 7 (修正前)

↑iPhone 7でself.viewにaddSubview: した場合。

iPhone 7 (修正後)

↑iPhone 7でsafeViewにaddSubview: した場合。いいね!

iPhone X (修正前)

↑iPhone Xでself.viewにaddSubview: した場合。

iPhone X (修正後)

↑iPhone XでsafeViewにaddSubview: した場合。いいやん!

とまあこんな感じで上下のことは気にせずにレイアウト可能になる。

今までself.viewにaddSubview:してたりself.viewのheightとか取ってたけど、self.view→safeViewと変更するだけで、コードの修正がだいぶ楽になるはずだあ!とやってるんだが、、、


現時点での問題点

(1)self.view.backgroundの色をセットしないと上下が白くなる
self.viewにsafeViewを乗せてるせいだと思うが、iPhone Xだとsafe area外が上下にあるが、このカラーが白いまま。これが不自然に見えるのが嫌だとself.view.backgroundの色をセットする必要がある。

(2)キーボードは容赦なく画面下端から出て来る
safe area内に表示すりゃOKと思っていたけど、よく考えたらキーボードは画面下の端から出て来る。safe area内にしてよって訳にもいかない。

また問題出てきたら追加するわ。


iPhone Xの画面の高さが667って出てしまう謎

相変わらず古いアプリのiOS 11対応(というかiPhone X レイアウト対応)してるんだけど、どういうわけか画面のサイズがうまく取得できなかった。

ios - Detect if the device is iPhone X - Stack Overflow
ios - Detect iPhone X with a macro - Stack Overflow
↑基本ここいらのコードを参考にして

int height = (int)[[UIScreen mainScreen] bounds].size.height;

って値をチェックしてみたんだけど、シミュレータがiPhone Xなのにどうやってもなぜか667って値になる。その値って4.7インチのんやん?

おっかしいなあ〜、やってられんなあ〜ってやさぐれてたら、そう言えばLaunchScreen設定してないなあ。その辺りか?と思って適当にシミュレータのスクショ撮って、その画像をLaunchScreenの画像としてを設定してみた。

Launch Imageの設定

↑ここな。最初見た時には右ペインのiOS 8.0 and Laterってところにどちらもチェック入ってなかったわ。

この画像を設定したらちゃんとheightが812になったわ。

そう言えば同じこと昔あったよなあ。画面が3.5インチ→4インチになった頃だったかな?




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.

FC2Ad