こんにちは!12/11担当の @koogawa です。どうぞよろしくお願いします。
さて、iPhoneには「加速度センサー」や「電子コンパス」など、いろいろなセンサーが搭載されていることはご存知だと思います。そこで今回は、iPhoneで検知できる様々な情報とその実装方法を、10個ピックアップしてまとめてました。メジャーなものからマニアックなものまで色々揃えましたので、何か一つでもお役に立てたら嬉しいです。
では、いってみましょう!
光・音声系
1. 輝度センサー
iPhoneの画面輝度(明るさ)が取得・設定できます。
画面輝度=周りの明るさなので、輝度が高ければユーザが明るい場所にいると判断することもできそうです。ただ、中には画面輝度を固定に設定しているユーザもいるので、一概にこの基準が当てはまるとは限りません。
実装方法
画面輝度は次のように取得できます。
CGFloat brightness = [UIScreen mainScreen].brightness;
0.0〜1.0 の値が返ってきます。数値が増えるほど明るくなります。
詳しい記事
サンプルコード
2. 近接センサー
通話中、画面に顔が近付くと自動的に画面をロックしてくれるアレです。もちろん顔じゃなくても反応します。
実装方法
まずは近接センサーをオンにします。
[UIDevice currentDevice].proximityMonitoringEnabled = YES;
次に、近接センサーを監視します。
近接センサーが反応すると、UIDeviceProximityStateDidChangeNotification
が飛んでくるので、それを監視します。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(proximitySensorStateDidChange:)
name:UIDeviceProximityStateDidChangeNotification
object:nil];
詳しい記事
サンプルコード
3. シェイクジェスチャー
iPhoneを振ったときの動作を検知します。
実装方法
シェイクジェスチャーを検知するためにはファーストレスポンダにならないといけないので、canBecomeFirstResonder
をオーバライドして YES
を返します。
- (BOOL)canBecomeFirstResponder {
return YES;
}
この状態でiPhoneを振ると、次のメソッドが呼ばれるようになります。
// シェイク開始
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) {
NSLog(@"Motion began");
}
}
// シェイク完了
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) {
NSLog(@"Motion ended");
}
}
このメソッドを利用して、シェイクジェスチャーを検知します。
詳しい記事
サンプルコード
4. マイクの音
Core Audioを使用して、マイクから音を検知します。
実装方法
記録するデータフォーマットを決めます。
AudioStreamBasicDescription dataFormat;
dataFormat.mSampleRate = 44100.0f;
dataFormat.mFormatID = kAudioFormatLinearPCM;
dataFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
dataFormat.mBytesPerPacket = 2;
dataFormat.mFramesPerPacket = 1;
dataFormat.mBytesPerFrame = 2;
dataFormat.mChannelsPerFrame = 1;
dataFormat.mBitsPerChannel = 16;
dataFormat.mReserved = 0;
音の監視を開始します。
AudioQueueNewInput(&dataFormat, AudioInputCallback, (__bridge void *)(self), CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &_queue);
AudioQueueStart(_queue, NULL);
マイクのレベルを取得できるように、レベルメータを有効化しておきます。
UInt32 enabledLevelMeter = true;
AudioQueueSetProperty(_queue, kAudioQueueProperty_EnableLevelMetering, &enabledLevelMeter, sizeof(UInt32));
一定時間ごとにレベルを取得して、画面に表示します。
- (void)detectVolume:(NSTimer *)timer
{
// レベルを取得
AudioQueueLevelMeterState levelMeter;
UInt32 levelMeterSize = sizeof(AudioQueueLevelMeterState);
AudioQueueGetProperty(_queue, kAudioQueueProperty_CurrentLevelMeterDB, &levelMeter, &levelMeterSize);
// 最大レベル、平均レベルを表示
self.peakTextField.text = [NSString stringWithFormat:@"%.2f", levelMeter.mPeakPower];
self.averageTextField.text = [NSString stringWithFormat:@"%.2f", levelMeter.mAveragePower];
}
通常、mPeakPower
、mAveragePower
には負の値がセットされており、音量に比例して値も大きくなっていきます。最大値は 0 になります。
詳しい記事
サンプルコード
位置情報系
5. 緯度・経度
GPSを使って、現在地の緯度・経度を取得します。
実装方法
現在地の取得を開始します。
if ([CLLocationManager locationServicesEnabled])
{
// インスタンスを生成
_locationManager = [[CLLocationManager alloc] init];
// デリゲートを設定
_locationManager.delegate = self;
// 位置情報の取得開始
[_locationManager startUpdatingLocation];
}
この状態で位置情報が更新されると、次のメソッドが呼ばれます。
// 位置情報が更新されるたびに呼ばれる
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
self.latTextField.text = [NSString stringWithFormat:@"%.2f", newLocation.coordinate.latitude];
self.lonTextField.text = [NSString stringWithFormat:@"%.2f", newLocation.coordinate.longitude];
}
引数 newLocation
から現在地を取得することができます。
詳しい記事
サンプルコード
6. 電子コンパス
磁力センサーを利用して、iPhoneの向きを計測することができます。
実装方法
取得を開始します。
if ([CLLocationManager headingAvailable])
{
// インスタンスを生成
_locationManager = [[CLLocationManager alloc] init];
// デリゲートを設定
_locationManager.delegate = self;
// 何度動いたら更新するか(デフォルトは1度)
_locationManager.headingFilter = kCLHeadingFilterNone;
// デバイスの度の向きを北とするか(デフォルトは画面上部)
_locationManager.headingOrientation = CLDeviceOrientationPortrait;
// ヘディングイベントの開始
[_locationManager startUpdatingHeading];
}
この状態でiPhoneの向きが変わると、次のメソッドが呼ばれます。
// デバイスの方位が変わるたびに呼ばれる
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
CLLocationDirection heading = newHeading.magneticHeading;
self.textField.text = [NSString stringWithFormat:@"%.2f", heading];
}
magneticHeading
には 0.0 から 359.9 の値が入ります。北の方向がちょうど 0.0 になり、それから東、南、西の順に値が増えていき、北に戻ると再び 0.0 に戻ります。
方角 | 値 |
---|---|
北 | 0.0 |
東 | 90.0 |
南 | 180.0 |
西 | 270.0 |
詳しい記事
サンプルコード
7. 標高
GPSを使って、現在地の標高を測定できます。
実装方法
現在地情報の取得を開始します。
if ([CLLocationManager locationServicesEnabled])
{
// インスタンスを生成
_locationManager = [[CLLocationManager alloc] init];
// デリゲートを設定
_locationManager.delegate = self;
// 位置情報の取得開始
[_locationManager startUpdatingLocation];
}
この状態でiPhoneの位置情報が更新されると、次のメソッドが呼ばれます。
// 位置情報が更新されるたびに呼ばれる
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
self.textField.text = [NSString stringWithFormat:@"%.2f m", newLocation.altitude];
}
引数 newLocation
の altitude
プロパティで標高が取得できます。単位はメートルです。
詳しい記事
サンプルコード
移動・動作系
8. 加速度センサー
加速度センサーを利用することで、例えば iPhone の傾きによって画面上のボールが転がる、などと言った動きのあるアプリを作ることができます。
実装方法
インスタンスを生成します。
_motionManager = [[CMMotionManager alloc] init];
適切な更新間隔を設定をして加速度センサーを有効化します。
if (_motionManager.accelerometerAvailable)
{
// センサーの更新間隔の指定
_motionManager.accelerometerUpdateInterval = 1 / 10; // 10Hz
// ハンドラを指定
CMAccelerometerHandler handler = ^(CMAccelerometerData *data, NSError *error)
{
// 画面に表示
self.xLabel.text = [NSString stringWithFormat:@"x %f", data.acceleration.x];
self.yLabel.text = [NSString stringWithFormat:@"y %f", data.acceleration.y];
self.zLabel.text = [NSString stringWithFormat:@"z %f", data.acceleration.z];
};
// 加速度の取得開始
[_motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:handler];
}
startAccelerometerUpdatesToQueue
メソッドを実行すると、指定した更新間隔でハンドラの内容が実行されます。
詳しい記事
サンプルコード
9. 歩数・進行状況
CoreMotionを使って、歩数カウントを取得できます。(現時点ではiPhone 5Sのみ対応)
実装方法
CMStepCounter
インスタンスを生成します。
_stepCounter = [[CMStepCounter alloc] init];
歩数のカウントを開始します。
[_stepCounter startStepCountingUpdatesToQueue:[NSOperationQueue mainQueue]
updateOn:1
withHandler:^(NSInteger numberOfSteps, NSDate *timestamp, NSError *error) {
// 歩数が更新されるたびに呼ばれる
}];
- 第1引数:handler を呼び出す queue を指定
- 第2引数:何歩歩いたら handler を呼び出すか(実際にはこの指定通りには動かなかった)
- 第3引数:歩数更新時に呼び出す handler
第3引数で指定する Blocks には、計測を始めてからの累計歩数、更新時のタイムスタンプ、エラー情報が返ってきます。
また、歩数以外にもユーザの歩行情報(歩いているのか、走っているか等)も取得できます。詳しくは、下記の記事を参照してください。
詳しい記事
サンプルコード
その他
10. 顔検出
Core Image を使って、顔を検出することができます。
実装方法
インスタンスを生成します。
NSDictionary *options = [NSDictionary dictionaryWithObject:CIDetectorAccuracyHigh
forKey:CIDetectorAccuracy];
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace
context:nil
options:options];
detectorOfType
には検出タイプを指定します。今回は顔検出なので、CIDetectorTypeFace
を指定します。((今のところ CIDetectorTypeFace しか設定できないようです))
options
には検出精度 CIDetectorAccuracy
等を指定できます。
次に、顔検出を実行します。
CIImage *ciImage = [[CIImage alloc] initWithCGImage:originalImage.CGImage];
NSDictionary *imageOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:1]
forKey:CIDetectorImageOrientation];
NSArray *array = [detector featuresInImage:ciImage options:imageOptions];
featuresInImage
には、顔検出したい画像を CIImage
クラスで指定します。
options
には画像の向きなどを指定します。カメラの画像を利用する場合には、デバイスの方向を正しく指定しないと顔検出ができないので注意してください。
正常に顔が検出されると、検出結果が CIFaceFeature
オブジェクトで返ってきます。このオブジェクトには、検出された顔の範囲や、目と口の位置などが含まれます。
- bounds - 顔の範囲
- leftEyePosition - 左目の位置
- mouthPosition - 口の位置
- rightEyePosition - 右目の位置
ここで注意したいのは、CoreImage
は、左下の座標が (0,0) となる点です。よって、検出元画像の上に部品を載せたい場合は、座標をUIKitの座標系に変換する必要があります。詳しくは、下記の記事を参照してください。
詳しい記事
サンプルコード
さいごに
輝度センサーから顔検知までざっと書いてみましたが、いかがでしたでしょうか。すべての項目を詳しく書いていると、相当な量になってしまうため、各項目は簡単な説明に留めました。もっと詳しく知りたい場合はぜひ「詳しい記事」も参照してみてください。
なお、今回紹介した10項目のサンプルコードは、ひとつのアプリにまとめてGithubにアップしてあります。すぐにビルドして使えるようにしてあるので、ぜひダウンロードしてみてくださいね。
https://github.com/koogawa/iSensor
Swift 4 対応版もあるよ! https://github.com/koogawa/iSensorSwift
この記事が皆様のお役に立てれば光栄ですm(_ _)m