web-dev-qa-db-ja.com

iOSでガウスぼかし効果をアニメーション化するにはどうすればよいですか?

IOS 7の全体的な感じとして、ぼかし効果を画面の特定の部分に適用してそれを難読化しますが、ぼかしをすぐに投げるだけではなく、それをアニメーション化してからアニメーション化したいので、ユーザーには、ぼかし効果が適用されているのがほとんど見えます。

まるでPhotoshopのように、ガウスぼかしの値を1度に0から10ではなく0から10に少しずつ変更しました。

私はこれに対していくつかの解決策を試しましたが、最も一般的な提案は、ぼかしのないビューの上にぼかしビューを単に配置してから、ぼかしビューのアルファ値を下げることです。

これは機能します大丈夫が、遷移がないため、あまりオーバーレイではありません。例:

enter image description here

そのような効果を達成するためのより良い方法は何でしょうか?私は GPUImage に精通していますが、それでそれを達成する方法はわかりません。

また、ぼかしのパーセンテージを制御できるので、ユーザーからインタラクティブに適用できると便利です。 (例:ユーザーが途中までドラッグした、ブラーが半分適用された、など)

25
user2005643

IOS 9以降では、視覚効果ビューの効果をアニメーション化できます。

[UIView animateWithDuration:0.3 animations: ^ {
    visualEffectView.effect = blurEffect;
} completion:nil];

これにより、ぼかし半径をアニメートするという期待される効果が得られます。


ぼやけていないビュー->ぼやけているビューからクロスフェードをアニメートすると、十分に楽しいと思います。ぼかしていないビューの上にあるぼかしビューの表示をアニメーション化する必要があります。

blurViewがぼかし効果を含むビューであると仮定しましょう。

アニメーション化された遷移を達成する方法の2つの例を次に示します。

[UIView transitionWithView:self.view duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations: ^ {
    [self.view addSubview:blurView];
} completion:nil];

ここでは、blurViewがすでに設定されていると想定し、アニメーションのサブビューとして追加を移行します。

別の方法でこれを実現することもできます。

blurView.alpha = 0.0f;
[UIView animateWithDuration:0.3 animations: ^ {
    blurView.alpha = 1.0f;
} completion:nil];

ここでは、ぼかしビューを透明にして、その外観をアニメーション化します。このメソッドを使用してもhiddenでは機能しないため、alphaプロパティを使用する必要があることに注意してください。


インタラクティブにぼかしの量を制御したい場合は、次の例をご覧ください。

まず、ぼかしたいビューの画像を作成します。

UIGraphicsBeginImageContextWithOptions(nonBlurredView.bounds.size, NO, self.view.window.screen.scale);
[nonBlurredView drawViewHierarchyInRect:nonBlurredView.bounds afterScreenUpdates:NO];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();

この画像を保管してください。ビューが変更された場合にのみ、同様の方法で再描画します。それ以外の場合は、階層の描画にコストがかかるため、この画像を再利用する必要があります。

ここで、ぼかす必要がある場合は、次のコードを使用します。

CIImage *imageToBlur = [CIImage imageWithCGImage:snapshotImage.CGImage];    
CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"]; 
[gaussianBlurFilter setValue:imageToBlur forKey: @"inputImage"]; 
[gaussianBlurFilter setValue:@10 forKey: @"inputRadius"]; //Here you input the blur radius - the larger, the 
CIImage *resultImage = [gaussianBlurFilter valueForKey: @"outputImage"]; 
UIImage *endImage = [[UIImage alloc] initWithCIImage:resultImage];

inputRadius入力は、実行されるブラーの量を設定します。これをアニメートすると、インタラクティブな感覚を実現できます。

ただし、前者の方法の方がはるかに簡単で、ユーザーにとっても気分が良いと思います。

44
Leo Natan

これはOS Xでは簡単で、1つのビューがその背後のビューにエフェクトをCIFilterでき、プロセッサが強力で高速です。ただし、iOSではビュー合成フィルターがなく、ぼかしにはしばらく時間がかかります。アニメーションのフレームと同じくらい速く、ライブで繰り返し行うことはできません。したがって、何らかの形の妥協が必要です。

ただし、ぼかしたいことを事前に十分に理解している場合は、ぼかしのグラデーションを使用して一連の画像を準備できます(ぼかしなし、少しぼかし、少しぼかしなど)。次に、画像を組み立てて、アニメーション化されたUIImageViewの「フレーム」として「再生」します。

しかし、それは私が実際に助言することではありません。私がすることは、ぼかし画像とぼかしのない画像を準備し、CIDissolveTransitionを使用して、ぼかしのない画像からぼかし画像にディゾルブすることです。いいえ、ぼかしを徐々に適用するのと同じではありませんが、計算コストが低く、ツールボックスで最高の「ディゾルブ」エフェクトです。

6
matt

私は、可変ぼかし半径とフレームレート( MSLiveBlur )でライブぼかしにGPUImageを使用する小さなプロジェクトを開発しました-これはまさに必要なもののように聞こえます。

サンプルアプリには、質問で述べたように、ユーザーアクションに応じてぼかしレベルを増減するスライダーがあります。ユーザーの操作なしでアニメーション化したい場合は、最終値に達するまでぼかし半径をゆっくりと増加させるタイマーを作成できます。ただし、このソリューションではCoreAnimationを使用できません。

[[MSLiveBlurView sharedInstance] setBlurInterval:0.2];
[[MSLiveBlurView sharedInstance] blurRect:someView.frame];

// Count x from 0 to your final radius
[MSLiveBlurView sharedInstance].blurRadius = x;
3
michaels

コーディングの問題に対する既製のソリューションを提案することはめったにありません。ただし、この場合は LiveFrost をお勧めします。これは、人気のあるiOS 7ガウスぼかし効果の複製にのみ焦点を当てた、本当に堅固なUIViewサブクラスです。

また、このクラスの設計に関する決定については、著者のブログを読むことをお勧めします。私はiOS 7のリリース以来、このトピックについて具体的に多くの研究を行ってきましたが、このコードについて文字通りゼロの苦情を抱えています。

そのままの状態でぼかしアニメーションも付いています!頑張って :)

3
Sam

これは、事前計算された画像でぼかしをアニメーション化するために使用できる関数です。あなたはGPUImageに精通していると言ったので、それを使用しました(ただし、単純なぼかしアルゴリズムでも動作します)。

これにより、CPUを1〜2%のコストでリアルブラーリアルタイムでアニメーション化できます。

// configuration
let imageCount: Int = 10
let blurMax: Float = 40.0
// keep images in memory
var currentIdx: Int = 0
var imgs: [UIImage] = []

// func that create the precomputed images with GPUImage (call it in the viewDidLoad for example)
func initBlur() {
    let blur = GaussianBlur()
    let myImage: UIImage = UIImage(named: "your_image")!
    let pictureInput = PictureInput(image: myImage)
    let pictureOutput = PictureOutput()
    pictureOutput.onlyCaptureNextFrame = false

    pictureOutput.imageAvailableCallback = { image in
        self.imgs.append(image)
    }

    pictureInput --> blur --> pictureOutput

    for i in 0...imageCount {
        blur.blurRadiusInPixels = (Float(i) / Float(imageCount)) * blurMax
        pictureInput.processImage(synchronously: true)
    }
}

// function that return the correct image from the image set with a blur percentage from a value between 0 and 1 where 0 = no blur and 1 full blurred.
func getBlurredImage(value: Float) -> UIImage? {
    // return nil if there isn't precompiled images
    if imgs.count == 0 {
        return nil
    }

    // get the desired blurred image index
    let idx = Int(value * Float(imageCount - 1))
    // if the index changed, check the correctness of the index
    if currentIdx != idx {
        if idx < 0 {
            currentIdx = 0
        }
        else if idx >= imgs.count {
            currentIdx = imageCount - 1
        }
        else {
            currentIdx = idx
        }
    }
    return imgs[currentIdx]
}

それだけです。次に、たとえばタイマーを使用したり、scrollViewDidScroll関数で使用したりできます。

imageView.image = getBlurredImage(value: yOffset / height)
1
Anthony