티스토리 툴바


블로그 이미지
궁수자리

Rss feed Tistory
프로그래밍 이야기 2010/04/28 09:45

iPhone 카메라에서 영상 데이터 얻어오기 팁 (OS 3.x)

지금까지 PLCameraController를 사용하는 방법은 오버레이된 콘텐츠 (OpenGL 로 그려진 장면 등) 가 영상 캡쳐에 그대로 함께 캡쳐가 된다는 단점이 있었다. 마커나 대상물 추적을 통해 가상 객체를 삽입해야 하는 증강현실 응용 앱에서는 치명적인 문제인데, 가상 객체를 합성하게 되면 가상 객체가 영상의 대상물을 가리게 되므로 추적이 불가능해지기 때문이다. 

최근에 이와 관련된 내용을 찾던 중에 UIWindow 두 개를 사용하여 오버레이된 콘텐츠가 함께 캡쳐되는 문제를 피해갈 수 있다는 댓글을 보았었다. UIWindow를 두개 사용한다는 것이 이상하게 보였고 (보통 아이폰 앱에서는 UIWindow가 하나이다.), 정확히 어떻게 하면 된다는 얘기가 없었기 때문에 그러려니 하고 말았었다. 

그러다가 최근에 카메라 영상 캡쳐를 할 필요가 있었기 때문에 몇몇 블로그/게시판의 글들을 참조하여 여러 방향으로 삽질을 거듭한 끝에  마침내 카메라로부터 영상 데이터를 캡쳐해 올 수 있게 되었다. 


지금부터는 UIWindow 두 개를 어떻게 사용하는지에 대한 설명이다. 

기본적으로 application delegate 는 UIWidow 하나를 가지고 있는데 여기에 UIWindow 를 previewWindow 라는 이름으로 하나 더 추가해 준다. 나중에 previewWindow 에 PLCameraController 에서 얻는 previewView를 subview로 넣어주게 된다. 

UIWindow *window;
UIWindow *previewWindow ;


그 다음 'applicationDidFinishLaunching' 메소드로 가서 초기화를 수행한다. 
먼저 메인 UIWindow 의 배경을 투명하게 만들어준다.  

window.opaque = NO ;
window.backgroundColor = [UIColor clearColor] ;


그 다음 흔히 하듯이 메인 UIWindow에 추가될 view를 초기화 한다. 아래의 예에서는 OpenGL 뷰를 만들어 subview 로 넣어주었다. OpenGL 뷰 뒤로 삽입될 비디오 background를 볼 수 있도록 역시 투명한 배경색을 갖도록 셋팅해준다 (이전 글 참조). 

glView = [[EAGLView alloc]
initWithFrame:CGRectMake(0, 0, video_width, video_height)
pixelFormat:kEAGLColorFormatRGBA8
depthFormat:GL_DEPTH_COMPONENT16_OES
stencilFormat:0
preserveBackbuffer:NO] ;

glView.opaque = NO ;
glView.backgroundColor = [UIColor clearColor] ;
[window addSubview:glView] ;


PLCameraController 와 previewWindow를 초기화 해 준다. 

if(camController != nil)
     [camController release] ;

// Initialization of PLCameraController
camController = [PLCameraController sharedInstance] ;
.....
previewWindow = [[UIWindow alloc] init] ;
previewWindow.autoresizesSubviews = YES ;


PLCameraController 의 previewView를 previewWindow의 subview로 추가해 준다. 아래 코드에서 preview.frame 의 크기가 나중에 획득할 영상의 가로/세로 크기가 된다. 비율을 유지하면서 화면에 꽉차게 만들기 위해 (320, 426)의 값을 주었다. 

UIView * preview = [camController previewView] ;
preview.frame = CGRectMake(0,0, 320, 426) ;
[previewWindow addSubview:preview] ;


previewWindow와 메인 window를 화면에 나타나도록 한다. 이 때 makeKeyAndVisible 메소드는 반드시 previewWindow 를 먼저, 메인 window를 나중에 호출해 주어야 한다. 

[previewWindow makeKeyAndVisible] ;
[window makeKeyAndVisible];

이제 프로그램을 빌드하고 실행하면 비디오 preview를 볼 수 있게된다. 
카메라에서 RGB data를 얻기 위해서는 많이 쓰이는 아래와 같은 코드를 사용한다. 

CoreSurfaceBufferRef coreSurfaceBuffer =
      [cameraController _createPreviewIOSurface];

if (!coreSurfaceBuffer) return;

Surface *surface =
      [[Surface alloc]initWithCoreSurfaceBuffer:coreSurfaceBuffer];
[surface lock];

previewHeight = surface.height;
previewWidth = surface.width;
previewBytesPerRow = previewWidth*4;
pixelDataLength = previewBytesPerRow*previewHeight;

void *pixels = surface.baseAddress;
int sufaceBytesPerRow = surface.bytesPerRow ;

// Copy the pixels to your buffer
memcpy(Your_buffer, pixels, pixelDataLength) ;


아래는 위와 같은 구현을 통해 카메라에서 획득한 영상 데이터를 이용한 간단한 증강현실 어플리케이션이다. 



위에 설명한 방법이 완벽한 것은 아니며, 다음과 같은 문제점이 있다. 먼저, 가끔 영상의 scanline이 잘 맞지 않은 상태에서 capture되는 경우가 생긴다. 증강현실을 위한 Tracking에 있어서 이런 경우 문제가 된다.

두 번째는 오토포커싱 기능 때문이다. 3GS에서는 오토 포커싱 될 때마다 사각형이 표시되는데, 이 사각형도 함께 캡쳐가 되므로 이 현상 역시 경우에 따라 문제가 될 수도 있다. 포커싱 사각형을 없애려면  PLCameraController 의 delegate 메소드인 cameraControllerReadyStateChanged 를 아래와 같이 구현해 준다.

- (void)cameraControllerReadyStateChanged:(NSNotification *)aNotification
{
     [(PLCameraController *)cameraController setDontShowFocus:YES] ;
}

아이폰 OS 4 에서는 Full camera access 를 지원한다고 하니, 조만간 해결될 문제겠지만 OS 4가 나오기 전까지는 연구용으로 그럭저럭 써먹을 수 있는 방법인 것 같다.  

저작자 표시 비영리 변경 금지
TOTAL 73,112 TODAY 4