正确的CIGaussianBlur作物

hoc*_*man 27 macos objective-c core-image

正如我注意到当CIGaussianBlur应用于图像时,图像的角落变得模糊,因此它看起来比原始的小.所以我发现我需要正确裁剪它以避免图像的透明边缘.但是如何计算我需要根据模糊量裁剪多少?


例:

原始图片:
在此输入图像描述

图像有50 inputRadius的CIGaussianBlur(蓝色是一切的背景):
在此输入图像描述

Eri*_*ary 52

以下面的代码为例......

CIContext *context = [CIContext contextWithOptions:nil];

CIImage *inputImage = [[CIImage alloc] initWithImage:image];

CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];

[filter setValue:inputImage forKey:kCIInputImageKey];

[filter setValue:[NSNumber numberWithFloat:5.0f] forKey:@"inputRadius"];

CIImage *result = [filter valueForKey:kCIOutputImageKey];

CGImageRef cgImage = [context createCGImage:result fromRect:[result extent]];

Run Code Online (Sandbox Code Playgroud)

这会生成您在上面提供的图像.但是,如果我改为使用原始图像rect来创建上下文中的CGImage,则生成的图像是所需的大小.

CGImageRef cgImage = [context createCGImage:result fromRect:[inputImage extent]];
Run Code Online (Sandbox Code Playgroud)


Mac*_*ser 24

有两个问题.第一个是模糊滤镜对输入图像边缘之外的像素进行采样.这些像素是透明的.这就是透明像素的来源.诀窍是在应用模糊滤镜之前扩展边缘.这可以通过钳位滤波器完成,例如:

CIFilter *affineClampFilter = [CIFilter filterWithName:@"CIAffineClamp"];

CGAffineTransform xform = CGAffineTransformMakeScale(1.0, 1.0);
[affineClampFilter setValue:[NSValue valueWithBytes:&xform
                                           objCType:@encode(CGAffineTransform)]
                     forKey:@"inputTransform"];
Run Code Online (Sandbox Code Playgroud)

此滤镜无限延伸边缘并消除透明度.下一步是应用模糊滤镜.

第二个问题有点奇怪.一些渲染器为模糊滤镜生成更大的输出图像,您必须通过某种偏移调整生成的CIImage的原点,例如:

CGImageRef cgImage = [context createCGImage:outputImage
                                   fromRect:CGRectOffset([inputImage extend],
                                                         offset, offset)];
Run Code Online (Sandbox Code Playgroud)

我的iPhone上的软件渲染器需要三倍的模糊半径作为偏移.同一iPhone上的硬件渲染器根本不需要任何偏移.也许你可以从输入和输出图像的大小差异中推断出偏移,但我没有尝试......

  • 这完美地工作。我只是想指出在您的示例中分配的 CGAffineTransform 如果是过滤器的默认值,因此您可以省略所有这些代码,或者只是调用 [affineClampFilter setDefaults] (3认同)

orj*_*orj 13

要获得具有硬边的图像的漂亮模糊版本,首先需要将CIAffineClamp应用于源图像,将其边缘扩展,然后您需要确保在生成输出图像时使用输入图像的范围.

代码如下:

CIContext *context = [CIContext contextWithOptions:nil];

UIImage *image = [UIImage imageNamed:@"Flower"];
CIImage *inputImage = [[CIImage alloc] initWithImage:image];

CIFilter *clampFilter = [CIFilter filterWithName:@"CIAffineClamp"];
[clampFilter setDefaults];
[clampFilter setValue:inputImage forKey:kCIInputImageKey];

CIFilter *blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
[blurFilter setValue:clampFilter.outputImage forKey:kCIInputImageKey];
[blurFilter setValue:@10.0f forKey:@"inputRadius"];

CIImage *result = [blurFilter valueForKey:kCIOutputImageKey];

CGImageRef cgImage = [context createCGImage:result fromRect:[inputImage extent]];
UIImage result = [[UIImage alloc] initWithCGImage:cgImage scale:image.scale orientation:UIImageOrientationUp];

CGImageRelease(cgImage);
Run Code Online (Sandbox Code Playgroud)

请注意,此代码已在iOS上测试过.对于OS X应该是类似的(用NSImage代替UIImage).


Ben*_*ild 9

我看到了一些解决方案,并想根据这里分享的一些想法推荐一个更现代的解决方案:

private lazy var coreImageContext = CIContext() // Re-use this.

func blurredImage(image: CIImage, radius: CGFloat) -> CGImage? {
    let blurredImage = image
        .clampedToExtent()
        .applyingFilter(
            "CIGaussianBlur",
            parameters: [
                kCIInputRadiusKey: radius,
            ]
        )
        .cropped(to: image.extent)

    return coreImageContext.createCGImage(blurredImage, from: blurredImage.extent)
}
Run Code Online (Sandbox Code Playgroud)

如果你需要UIImage之后,你当然可以像这样得到它:

let image = UIImage(cgImage: cgImage)
Run Code Online (Sandbox Code Playgroud)

...对于那些想知道的人,返回 a 的原因CGImage是(如Apple 文档中所述):

由于 Core Image 的坐标系统与 不匹配UIKit,这种过滤方法在UIImageView以“contentMode”显示时可能会产生意想不到的结果。确保用 a 支持它,CGImage以便它正确处理 contentMode。

如果你需要一个CIImage你可以返回它,但在这种情况下,如果你正在显示图像,你可能需要小心。


Dmi*_*rov 5

这对我有用:)

CIContext *context = [CIContext contextWithOptions:nil];
CIImage *inputImage = [[CIImage alloc] initWithImage:image];
CIFilter *blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
[blurFilter setDefaults];
[blurFilter setValue:inputImage forKey:@"inputImage"];
CGFloat blurLevel = 20.0f;          // Set blur level
[blurFilter setValue:[NSNumber numberWithFloat:blurLevel] forKey:@"inputRadius"];    // set value for blur level
CIImage *outputImage = [blurFilter valueForKey:@"outputImage"];
CGRect rect = inputImage.extent;    // Create Rect
rect.origin.x += blurLevel;         // and set custom params
rect.origin.y += blurLevel;         // 
rect.size.height -= blurLevel*2.0f; //
rect.size.width -= blurLevel*2.0f;  //
CGImageRef cgImage = [context createCGImage:outputImage fromRect:rect];    // Then apply new rect
imageView.image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
Run Code Online (Sandbox Code Playgroud)