Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Swift:CIAffineClampを使って縁まで綺麗なぼかし画像を取得する

More than 1 year has passed since last update.

CIAffineClampってなぁに

CIAffineClamp.png

CIAffineClampによるフィルターを画像に適用すると,画像の縁(上下左右1px)をそれぞれの方向に無限大に引き伸ばした仮想上の画像データを生成することができます.これにより,ガウシアン・フィルタや一部のカラーフィルタのように,あるピクセルの周囲のピクセルをサンプリングしてそのピクセルの色を決定するようなフィルタ(下図)を扱う場合に画像縁の欠けている部分を補うことができます.
↓こういうやつ
ガウシアン.png
参照できない.png
↑デフォルトでは,はみ出した参照できない部分は透明色で補完されます.

直接CIGaussianBlurを使った場合

before.png
左)オリジナル,右)ぼかし加工結果
画像の縁の色が薄くなってぼかしが弱いことがわかります.

ソース

// オリジナル画像
let nsImage = NSImage(imageLiteralResourceName: "Test")        
guard let imageData = nsImage.tiffRepresentation, let ciImage = CIImage(data: imageData) else { return }

// ガウシアン・フィルタ
guard let blurFilter = CIFilter(name: "CIGaussianBlur") else { return }
blurFilter.setValue(ciImage, forKey: kCIInputImageKey)
blurFilter.setValue(5, forKey: kCIInputRadiusKey)
guard let blurImage = blurFilter.outputImage else { return }
let context = CIContext(options: nil)
guard let resultImage = context.createCGImage(blurImage, from: CGRect(origin: .zero, size: nsImage.size)) else { return }

resultView.image = NSImage(cgImage: resultImage, size: nsImage.size)

CIAffineClampを介して間接的にCIGaussianBlurを使った場合

after.png
左)オリジナル,中央)CIAffineClamp時点での結果,右)ぼかし加工結果
画像の縁までしっかりぼかしがかかっていることがわかります.

ソース

// オリジナル画像
let nsImage = NSImage(imageLiteralResourceName: "Test")        
guard let imageData = nsImage.tiffRepresentation, let ciImage = CIImage(data: imageData) else { return }

// CIAffineClamp
guard let clampFilter = CIFilter(name: "CIAffineClamp") else { return }
clampFilter.setValue(ciImage, forKey: kCIInputImageKey)
clampFilter.setValue(CGAffineTransform(scaleX: 1.0, y: 1.0), forKey: kCIInputTransformKey)
guard let clampImage = clampFilter.outputImage else { return }
let context = CIContext(options: nil)
let rect = CGRect(origin: CGPoint(x: -25, y: -25), size: CGSize(width:  nsImage.size.width + 50, height: nsImage.size.height + 50))
guard let cgImage = context.createCGImage(clampImage, from: rect) else { return }

imageView.image = NSImage(cgImage: cgImage, size: rect.size)

// ガウシアン・フィルタ
guard let blurFilter = CIFilter(name: "CIGaussianBlur") else { return }
blurFilter.setValue(clampImage, forKey: kCIInputImageKey)
blurFilter.setValue(5, forKey: kCIInputRadiusKey)
guard let blurImage = blurFilter.outputImage else { return }
guard let resultImage = context.createCGImage(blurImage, from: CGRect(origin: .zero, size: nsImage.size)) else { return }

resultView.image = NSImage(cgImage: resultImage, size: nsImage.size)

所感

CIFilterはうまく組み合わせることで,効率的に高速な画像処理が行えるため,ガンガン使っていきましょう.

Kyome
火星に住む犬です。 趣味でmacOS アプリを開発しています。
https://kyome.io
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away