2012年3月10日 星期六

Filter4Cam 實作: 7. 濾鏡視窗顯示範圍

since: 2012/03/10
update: 2012/03/12

reference: I touchs: Filter4Cam 實作: 6. 測試 Camera Overlay 與 Filter Rectangle

A. 說明
      1. 由於之後會在 Camera 上放置多個 Overlay 的 UI 元件, 因此將設備方向改變時
          的程式碼調整, 由原本 Filter4CamHelper 類別提供的 orientationTransform: 方法,
          移到 ViewController 類別內實作.

-----------------------------------------------------------------------------------------

B. 調整濾鏡視窗外框:
     1. 開啓 ViewController.h 檔案, 調整如下:
....

@interface ViewController : GLKViewController <AVCaptureVideoDataOutputSampleBufferDelegate>
{
....
    //@add for Camera Overlay UI
    UIImageView *filterLensImageView; 
....
}
....
//@add for Camera Overlay UI
@property (nonatomic, strong) UIImageView *filterLensImageView;
....
//@add for orientation Transform

- (CIImage *)orientationTransform:(CIImage *)sourceImage; // 方向轉變的調整

//@add for setting camera Overlay
- (void)cameraOverlay;
....


    2. 開啓 ViewController.m 檔案, 調整如下:
....
//@add for Camera Overlay UI
@synthesize filterLensImageView = _filterLensImageView;
....
#pragma mark Getter
....
//@add for Camera Overlay UI
- (UIImageView *)filterLensImageView
{  
    if (_filterLensImageView == nil) {
        _filterLensImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"filterLens.png"]];
    }
   
    return _filterLensImageView;
}
....
#pragma mark Utility Tools

//@add for setting camera Overlay
- (void)cameraOverlay
{   
    [self.filterLensImageView setFrame:CGRectMake(20, 80, 280, 280)];
    [self.view addSubview:self.filterLensImageView];
}

//@add for orientation Transform(方向轉變的調整)
- (CIImage *)orientationTransform:(CIImage *)sourceImage
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    CGAffineTransform affineTransform; // 仿射轉換
   
    // 設備垂直擺放
    if (orientation == UIDeviceOrientationPortrait)
    {
        affineTransform = CGAffineTransformMakeRotation(-M_PI / 2);
    }
    // 設備垂直 180 度擺放
    else if (orientation == UIDeviceOrientationPortraitUpsideDown) {
        affineTransform = CGAffineTransformMakeRotation(M_PI / 2);
    }
    // 設備水平向右擺放
    else if (orientation == UIDeviceOrientationLandscapeRight) {
        affineTransform = CGAffineTransformMakeRotation(M_PI);
    }
    // 設備水平向左擺放
    else if (orientation == UIDeviceOrientationLandscapeLeft) {
        affineTransform = CGAffineTransformMakeRotation(0);
    }
    //
(2012/03/12 update)
    // 其它 (UIDeviceOrientationFaceUp, UIDeviceOrientationFaceDown,
    //           UIDeviceOrientationUnknown)

    else {
        affineTransform = CGAffineTransformMakeRotation(0);
    }
  
    return [sourceImage imageByApplyingTransform:affineTransform];
}
....
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
   
    // 將取得的 sampleBuffer 轉成 CVPixelBuffer
    CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
   
    // 接著, 將 CVPixelBuffer 利用 Core Image 的初始化方法再轉成 CIImage.
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
       
    //@add:濾鏡測試
    //ciImage = [self filterTest:ciImage];
   
    //@add:方向轉變的調整
    //ciImage = [Filter4CamHelper orientationTransform:ciImage];
    ciImage = [self orientationTransform:ciImage];

    // 然後使用 CIContext 物件將其內容畫到 render buffer
    [self.coreImageContext drawImage:ciImage atPoint:CGPointZero fromRect:[ciImage extent]];
   
    // 最後, 在螢幕上呈現出來.
    [self.glContext presentRenderbuffer:GL_RENDERBUFFER];
}

....
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //@add:helper Test
    [self helperTest];
   
    //@add: establish Render
    [self establishRender];

    //@add: establishCamera
    [self establishCamera:kCameraBack];
   
    //@add for setting camera Overlay
    [self cameraOverlay];
   
    //@add: startRunning
    [self startRunningSession];
}

....// (2012/03/12 update)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    /*
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    } else {
        return YES;
    }
    */
   
    //@update
    // 設備垂直擺放
    if (interfaceOrientation == UIDeviceOrientationPortrait)
    {
        [self.filterLensImageView setFrame:CGRectMake(20, 80, 280, 280)];
    }
    // 設備垂直 180 度擺放
    else if (interfaceOrientation == UIDeviceOrientationPortraitUpsideDown) {
        [self.filterLensImageView setFrame:CGRectMake(20, 80, 280, 280)];
    }
    // 設備水平向右擺放
    else if (interfaceOrientation == UIDeviceOrientationLandscapeRight) {
        [self.filterLensImageView setFrame:CGRectMake(80, 20, 280, 280)];
    }
    // 設備水平向左擺放
    else if (interfaceOrientation == UIDeviceOrientationLandscapeLeft) {
        [self.filterLensImageView setFrame:CGRectMake(80, 20, 280, 280)];
    }

    // 其它 (UIDeviceOrientationFaceUp, UIDeviceOrientationFaceDown,
    //           UIDeviceOrientationUnknown)
    else {
        [self.filterLensImageView setFrame:CGRectMake(80, 20, 280, 280)];
    }
   
    return YES;
}

....

    3. 編譯並執行
        直向:

        橫向:

-----------------------------------------------------------------------------------------

C. 濾鏡測試:
    1. 開啓 ViewController.h 檔案, 調整如下:
....
//@add for orientation Transform
- (CIImage *)orientationTransform:(CIImage *)sourceImage; // 方向轉變的調整
- (void)filterOrientationTransform:(CIImage *)sourceImage;  // 方向轉變的調整
....

    2. 開啓 ViewController.m 檔案, 調整如下:
....
//@add for filter Orientation Transform (方向轉變的調整)
- (void)filterOrientationTransform:(CIImage *)sourceImage
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
   
    // 設備垂直擺放
    if (orientation == UIDeviceOrientationPortrait)
    {
        [self.coreImageContext drawImage:sourceImage
                                  inRect:CGRectMake(23.5, 123.5, 274, 274) fromRect:[sourceImage extent]];
    }
    // 設備垂直 180 度擺放
    else if (orientation == UIDeviceOrientationPortraitUpsideDown) {
        [self.coreImageContext drawImage:sourceImage
                                  inRect:CGRectMake(23.5, 123.5, 274, 274) fromRect:[sourceImage extent]];
    }
    // 設備水平向右擺放
    else if (orientation == UIDeviceOrientationLandscapeRight) {
        [self.coreImageContext drawImage:sourceImage
                                  inRect:CGRectMake(83.5, 23.5, 274, 274) fromRect:[sourceImage extent]];
    }
    // 設備水平向左擺放
    else {
        [self.coreImageContext drawImage:sourceImage
                                  inRect:CGRectMake(83.5, 23.5, 274, 274) fromRect:[sourceImage extent]];
    }
}
....
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
   
    // 將取得的 sampleBuffer 轉成 CVPixelBuffer
    CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
   
    // 接著, 將 CVPixelBuffer 利用 Core Image 的初始化方法再轉成 CIImage.
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
       
    //@add:濾鏡測試
    //ciImage = [self filterTest:ciImage];
   
    //@add:方向轉變的調整
    //ciImage = [Filter4CamHelper orientationTransform:ciImage];
    ciImage = [self orientationTransform:ciImage];

    // 然後使用 CIContext 物件將其內容畫到 render buffer
    [self.coreImageContext drawImage:ciImage atPoint:CGPointZero fromRect:[ciImage extent]];
   
    //@add test for filter Rectangle
    //@add:濾鏡測試
    ciImage = [self filterTest:ciImage];
   
    //[self.coreImageContext drawImage:ciImage inRect:CGRectMake(23.5, 123.5, 274, 274) fromRect:[ciImage extent]];
    [self filterOrientationTransform:ciImage];
   
    // 最後, 在螢幕上呈現出來.
    [self.glContext presentRenderbuffer:GL_RENDERBUFFER];
}
....

   3. 編譯並執行
       直向:

        橫向:

   說明: 設備轉向時, 似乎不太穩定.

-----------------------------------------------------------------------------------------

D. 調整濾鏡顯示範圍 (2012/03/12 update)

      1. 開啓 ViewController.h 檔案, 修改如下:
....
@interface ViewController : GLKViewController <AVCaptureVideoDataOutputSampleBufferDelegate>
{
....
    BOOL isUsingFrontCamera;
    //@add 設備上一次方向是否為水平擺放(向左或向右皆算)
    BOOL isPreviousOrientationLandscape;
....
}
....
@property (assign) BOOL isUsingFrontCamera;
//@add
@property (assign) BOOL isPreviousOrientationLandscape;
....

      1. 開啓 ViewController.m 檔案, 修改如下:
....
@synthesize isUsingFrontCamera = _isUsingFrontCamera;
//@add
@synthesize isPreviousOrientationLandscape = _isPreviousOrientationLandscape;
....

- (void)filterOrientationTransform:(CIImage *)sourceImage
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
       
    // 設備垂直擺放
    if (orientation == UIDeviceOrientationPortrait)
    {
        //@add
        self.isPreviousOrientationLandscape = NO;
                                                                                                  
        [self.coreImageContext drawImage:sourceImage inRect:CGRectMake(23.5, 123.5, 274, 274)
                                // x 越小, 濾鏡越向右; y 負越多, 濾鏡越向上
                                fromRect:CGRectMake(23, -517.5, 274, 274)];
    }
    // 設備垂直 180 度擺放
    else if (orientation == UIDeviceOrientationPortraitUpsideDown) {
      
        //@add
        self.isPreviousOrientationLandscape = NO;
      
        [self.coreImageContext drawImage:sourceImage inRect:CGRectMake(23.5, 123.5, 274, 274)
                                // x 負越多, 濾鏡越向左; y 越多, 濾鏡越向上
                                fromRect:CGRectMake(-458.5, 123, 274, 274)];
    }
    // 設備水平向右擺放
    else if (orientation == UIDeviceOrientationLandscapeRight) {

        //@add
        self.isPreviousOrientationLandscape = YES;
      
        [self.coreImageContext drawImage:sourceImage inRect:CGRectMake(83.5, 23.5, 274, 274)
                                // x 負越多, 濾鏡越向右; y 負越多, 濾鏡越向上
                                fromRect:CGRectMake(-557, -457.5, 274, 274)];
    }
    // 設備水平向左擺放(最穩定)
    else if (orientation == UIDeviceOrientationLandscapeLeft) {

        //@add
        self.isPreviousOrientationLandscape = YES;
      
        [self.coreImageContext drawImage:sourceImage inRect:CGRectMake(83.5, 23.5, 274, 274)
                                // x 越大, 濾鏡越向左; y 越多, 濾鏡越向上
                                fromRect:CGRectMake(83.5, 23.5, 274, 274)];
    }
    // 其它 (UIDeviceOrientationFaceUp, UIDeviceOrientationFaceDown,
    //           UIDeviceOrientationUnknown)
    else {  
      
        //@在此不記錄上一次設備的方向
      
        //@add:上一次設備為水平擺放
        if (self.isPreviousOrientationLandscape == YES) {

            [self.coreImageContext drawImage:sourceImage inRect:CGRectMake(83.5, 23.5, 274, 274)
                                    // x 越大, 濾鏡越向左; y 越多, 濾鏡越向上
                                    fromRect:CGRectMake(83.5, 23.5, 274, 274)];
        }
        //@add:上一次設備為垂直擺放
        else {

            [self.coreImageContext drawImage:sourceImage inRect:CGRectMake(23.5, 123.5, 274, 274)
                                    // x 越大, 濾鏡越向左; y 越多, 濾鏡越向上
                                    fromRect:CGRectMake(23.5, 123.5, 274, 274)];
        }
    }
}

....
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
   
    //@add
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    if (orientation == UIDeviceOrientationLandscapeRight || orientation == UIDeviceOrientationLandscapeLeft) {
        self.isPreviousOrientationLandscape = YES;
    }
    else {
        self.isPreviousOrientationLandscape = NO;
    }
    ....
}
....

      3. 編譯並執行:
       直向:

       橫向:

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。