MILLEN BOX

音楽好きの元組み込みソフトエンジニアによるプログラミング(主にiOSアプリ開発)の勉強の記録

Core ImageでBlur画像を作成する(Ver.1 & 2) [CIFilter]

CoreImageにてBlur画像を作成する為の関数についてメモを残しときます。

1. ガウジアンFilter関数 Ver.1

以下は元画像(CIImage)からBlur画像を作成する関数です。
UIImageからCIImageのゲット方法は let imageCIImage = CIImage(CGImage: imageUIImage.CGImage!) です。

    /**
     ガウジアンFilterを適応する
     
     - parameter inputCIImage : 元CIICmage
     - parameter value : フィルターのかけ度合い
     - returns : ぼかし画像のサイズ
     */
    func applyGaussianBlurFilter(inputCIImage: CIImage, value: Float) -> CIImage {

        //ガウシンアン(ぼかし)フィルターの適応
        let filter = CIFilter(name: "CIGaussianBlur")
        filter?.setValue(inputCIImage, forKey: kCIInputImageKey)
        filter?.setValue((value), forKey: kCIInputRadiusKey)
        let outputCIImage = filter?.outputImage
        
        guard let _outputCIImage = outputCIImage else {
            fatalError("applyGaussianBlurFilter does not work.")
        }
        
        return _outputCIImage

    }

CIImageからUIImageへの復元は以下を参考にして下さい。
(変数が何を示しているかは関数名から想像お願いいたします...汗)

let rect = CGRect(origin: CGPointZero, size: imageUIImage.size)
let context = CIContext(options: nil)
let cgImage = context.createCGImage(outputCIImage, fromRect: rect)
let blurImage = UIImage(CGImage: cgImage)

2. ガウジアンFilter関数 Ver.2

Ver.1 のままだとガウジアンFilter適応後の画像端が透明色のグラデーションがかかってしまう問題があります。
対策としてClampフィルターを前処理として適応します。
この辺の詳細については以下を参照の事。
▶︎ objective c - Correct crop of CIGaussianBlur - Stack Overflow

以下、関数です。

    /**
     ガウジアンFilterを適応する
     
     - parameter inputCIImage : 元CIICmage
     - parameter value : フィルターのかけ度合い
     - returns : ぼかし画像のサイズ
     */
    func applyGaussianBlurFilter(inputCIImage: CIImage, value: Float) -> CIImage {
        
        //inputCIImageを何も考えずにCIGaussianBlurをかけると画面端に透過色が混じる
        //その対策の為、CIAffineClampを使い画面外側に拡大した元画像を配置し現象の対策を行う
        //URL: http://stackoverflow.com/questions/12839729/correct-crop-of-cigaussianblur
        let affineClampFilter = CIFilter(name: "CIAffineClamp")
        let xform = CGAffineTransformMakeScale(1.0, 1.0)
        affineClampFilter?.setValue(inputCIImage, forKey: kCIInputImageKey)
        affineClampFilter?.setValue(NSValue(CGAffineTransform: xform), forKey: "inputTransform")
        let outputAfterCalmp = affineClampFilter?.outputImage

        //ガウシンアン(ぼかし)フィルターの適応
        let filter = CIFilter(name: "CIGaussianBlur")
        filter?.setValue(outputAfterCalmp, forKey: kCIInputImageKey)
        filter?.setValue((value), forKey: kCIInputRadiusKey)
        let outputCIImage = filter?.outputImage
        
        guard let _outputCIImage = outputCIImage else {
            fatalError("applyGaussianBlurFilter does not work.")
        }
        
        return _outputCIImage

    }

CIImageからUIImageへの復元はrectの取得方法に変更があります。

let rect = inputCIImage.extent
let context = CIContext(options: nil)
let cgImage = context.createCGImage(outputCIImage, fromRect: rect)
let blurImage = UIImage(CGImage: cgImage)

所感

Ver.1で発生した「画面端透明問題」で結構ハマってしましました。
情報提供頂いた @akio0911 さんには感謝です!