簡體   English   中英

如何在iOS中設置/輸出高斯模糊效果?

[英]How do I animate in/out a gaussian blur effect in iOS?

對於整個iOS 7的感覺,我想將模糊效果應用到屏幕的特定部分以對其進行模糊處理,但我不想立即投射模糊,我想要將其設置為動畫並將其設置為動畫用戶幾乎看到應用的模糊效果。

幾乎就像在Photoshop中一樣,你將高斯模糊值從0改為10,而不是一次性改為0到10。

我已經嘗試了一些解決方案,最流行的建議是簡單地將模糊視圖放在非模糊視圖的頂部,然后降低模糊視圖的alpha值。

沒關系 ,但不是很令人愉悅,因為沒有過渡,它只是一個疊加。 例:

在此輸入圖像描述

什么是實現這種效果的更好方法? 我熟悉GPUImage ,但不知道如何用它完成它。

如果我可以控制它的模糊百分比也很好,所以它可以從用戶交互應用。 (例如:用戶拖動中途,模糊應用一半等)

使用iOS 9及更高版本,您可以為視覺效果視圖設置動畫效果:

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

這將實現動畫模糊半徑的預期效果。


我認為如果你從非模糊視圖動畫交叉淡化 - >模糊視圖,它將是令人愉快的。 您需要在非模糊視圖的頂部為模糊視圖的顯示設置動畫。

我們假設blurView是包含模糊效果的視圖。

以下是如何完成動畫過渡的兩個示例:

[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輸入用於設置執行的模糊量。 如果你動畫這個,你將獲得互動的感覺。

但我仍然認為前一種方法更容易,並且對用戶來說感覺很好。

這在OS X上很容易,其中一個視圖可以對其后面的視圖產生影響,並且處理器功能強大且速度快。 但是,在iOS上,沒有視圖合成濾鏡,模糊需要一些時間:你不能像動畫的幀一樣快速地重復,實時。 因此需要某種形式的妥協。

但是,如果您事先知道想要模糊的是什么,則可以使用模糊漸變來准備一系列圖像:沒有模糊,有點模糊,有點模糊,等等。 然后組裝圖像並“播放”它們作為動畫UIImageView的“幀”。

然而,這不是我實際建議的。 我要做的是准備模糊圖像和非模糊圖像,並使用CIDissolveTransition從非模糊圖像溶解到模糊圖像。 不,它與逐漸應用模糊不同,但它在計算上很便宜,並且是工具箱中最好的“溶解”效果。

我很少建議現成的編碼問題解決方案。 但是,在這種情況下,我會全心全意地推薦LiveFrost 它是一個非常可靠的UIView子類,專門用於復制流行的iOS 7高斯模糊效果。

我還鼓勵您閱讀作者的博客,了解他對本課程的設計決策。 自從iOS 7發布以來,我已經在這個主題上做了很多研究,而且我對這段代碼實際上是ZERO COMPLAINTS。

它甚至還有開箱即用的模糊動畫! 祝你好運 :)

我開發了一個小項目,它使用GPUImage進行實時模糊,具有可變模糊半徑和幀速率( MSLiveBlur ) - 這聽起來就像你需要的那樣。

在示例應用程序中,我有一個滑塊可以增加/減少模糊級別以響應用戶操作,正如您在問題中提到的那樣。 如果您想在沒有用戶交互的情況下為其設置動畫,您可以制作一個計時器,緩慢增加模糊半徑,直到達到最終值。 但是,您無法將CoreAnimation與此解決方案一起使用。

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

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

這是一個可用於使用預先計算的圖像為模糊設置動畫的功能。 你說你熟悉GPUImage所以我用它(但它也適用於簡單的模糊算法)。

有了這個,你可以動畫實時 真實模糊用1-2%的CPU的成本

// 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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM