Core Image使用指南

簡(jiǎn)介

Core Image是一個(gè)圖片處理及分析庫(kù),里面封裝了非常易用的API,比如大量常用濾鏡。因?yàn)樗柚鶪PU或者CPU渲染,所以可以接近實(shí)時(shí)的速度處理靜態(tài)圖片和視頻圖片,圖片可來(lái)自Core Graphics、Core Video以及I/O框架。

Core Image架構(gòu)

功能列表

Core Image提供的能力包括:

  • 通過(guò)大量?jī)?nèi)置濾鏡處理圖片
  • 通過(guò)濾鏡鏈自定義處理效果
  • 自動(dòng)化圖片增強(qiáng)
  • 特征檢測(cè),比如人臉、矩形、文字等
  • 創(chuàng)建自定義濾鏡

基本概念

濾鏡

一個(gè)濾鏡在語(yǔ)義上表示某種能力,當(dāng)作用在一張圖片上時(shí),可以經(jīng)過(guò)某種變換從而得到另一張圖片。

我們都知道,圖片在計(jì)算機(jī)中是以像素為基本單位而保存的像素矩陣,通過(guò)圖像處理單元GPU才能將其顯示在屏幕上。在數(shù)學(xué)上,濾鏡其實(shí)也是一個(gè)矩陣,也叫卷積核,通常比圖片的像素矩陣維度小得多。在真正處理圖片時(shí),圖片像素矩陣和卷積核做卷積運(yùn)算,最終輸出一個(gè)“新”圖片。

濾鏡的處理過(guò)程

濾鏡鏈

顧名思義,濾鏡鏈就是將多個(gè)濾鏡鏈接在一起,前一個(gè)濾鏡的輸出作為下一個(gè)濾鏡的輸入,就像流水線一樣,圖片從第一個(gè)濾鏡中進(jìn)入,處理之后再進(jìn)入下一個(gè),一直到最后一個(gè)濾鏡。通過(guò)這種方式,可以創(chuàng)建出更加如何需求的效果。

但實(shí)際上,Core Image的處理邏輯有點(diǎn)不同,它并不會(huì)讓一張圖片經(jīng)過(guò)多次處理。為了性能考慮,Core Image會(huì)先將多個(gè)濾鏡的卷積核合成為一個(gè),然后一次性得出最終的結(jié)果。

圖片處理

簡(jiǎn)單來(lái)說(shuō),圖片處理就是將某張圖片作用于某個(gè)濾鏡的過(guò)程。

在Core Image中,圖片為CIImage,濾鏡為CIFilter,為濾鏡設(shè)置參數(shù)要通過(guò)KVC實(shí)現(xiàn)。同時(shí),還需要一個(gè)上下文對(duì)象CIContext,里面保存著所有相關(guān)的細(xì)節(jié)。因?yàn)檫@些細(xì)節(jié)非常多,所以最好在合適的時(shí)機(jī)創(chuàng)建一個(gè)可重復(fù)利用的CIContext對(duì)象。

單濾鏡

最基本的用法就是只使用單個(gè)濾鏡,如下所示。

- (void)blurImageWithRadius:(CGFloat)radius {    
    UIImage *originalImage = [UIImage imageNamed:@"blackboard.jpg"];
    CIImage *ciimage = [CIImage imageWithData: UIImageJPEGRepresentation(originalImage, .9)];
    
    CIFilter *gaussianBlur = [CIFilter filterWithName:@"CIGaussianBlur"];
    [gaussianBlur setValue:@(radius) forKey:@"inputRadius"];
    [gaussianBlur setValue:ciimage forKey:@"inputImage"];
    
    [self.processedImageView setImage:[UIImage imageWithCIImage:gaussianBlur.outputImage]];
}

在CoreImage中所有相關(guān)操作中只能使用CIImage這個(gè)格式,但是它并不能直接呈現(xiàn)給用戶,因?yàn)?strong>CIImage只是一種用來(lái)生產(chǎn)圖片的“配方”,其實(shí)就是一種操作流程,比如從URL讀取圖片文件,某個(gè)濾鏡操作的輸出等,只有在渲染或者輸出時(shí)才會(huì)開始執(zhí)行??偨Y(jié)下來(lái),可以通過(guò)下面這些方法創(chuàng)建CIImage:

  • NSURL
  • NSData
  • UIImage
  • CGImageRef
  • CVImageBufferRef
  • CIImageProvider
- (void)createCIImageMethods {
    CIImage *ciimg;
    
    // 1. URL
    ciimg = [[CIImage alloc] initWithContentsOfURL:[NSURL URLWithString:@"some-url"]];
    
    // 2. bytes
    ciimg = [CIImage imageWithData:[NSData dataWithContentsOfFile:@"some-file-path"]];
    
    // 3. UIImage
    ciimg = [CIImage imageWithData:UIImageJPEGRepresentation([UIImage imageNamed:@"some-img-name"], .9)];
    ciimg = [CIImage imageWithData:UIImagePNGRepresentation([UIImage imageNamed:@"png-name"])];
    
    // 4. CGImageRef
    ciimg = [CIImage imageWithCGImage:[UIImage imageNamed:@"some-img"].CGImage];
    
    //...
}

濾鏡分類

Core Image中有大量的濾鏡,而且隨著系統(tǒng)的不斷升級(jí),還在不斷添加新的濾鏡。系統(tǒng)將它們分為以下這些類別:

類別名稱 說(shuō)明 例子
CICategoryBlur 模糊 高斯模糊、降噪等
CICategoryColorAdjustment 顏色調(diào)整 色值、曝光度、明暗度調(diào)整,色溫,色調(diào)曲線等
CICategoryColorEffect 顏色效果 色值轉(zhuǎn)換、黑白效果、褪色等
CICategoryCompositeOperation 合成 疊加,顏色混合、差分、乘除,亮度、色度混合等等
CICategoryDistortionEffect 扭曲 隆起、線性隆起,德羅斯特效應(yīng),替換扭曲,玻璃扭曲等
CICategoryGenerator 生成器 生成條形碼、二維碼、星光??、日光,純色圖片、隨機(jī)圖片等
CICategoryGeometryAdjustment 幾何變換 仿射、透視變換,剪裁,蘭索斯縮放
CICategoryGradient 漸變 高斯?jié)u變、線性漸變、徑向漸變等
CICategoryHalftoneEffect 網(wǎng)版效果 圓形網(wǎng)屏,點(diǎn)狀網(wǎng)目板等
CICategoryReduction 不知道該如何翻譯 區(qū)域平均值、最值,行、列平均值等
CICategorySharpen 銳化 亮度銳化、非銳化蒙版
CICategoryStylize 風(fēng)格化 蒙版混合,軟化邊緣,喜劇效果,卷積,結(jié)晶,邊緣檢測(cè)等
CICategoryTileEffect 鋪貼效果 以多種不同形式填充圖案等
CICategoryTransition 過(guò)渡 條形過(guò)渡,溶劑過(guò)渡等

把這些功能組合在一起,基本可以實(shí)現(xiàn)一個(gè)Photoshop了。

濾鏡鏈

前面說(shuō)了,當(dāng)要經(jīng)過(guò)多個(gè)濾鏡的處理時(shí),CoreImage為了提高性能會(huì)將多個(gè)濾鏡合成為一個(gè),并在合適時(shí)機(jī)完成處理。

例如,如果分步處理,其流程如下:

分步處理濾鏡鏈

但如果合成為一個(gè)Filter,則其流程如下:

將多個(gè)濾鏡合成為一個(gè)
- (CIImage *)processWithImage:(CIImage *)image fileterName:(NSString *)name params:(NSDictionary *)params {
    CIFilter *filter = [CIFilter filterWithName:name];
    [filter setValue:image forKey:@"inputImage"];
    for (NSString *key in params.allKeys) {
        [filter setValue:params[key] forKey:key];
    }
    return filter.outputImage;
}

- (IBAction)startProcessWithChain:(UIButton *)sender {
    CIImage *blurImg, *bloomImg, *croppedImg;
    blurImg = [self processWithImage:self.inputImage
                         fileterName:@"CIGaussianBlur"
                              params:@{kCIInputRadiusKey: @(1.2)}];
    bloomImg = [self processWithImage:blurImg
                          fileterName:@"CIBloom"
                               params:@{kCIInputRadiusKey: @(8.0),
                                        kCIInputIntensityKey: @(1.0)}];
    croppedImg = [bloomImg imageByCroppingToRect:CGRectMake(50, 100, 300, 300)];
    
    [self.processedImageView setImage:[UIImage imageWithCIImage:croppedImg]];
}

常用操作

Core Image除過(guò)用CFilter來(lái)處理圖片外,還可以通過(guò)一些預(yù)定義的方法直接處理圖片,將更加簡(jiǎn)便。比如:

  • initWithColor: 純色圖片
  • imageByApplyingTransform: 給圖片進(jìn)行仿射變換
  • imageByCompositingOverImage: 疊加圖片
  • imageByCroppingToRect: 剪裁圖片
  • imageByClampingToRect: 擴(kuò)展邊界
  • imageByInsertingIntermediate 插值

檢測(cè)

在圖片識(shí)別處理中,如果要識(shí)別特定對(duì)象,一般都要先進(jìn)行輪廓檢測(cè),然后再根據(jù)輪廓剪裁后識(shí)別物體,這樣會(huì)更加高效準(zhǔn)確。比如人臉、矩形等對(duì)象的識(shí)別。在Core Image中,提供了開箱即用的輪廓檢測(cè)功能,其中只能進(jìn)行三類操作:人臉、矩形、文字。下面看看人臉檢測(cè)的使用方法:

- (void)detect:(UIBarButtonItem *)sender{
    CIImage *image = [CIImage imageWithData:UIImageJPEGRepresentation(self.image, .95)];
    NSLog(@"image size: %@", NSStringFromCGSize(self.image.size));
    CIContext *context = [CIContext context];
    NSDictionary *options = @{CIDetectorAccuracy: CIDetectorAccuracyHigh};
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace context:context options:options];
    options = @{CIDetectorImageOrientation: [[image properties] valueForKey:(NSString *)kCGImagePropertyOrientation]};
    
    NSArray *features = [detector featuresInImage:image options:options];
    
    for (CIFaceFeature *feature in features) {
        NSLog(@"face bounds: %@", NSStringFromCGRect(feature.bounds));
        [self drawBorderWithFaceFeature:feature];
    }
}

- (void)drawBorderWithFaceFeature:(CIFaceFeature *)feature{
    CGRect frame = [self convertFaceBoundsToView:feature.bounds];
    NSLog(@"converted face bounds: %@", NSStringFromCGRect(frame));

    UILabel *label = [[UILabel alloc] initWithFrame:frame];
    label.backgroundColor = [UIColor clearColor];
    label.layer.borderColor = [UIColor redColor].CGColor;
    label.layer.borderWidth = 2.f;
    [self.imageView addSubview:label];
}

- (CGRect)convertFaceBoundsToView:(CGRect)bounds{
    CGFloat ratio = CGRectGetWidth(self.imageView.bounds)/self.image.size.width;
    return CGRectMake(CGRectGetMinX(bounds)*ratio, CGRectGetMinY(bounds)*ratio, CGRectGetWidth(bounds)*ratio, CGRectGetHeight(bounds)*ratio);
}

經(jīng)過(guò)使用發(fā)現(xiàn),只要當(dāng)圖片中含有少量人時(shí)結(jié)果比較準(zhǔn)確,當(dāng)圖片清晰度降低、并且人較多時(shí)結(jié)果不一定準(zhǔn)確。

注意點(diǎn)

為了提高應(yīng)用程序的性能,在使用Core Image時(shí)盡可能注意以下細(xì)節(jié):

  • 不要每次都創(chuàng)建CIContext,應(yīng)盡可能復(fù)用;
  • 如果沒(méi)有必要,避免動(dòng)畫和顏色空間管理;
  • 盡可能使用更小的圖片、簡(jiǎn)單的濾鏡;
  • 確保不要超過(guò)CPU或者GPU的限度等。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容