Posted at

iOS+OpenCV: CvVideoCameraのアスペクト比を正しくする

More than 5 years have passed since last update.


問題点


  • CvVideoCameraのアスペクト比がおかしい



    • UIViewContentModeScaleToFillの状態。




事前調査


  • カメラ画像を表示しているUIImageViewのcontentModeを変更しても反映されない。

  • CALayerがなんたらかんたら。

  • カメラの動作を開始しないとカメラの解像度が確定しない。


    • 動作開始後に調整しないといけない。



  • カテゴリを使って既存クラスを拡張できる。(メソッドの追加)


    • CvVideoCameraにstartWithContentMode:を追加する。




完成品


CvVideoCamera+ContentMode.h

#import <UIKit/UIKit.h>

#import <opencv2/highgui/cap_ios.h>

@interface CvVideoCamera (WithContentMode)

- (void)startWithContentMode:(UIViewContentMode)contentMode;

@end



CvVideoCamera+ContentMode.m

#import <AVFoundation/AVFoundation.h>

#import <CoreGraphics/CoreGraphics.h>
#import <CoreMedia/CoreMedia.h>
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>
#import "CvVideoCamera+ContentMode.h"

@implementation CvVideoCamera (WithContentMode)

- (void)startWithContentMode:(UIViewContentMode)contentMode
{
[self start];

//カメラの解像度を調べる
AVCaptureInput *input = [self.captureSession.inputs objectAtIndex:0];
AVCaptureInputPort *port = [input.ports objectAtIndex:0];
CMFormatDescriptionRef formatDescription = port.formatDescription;
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
NSLog( @"dimensions=%dx%d", dimensions.width, dimensions.height );

if( parentView.layer.sublayers != nil )
{
CALayer *layer = [parentView.layer.sublayers objectAtIndex:0];
NSLog( @"[before] frame%@ position%@", NSStringFromCGRect(layer.frame), NSStringFromCGPoint(layer.position) );

//現在のアスペクト比
CGFloat ratiox = dimensions.width / layer.frame.size.width;
CGFloat ratioy = dimensions.height / layer.frame.size.height;
//contentModeによる表示サイズ/位置の決定
switch( contentMode )
{
case UIViewContentModeScaleAspectFit:
ratiox = (ratiox > ratioy)? ratiox : ratioy;
ratioy = ratiox;
break;
case UIViewContentModeScaleAspectFill:
ratiox = (ratiox < ratioy)? ratiox : ratioy;
ratioy = ratiox;
break;
default:
NSLog( @"does not support" );
break;
}
NSLog( @"ratio(%.3f,%.3f)", ratiox, ratioy );
//新しい表示サイズ/位置をセット
CGFloat x, y, w, h;
w = dimensions.width / ratiox;
h = dimensions.height / ratioy;
x = (layer.frame.size.width - w)/2;
y = (layer.frame.size.height - h)/2;
layer.frame = CGRectMake( x, y, w, h );
NSLog( @"[after] frame%@ position%@", NSStringFromCGRect(layer.frame), NSStringFromCGPoint(layer.position) );
}
}

@end



使い方など



  • startの代わりにstartWithContentMode:を呼ぶ。


  • ScaleAspectFitScaleAspectFillのみ対応。

  • 対症療法的に作ったので色々と不安。