FC2ブログ

頭と尻尾はくれてやる!

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


iOSアプリ赤ちゃんの成長グラフver2.3(ARKitで身長計測機能の追加)が公開

変更内容はARKitを使って子供の身長を計測できる機能の追加。もちろん今まで通り手入力もできる。



↑こんな感じで。
子供の身長は2歳未満は寝かして、2歳以上は立って計測する(※)ので自動的に2歳未満の場合は横向き(壁から頭)、2歳以上は縦向き(床から頭)を計測する。
頭部把握後にドラッグで微調整できる。
画面をダブルタップでリセットできるんだけど、これを記述するの忘れてたな、、、😨


ちなみにこれ、コード自体は1年くらい前にできてた。
昨年の今頃ARKitを引き連れiOS 11が公開になった。事前にXcodeのbeta版をインストールしてARKit使った機能を組み込もうと作っていたのだが、どういうわけか申請ができなかった。このアプリだけでなく他の場合でも。
Appleのサポートといろいろとやりとりするも何の進展もなく時だけが経過してた。
ところが最近MacをMojaveにアップデートしたらすんなり申請できたのだった。
昨日申請し、今日にはReady for Saleへ。感慨深い。


※厚生労働省が統計を取るのに定めている計測方法。なので母子手帳に載ってるグラフなんかを見ると身長は2歳で不連続になってる。


iOSで出力したファイルをAirDropでMacに送信する

iOSアプリで作成、保存したファイルをMac側で使うのにずっとiTunes経由で取得してた。Application supports iTunes file sharingをYESにしとく方法ね。でもこれやっぱり面倒。そこでAirDrop使えばいいんじゃね?と思ってやってみた。

UIActivityViewController Tutorial: Sharing Data

↑Info.plistの設定はこのあたりを参考に。ただ面倒なのでアイコンとかは使ってない(俺のはリリース目的じゃないし)。
public.mime-typeもセットしてない。
拡張子はなんでもいい。.hogeでも.fooでも。

送信するためのiOS側のUIActivityViewControllerあたりのコードがこんな感じ。

{
    //(1)
    NSURL *url = [NSURL fileURLWithPath:fileName];

    //(2)
    NSError *error = nil;
    NSData *data = [saveString dataUsingEncoding:NSUTF8StringEncoding];
    BOOL succeed = [data writeToURL:url options:NSDataWritingAtomic error:&error];

    //(3)
    if (succeed) {
        UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[url] applicationActivities:@[]];
         [self presentViewController:activityViewController animated:YES completion:nil];
    }
}
(1)ここでfileNameはNSStringオブジェクト、ファイルの保存先で拡張子まで含む。
(2)saveStringもNSStringオブジェクトで中身はたんにxmlファイル。これをNSDataオブジェクトに変えて保存する。
(3)ここで指定するactivityItemsはNSURLオブジェクト。当初urlではなくdataもしくはurl,dataを記述しててうまくいかなかった。Info.plistのUTIの設定でConforms to UTIsにpublic.dataってしてるからNSDataオブジェクトを送信する必要があるのかと思ってた。

ともかく、これでめでたく送信することができた。MacのFinderでダウンロードフォルダーに入ってる。長かったなあ、、、


おまけ

UIActivityViewController表示

↑UIActivityViewController でCancelなり処理後にDoneしたらどうこうしたい時の記述はこんな感じで。
{
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[url] applicationActivities:@[]];
        [activityViewController setCompletionWithItemsHandler:
         ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
        // 処理
    }];
}



*versions
macOS Sierra 10.12.6
iOS 11.1.1
Xcode 9.1



Depth APIで部屋の奥の方を消してみた

iOS 11で公開された深度に絡むAPI、いわゆるDepth APIで遊んでみた。

Capturing Depth in iPhone Photography - WWDC 2017 - Videos - Apple Developer
↑これね。

サンプルコードのAVCamPhotoFilterのシェーダー部分をいじって、遠い部分を黒く塗りつぶすようにして部屋を撮影したのがこちら。

↑デバイスはiPhone 7 Plus。
なかなかしんどいですねえ、、、相当負荷が高い処理なんだろうな。

Supported Depth Resolutions for Streaming

↑上記のWWDCの動画内でこのようにリアルタイム(ストリーミング)だと320x180@24 fpsのデータが得られるとか(画像クリックで拡大)。案外小さいデータなんだな、とか思ってたんだが、、、それだけ処理が大変ってことか。

Depth APIとARKit使えば近くの人物などはそのまま表示し、周りの背景を描画したものに差し替えるような動画ができるんじゃね?とか思ってたけどこの様子じゃそれどころじゃなさそう。


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


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アプリはすごいよな。どういうアルゴリズムなんだろ?







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

FC2Ad