티스토리 뷰

Core Image tutorial Part. 2

(Ray wenderlich - Core Image tutorial: Getting Started 번역)

 

바쁜 사람들을 위한 1편 요약 혹은 복습)

 


- 코어 이미지는 여러분에게 쉽게 필터들을 이미지에 적용하게 해주는 강력한 프레임워크.

- Vibrane, hue, exposure 를 수정하는 것과 같은 모든 종류의 효과를 얻을 수 있음  

- CPU 또는 GPU 들 중 하나를 이미지 데이터를 처리하기 위해 사용 할 수 있고 아주 빠름.

- 비디오 프레임의 실시간 프로세싱을 하는데 충분

- 코어 이미지 필터는 또한 이미지나 비디오 프레임에 다양한 효과를 한번에 적용하기 위해서 필터들을 함께 연결지을 수 있음.

  * 다양한 필터들은 이미지에 적용되는 하나의 필터로 합쳐지는 것

  * 한번에 하나씩 각각의 필터들을 통해 이미지를 처리하는 것에 비교해서 매우 효율적


 

1. CIContext

 - 코어 이미지의 모든 프로세싱은 CIContext 내에서 수행 됩니다. 이것은 코어 그래픽스 혹은 OpenGL 컨텍스트와 다소 유사합니다.

2. CIImage

 - 이 클래스는 이미지 데이터를 가지고 있습니다. UIImage, 이미지 파일, pixel data 로부터 생성됩니다.

3. CIFilter

 - 이 클래스는 딕셔너리를 가지는데 해당 필터가 나타내는 특정 필터의 속성을 정의하고 있어요. 

    필터의 예시로는 vibrance, color inversion, cropping(생동감, 반전, 자르기) 등이 있습니다.

 

CIFilter 를 이미지에 적용하길 원할 때, 우리는 다음의 4가지 것들이 필요하다.


1. CIImage 객체를 만든다.

 - CIImage 는 몇 개의 초기화 메소드를 가진다. 대표적으로,

  * CIImage(contentsOfURL:), 

  * CIImage(data:), 

  * CIImage(CGImage:), 

  * CIImage(bitmapData:bytesPerRow:size:format:colorSpace:) 등등...

 - 우리는 이것들 중 대부분의 경우, 첫 번째 메소드를 사용할 것이다.

 

2. CIContext 를 만든다.

 - CIContext 는 CPU 혹 은 GPU 를 기반으로 한다. 

    CIContext 는 상대적으로 초기화 하는데 비용이 많이 들기 때문에, 이것을 반복적으로 만들기 보다는 오히려 재사용 한다.

    CIImage 객체를 아웃풋(출력)을 하려고 할 때는, 우리는 항상 하나를 필요로 하게 될 것이다.

 

3. CIFilter 를 만든다

 - 필터를 만들어낼 때마다, 많은 수의 프로퍼티를 구성해야 하는데 이는 우리가 사용하고자 하는 필터에 의존하게 됩니다.

 

4. 필터를 적용한 아웃풋을 얻는다. 

 - 필터는 사용자에게 아웃풋 이미지(필터 적용 결과)를 CIImage 로 주는데, 사용자는 이것을 UIImage 로 변환할 수 있습니다.

    CIContext 를 사용해서요.

 


 

2편 시작)

 

Putting It Into Context

 

살펴보기 전에, 우리는 '최적화' 에 대해 알아야 합니다.

 

 1편에서 전술한 것처럼 우린 "CIFilter" 를 적용하기 위해서는 "CIContext" 가 필요해요. 하지만 앞선 예시에서는 이 객체에 대한 언급이 없었어요. UIImage(CIImage:) 생성자가 모든 작업을 수행했어요. 얘는 CIContext 를 생성하고 이것을 이미지 필터링 작업을 수행하는데 사용하죠. 얘는 코어 이미지 API 를 사용하는 것을 매우 쉽게 만들어줘요. 

 

  하지만 큰 단점이 있어요. 얘는 자신이 사용될 때마다 새로운 CIContext 를 만들어내요. CIContext 인스턴스는 퍼포먼스를 증가시키기 위해 재사용 될 친구였어요. 만약 필터 값을 업데이트하기 위해 silder 객체를 사용하길 원한다면(+ 뒤에서 해볼거에요 !), 새로운 CIContext 를 필터를 변경할 때마다 매번 생성하는 것은 너무나 느린 방식이 될 거에요.

 

이것을 적절하게 만들어 봅시다. 코드의 4번째 부분을 삭제하고 다음의 코드로 대체해 보죠.

 

다시 섹션별로 살펴보도록 하죠(새로운 부분)


1. 여기에 CIContext 객체를 설정하고 CGImage 를 그리기 위해 사용합니다. "CIContext(options:)" 생성자는 컬러 포맷과 같은 옵션들을 지정하는 NSDictionary 를 가지며, context 가 CPU 혹은 GPU 상에서 작동하는지 여부를 지정합니다. 이번 앱에서 기본 값은 괜찮으니 argumentnil 을 전달하겠습니다.

 

2. "createCGImage(_ :, from:)" 을 CIImage 와 함께 문맥 상에서 호출하는 것은 새로운 CGImage 인스턴스를 리턴할 것입니다.

 

3. 다음으로 "UIImage(cgImage:)" 생성자를 전처럼 CIImage 로부터 직접 생성하는 것 대신 새롭게 생성된 CGImage 로 부터 UIImage 를 생성하기 위해 사용합니다. (+ 추가 : 이 부분에서, 오브젝티브-C 에서는 메모리 관리 문제가 있었는데, 스위프트에서는 ARC 가 자동적으로 코어 파운데이션 객체들을 릴리즈 해줄 수 있으니 걱정 마세요)


실행한다면, 전과 똑같이 작동했음을 볼 수 있습니다. 

 

지금까지 예시에서는 CIContext 의 생성을 직접 핸들링하는 것은 많은 차이를 만들어내지는 않습니다.

그러나 다음 세션에서, 우리는 왜 이것이 성능에서 중요한지 보게 될 것입니다. 물론 필터를 동적으로 수정하는 어빌리티를 구현해 볼거에요!

 

Changing Filter Values

 

필터의 값을 바꾸는 것은 대단하지만, 단지 코어 이미지 필터로 사용자가 할 수 있는 것의 시작일 뿐입니다.

슬라이더를 추가하고 설정해서 실시간으로 필터 값을 조정해보도록 해볼게요..

 

이미지 뷰의 오토레이아웃을 변경하겠습니다.  

 

(스토리보드 지문은 패스하겠습니다. 원문에서 확인하세용)

(https://www.raywenderlich.com/2305-core-image-tutorial-getting-started)

 

슬라이더의 값이 변화할 때마다, 다른 값을 가진 이미지 필터를 다시 작업해야 합니다..

하지만, 우린 이 전체 프로세스를 다시 수행하길 원하지 않아요. 매우 비효율적이고 너무 오래 걸리거든요.

이를 해결하기 위해, 우리는 클래스 내의 몇 가지 내용을 바꿀 것입니다.

왜냐면 viedDidLoad 메소드 내에 우리가 만든 객체의 일부를 유지할 수 있도록 하기 위함입니다.

 

우리가 수행하길 원하는 가장 중요한 내용은 CIContext 를 우리가 사용하길 원할 때마다 재사용하는 것이에요.

만약 우리가 이것을 매번 재생성한다면, 우리의 프로그램은 매우 느리게 작동할 거에요.

(기존 코드를 보면) 붙잡은 상태로(= 재사용 안하고) 있는 다른 것은 CIFilter 와 원래의 이미지를 가지고 있는 CIImage 입니다.

모든 아웃풋에 대해 우리가 새로운 CIImage 를 필요로 하게 될 것이지만, 시작 이미지는 일정하게 유지됩니다.

 

 이 작업을 수행하기 위한 인스턴수 변수들을 몇 개 더해볼게요. 다음의 3개의 프로퍼티를 뷰컨트롤러 클래스에 더해주세요.

이 값들을 암시적으로 언래핑된 옵셔널로 '!' 문법을 사용해서 선언했습니다.

왜냐하면 viewDidLoad 까지 우리는 초기화 하지 않을 것이기 때문이죠.

우리는 '?' 도 사용할 수 있었지만, 코드가 디자인된 이 방식('!')이 우리가 이 값들을 사용할 때에 옵셔널이;  nil 이 되는 것을 예방할 것이라는 걸 알아야 합니다. (+ 물론 안전성은 떨어지겠죠...)

암시적 언래핑 문법은 어느 곳에서나 '!' 마크 없이도 옵셔널을 읽어들이기 훨씬 쉽게 만들어 줍니다. 

 

viewDidLoad 내의 코드를 변경하여 새로운 로컬 변수들을 선언하는 것 대신 이 프로퍼티들을 사용하세요. 

(+ viewDidLoad 에 선언했던 지역 변수들이 삭제되고 코드가 좀 더 깔끔해졌습니다.)

 

이제 changeValue 메소드를 구현하겠습니다.

이 메소드에서 구현할 내용은 CIFilter 딕셔너리의 내 "inputIntensity" 키의 값을 바꾸는 것입니다.

(+ 슬라이더를 이용해서 필터에 대한 강도를 조절할 예정이거든요)

 

일단 이 값을 바꾸게 되면 우리는 몇 가지 단계를 반복해야 합니다.

 

1. CIFilter 로부터 CIImage 아웃풋을 얻습니다.

2. CIImage 를 CGImage 로 변환합니다.

3. CGImage 를 UIImage 로 변환하고 image view 내에 표시합니다.

 

"amountSliderValueChanged(sender:)" 함수를 다음과 같이 바꾸도록 하겠습니다.

메소드 정의 부분에서 AnyObject 에서 UISilderargument 타입을 변경한 것을 주목하세요.

오직 이 메소드를 UISlider 로부터 값을 검색하기 위해 사용할 것입니다.

만약 AnyObjectargument 타입을 남겨둔다면, 이것을 UISlider 로 캐스팅을 해야하거나 다음 라인해서 에러를 던질 것입니다.

 

우리는 slider 로부터 값을 검색합니다 (슬라이더는 Float 값을 리턴하죠).

우리의 slider 는 기본 값이 설정되어 있는데, 최저가 0.0, 최고가 1.0, 기본값이 0.5 입니다. 

 

CIFilter 는 메소드를 가지는데, 이 메소드는 우리에게 CIFilterdictionary 내의 다른 키들에 대한 값들을 설정하는 것을 가능하게 해줍니다. 우리의 slider 로부터 얻고자 하는 것이면 무엇이든 간에, 우리는 단지 "kCIInputIntensity" 를 설정하면 됩니다.

(+ 그 이유는) 스위프트는 자동적으로 초기의 "CFFloat" 값을 "NSNumber" 객체로 변환해줍니다.

"setValue(value:forKey:)" 와 함께 사용하기에 적합하도록요. 

 

나머지는 동일하고, 이제부터는 "amountSliderValueChanged(sender:)" 를, CIFilter 의 아웃풋(filter.outputImage)을 UIImageView 에 렌더링 하기 위해 사용할 것입니다.

 

 

 

 

오늘은 여기까지, 다음 시간에~~~~

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함