頭と尻尾はくれてやる!

iOSアプリなどの開発日記です


iOSデバイスのカメラで得る画像データのサイズを知る方法

iPhoneやiPadのカメラを使って画像を得る時にそのデータのサイズはどうやって取得するのってお話だよ。

ここでのサイズってのはいくつの点で画像を表現してるのって意味でのサイズであって画像の幅が何ピクセルとかじゃないよ。例えばAVCaptureSessionPreset1280x720なら1280x720個の点で作られるデータを取得するんだ。一つの点はRGBとアルファ値で4つあって、それぞれがunsigned char(1バイト)になるよ。だから1280x720x4x1 で約3.5MBにもなるからテキトウなメモリ処理だと簡単にスタックオーバーフローしちゃうよ(経験談)。

AVCaptureSessionクラスのsessionPresetプロパティで画質とかを設定できるんだけど、リファレンスにはこういうのを設定できるとあるよね。
{
    NSString *const AVCaptureSessionPresetPhoto;
    NSString *const AVCaptureSessionPresetHigh;
    NSString *const AVCaptureSessionPresetMedium;
    NSString *const AVCaptureSessionPresetLow;
    NSString *const AVCaptureSessionPreset352x288;
    NSString *const AVCaptureSessionPreset640x480;
    NSString *const AVCaptureSessionPreset1280x720;
    NSString *const AVCaptureSessionPreset1920x1080;
    NSString *const AVCaptureSessionPresetiFrame960x540;
    NSString *const AVCaptureSessionPresetiFrame1280x720;
}
AVCaptureSessionPresetHighのようにデバイスの性能次第みたいなのもあるし、AVCaptureSessionPreset1280x720のように数字を指定してても縦長か横長かって話もあるしさ。
どうすればサイズを取得できるのよ?って調べるとこういう記事が見つかったんだ。

ios - Knowing resolution of AVCaptureSession's session presets - Stack Overflow
{
    //captureSessionはAVCaptureSessionオブジェクト
    AVCaptureInput *input = [captureSession.inputs objectAtIndex:0];
    AVCaptureInputPort *port = [input.ports objectAtIndex:0];
    CMFormatDescriptionRef formatDescription = port.formatDescription;
    CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
}
↑うん、確かに取得できる。とりあえずこれ使ってみるかな。せっかくだからカテゴリにしてまとめておこうっと。
@implementation AVCaptureSession (GetDimensions)
-(CMVideoDimensions)dimensions
{
    AVCaptureInput *input = [self.inputs objectAtIndex:0];
    AVCaptureInputPort *port = [input.ports objectAtIndex:0];
    CMFormatDescriptionRef formatDescription = port.formatDescription;
    CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
    return dimensions;
}
こうしておけば今後使う時には
{
    CMVideoDimensions dimensions = [captureSession dimensions];
    NSLog(@"dimensions : %dw , %dh",dimensions.width,dimensions.height);
}
ってな感じで一撃だもんね。
ちなみにCMVideoDimensionsはどういう構造体か見てみると
typedef struct {
    int32_t width;
    int32_t height;
} CMVideoDimensions;
↑このように整数型でwidth、heightを持ってるのでNSLogで確認するときは%dでOK。


iPhoneのお休みモードがオンだとリマインダーは通知してくれない

朝イチやりたいことがあったので忘れないように前日夜にiPhoneのリマインダーを設定しておいたんだよ。
その時刻は普段ならすでに起きてる時間なんだけど、家族は寝てるのでiPhoneはまだおやすみモードがオンの時間だったんだ。

当日朝、リマインダーに頼らずとも覚えていたので処理するのは問題なかったんだけど、予定時刻になってもリマインドしてくれなかったんだ。
前日夜にSiriは「はい、リマインドします」って言ってくれてたんだけどさ。

もしかして、おやすみモードをオンにしてるとリマインダーで通知してくれないのか?と思って調べるとこういう記事が。

【ハウツー】iPhoneの通知機能を有効利用するには? - 「おやすみモード」より「機内モード」の使用をオススメ | 携帯 | マイナビニュース
リマインダーがおやすみモードオンだと通知してくれない?

機内モードにするかどうかは置いといて、やはりお休みモードがオンだと通知してくれないんだな。危ない、危ない。


iPhone/iPadのフロントカメラ/リアカメラが使えるかを調べる

最近カメラまわりの処理をいろいろと書いてたりするんだけどさ。

はて、使ってるデバイスがどのカメラを持ってるかどうやって判断すればいいんだろう?って思ってたね。
フロントカメラが付いたのはiPhone 4からだし、初代iPadにはカメラがなかったみたいだし。

(参考)
iPhone 5とiPhone 4S、4、3GSのスペック比較表
iPad miniと第三世代iPad、iPad2、初代iPadのスペック比較表

デバイスを調べてそこから判断する、、、?
そりゃ違うんじゃないの?と思って調べてみるとちゃんとあるじゃない。
{
    BOOL isFrontCameraAvailable = [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront];
    BOOL isRearCameraAvailable = [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear];
}
↑そうそう、こういうのが欲しかったんだよ。
これでフロントカメラもリアカメラもあるかどうかを知ることができるよ、ありがたや。


ところでどうでもいいんだけど、カメラの名称ってみんなどうしてるんだろうな。
上の週アスの記事だとiPhoneの方には「メインカメラ」「フロントカメラ」、iPadの方は「バックカメラ」と「フロントカメラ」って記述してる。
とりあえず上のUIImagePickerControllerCameraDeviceにあるように「リア」と「フロント」にしようと個人的には決定。


回転させたらframeのwidthがなんか違う?

前からたまにself.viewのframeプロパティの値が変でちょっと待てよ!(キムタク風)って思うことあったんだ。
基本320x480のはずが、画面を横向き(landscape)にしてもframe.size.widthをみたら480になってないじゃない、とかそういうのね。

そんなわけでiPhone 4S(iOS 6.1.3)実機でチェックしてみたよ。回転はviewControllerにおまかせしてこちらでは何の記述(frameの設定など)もなし。ボタンをタップしたらself.viewの各プロパティを表示させてる。
-(void)buttonTappedHandler
{
    CGRect frame = self.view.frame;
    frameLabel.text = [NSString stringWithFormat:@"frame x=%.0f , y=%.0f , width=%.0f , height=%.0f",frame.origin.x,frame.origin.y , frame.size.width, frame.size.height];
    
    CGRect bound = self.view.bounds;
    boundLabel.text =  [NSString stringWithFormat:@"bound x=%.0f , y=%.0f , width=%.0f , height=%.0f",bound.origin.x,bound.origin.y , bound.size.width, bound.size.height];
}
結果はこんなの。

(1)ステータスバーあり、portrait
ステータスバーあり、縦

(2)ステータスバーあり、landscape
ステータスバーあり、横

(3)ステータスバーなし、portrait
ステータスバーなし、縦

(4)ステータスバーなし、landscape
ステータスバーなし、横

そういうことなんだな。
回転させた時のframeが「それ、俺の欲しい値じゃない!」って場合はboundsプロパティを使えばいいってことがわかったよ。
↓ここに書いてたんだけどね。
uiview - "Incorrect" frame / window size after re-orientation in iPhone - Stack Overflow





iOSのイベント伝搬ってどうなってたっけ?

頭と尻尾はくれてやる! UIImageViewオブジェクトにジェスチャー設定もボタンもダメ?
↑昨日UIImageViewに設定したジェスチャーが効かないとかボタンを置いても反応しないとか書いたんだけど、いろいろ調べてる時にiOSのイベント伝搬についての良記事を見つけたんだ。

Cocoaの日々: [iOS] Responder Chain と UIViewController

あああ。Responder Chainですか、そうですか。うん、なんか聞いたことあるような、、、そういう仕組みになってるんだね。
改めて勉強になったよ。
ボタンを設定する時に記述するtargetってのは単にメソッドを置くオブジェクトを指定してる、くらいの認識だったけどこれをnilにする("nilターゲット"って言うんだそうな)とResponder Chainを辿ってくれるんだと!

実際確かめたらそうなってることはわかったんだけど、これをどう使えば便利なのかピンと来ないんだよね。
でも、ブロック構文と同じでうまく使えばきっと幸せになれるんだろうな。




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