티스토리 뷰


Core Image Filter


코어 이미지 필터는 입력 이미지와 필터의 동작을 설정하는 옵션을 매개변수로 사용한다.

적용할 필터의 리스트를 지정하면 각필터를 지정했을 때

계산을 실행하는게 아니라 최종 출력 이미지를 요청할 때만

이 필터들을 한꺼번에 모두 적용한다.




필터 카테고리와 필터


코어 이미지 필터는 내부적으로 카테고리 단위로 구성된다.

한 필터는 하나 이상의 카테고리에 속할 수 있다.

카테고리를 이용해서 원하는 작업에 어떤 코어 이미지 필터들이 필요한지 결정할 수 있다.


CategoryKey 를 이용하여 CIFilterArray 를 구할 수 있다.

(https://developer.apple.com/library/content/documentation/GraphicsImaging/Reference/CoreImageFilterReference/)


self.categoryList = @{

    @"Blur" : kCICategoryBlur,

    @"Color Adjustment" : kCICategoryColorAdjustment,

    @"Color Effect" : kCICategoryColorEffect,

    @"Composite" : kCICategoryCompositeOperation,

    @"Distortion" : kCICategoryDistortionEffect,

    @"Generator" : kCICategoryGenerator,

    @"Geometry Adjustment" : kCICategoryGeometryAdjustment,

    @"Gradient" : kCICategoryGradient,

    @"Halftone Effect" : kCICategoryHalftoneEffect,

    @"Reduction" : kCICategoryReduction,

    @"Sharpen" : kCICategorySharpen,

    @"Stylize" : kCICategoryStylize,

    @"Tile" : kCICategoryTileEffect,

    @"Transition" : kCICategoryTransition

};

self.categoryKeys = [self.categoryList allKeys];


self.filterNameArray = [CIFilter filterNamesInCategory:self.selectedCategory];


각각의 filter 값에 대한 설명은 위 document 에 아주 상세히 설명되어 있으므로 사용법만 알아본다.




필터 속성


모든 CIFilter 객체는 attributes 라는 딕셔너리를 프로퍼티로 갖고있다.

이 dictionary 객체는 필터와 설정에 필요한 모든 정보를 담고있다.


CIFilter

NSArray<NSString *> *inputKeys;

NSArray<NSString *> *outputKeys;

NSDictionary<NSString *, id (NSDictionary *)> *attributes;


NSString *attributeName = [[self.selectedFilter inputKeys] objectAtIndex:indexPath.row];

NSDictionary *attributeInfo = [[self.selectedFilter attributes] valueForKey:attributeName];


inputKeys 는 attributeName array 이다.

attibuteInfo 는 attributes 를 이용하여 얻어올 수 있다.


attributeInfo 를 이용하면 속성이 어떤 타입인지, 

속성의 정보를 표현하는 데 어떤 클래스를 사용해야하는지 알 수 있다.


모든 필터가 속성 타입과 속성 클래스를 동일한 방식으로 지정하지 않는다.

어떤 필터는 kCIAttributeTypeColor 라는 속성 타입만을 지정할 수 있고,

어떤 필터는 CIColor 라는 속성 클래스만을 지정할 수 있다.


따라서 attributeType 과 attributeClass 를 사용하여 사용자가 조절할 수 있는 값을 사용한다.


- (NSString *)getCellIdentifierForAttributeType:(NSDictionary *)attributeInfo

{

    NSString *attributeType = @"";

    if ([attributeInfo objectForKey:kCIAttributeType]) {

        attributeType = [attributeInfo objectForKey:kCIAttributeType];

    }


    NSString *attributeClass =

    [attributeInfo objectForKey:kCIAttributeClass];


    NSString *cellIdentifier = @"";


    if ([attributeType isEqualToString:kCIAttributeTypeColor] ||

        [attributeClass isEqualToString:@"CIColor"])

    {

        cellIdentifier = kICSInputColorCellIdentifier;

    }


    if ([attributeType isEqualToString:kCIAttributeTypeImage] ||

        [attributeClass isEqualToString:@"CIImage"])

    {

        cellIdentifier = kICSInputImageCellIdentifier;

    }


    if ([attributeType isEqualToString:kCIAttributeTypeScalar] ||

        [attributeType isEqualToString:kCIAttributeTypeDistance] ||

        [attributeType isEqualToString:kCIAttributeTypeAngle] ||

        [attributeType isEqualToString:kCIAttributeTypeTime])

    {

        cellIdentifier = kICSInputNumberCellIdentifier;

    }


    if ([attributeType isEqualToString:kCIAttributeTypePosition] ||

        [attributeType isEqualToString:kCIAttributeTypeOffset] ||

        [attributeType isEqualToString:kCIAttributeTypeRectangle] ||

        [attributeClass isEqualToString:@"CIVector"])

    {

        cellIdentifier = kICSInputVectorCellIdentifier;

    }


    if ([attributeClass isEqualToString:@"NSValue"])

    {

        cellIdentifier = kICSInputTransformCellIdentifier;

    }


    return cellIdentifier;

}


위 정보는 cellForRow 에서 attributeInfo 를 이용하여 호출하면 된다.




이미지 객체 초기화


코어 이미지에서 이미지에 필터를 적용하려면 CIImage 클래스의 객체로 만들어야한다.

UIImage 객체로부터 CIImage 객체를 얻으려면, CGImage 로 변환 후 이를 다시 CIImage 로 변환해야한다.

( UIImage -> CGImage -> CIImage )


CGImageRef inputImageRef = [sourceImage CGImage];

CIImage *inputImage = [CIImage imageWithCGImage:inputImageRef];




필터링한 이미지 그리기


필터링한 이미지를 출력(UIImage 화) 하려면 필터의 속성 중에서 outputImage 객체를 요청한다.

이 객체를 컨텍스트, 이미지, 비트맵, 픽셀 버퍼 중 출력하고 싶은 대상과

대응하는 적절한 메소드를 호출하면된다.


이 시점에서는 이미 입력 이미지에 대해 필터 적용을 끝내고 출력이미지 객체가 생성돼 있어야한다.

일반적으로는 context 를 프로퍼티로서 미리 초기화하는 게 일반적이다.



- (IBAction)previewButtonTouched:(id)sender

{

    CIContext *context = [CIContext contextWithOptions:nil];

    

    CIFilter *filter = self.selectedFilter;

    CIImage *resultImage = [filter valueForKey:kCIOutputImageKey];

    CGRect imageRect = CGRectMake(0, 0, 200, 200);

    

    CGImageRef resultCGImage =

    [context createCGImage:resultImage fromRect:imageRect];

        

    UIImage *resultUIImage =

    [UIImage imageWithCGImage:resultCGImage];


    [self.previewImageView setImage:resultUIImage];

}


컨텍스트를 초기화 한 후 filter 를 통해 outputImage 에 대한 참조를 얻는데,

필터 중에는 입력보다 훨씬 더 커지는 결과 이미지를 생성하는 것도 있다. (Generator Category)

따라서 원하는 크기를 지정할 때 (imageRect) 고려가 필요하다.




여러개의 필터 적용하기


CIFilter *lastFilter = [self.filterArray lastObject];


if (lastFilter) {

    if ([[filter inputKeys] containsObject:@"inputImage"] ) {

        [filter setValue:[lastFilter outputImage]

                      forKey:@"inputImage"];

    }

}

[self.filterArray addObject:filter];


lastFilter 를 구해 와 inputImage 에 outputImage 를 set 해준다.


CIContext *context = [CIContext contextWithOptions:nil];

CIImage *resultImage = [filter valueForKey:kCIOutputImageKey];


CGImageRef resultCGImage = [context createCGImage:resultImage fromRect:CGRectMake(0, 0, 200, 200)];


UIImage *resultUIImage = [UIImage imageWithCGImage:resultCGImage];

[self.resultImageView setImage:resultUIImage];


코어 이미지는 필터링에 필요한 계산을 최소화하기 위해

자동으로 필터 체인을 최적화한다.

각 단계의 필터를 개별적으로 처리하지 않고

모든 필터에서 필요한 수학 계산을 합쳐서 한꺼번에 필터를 적용한다.







공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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
글 보관함