CIFilter的guassianBlur和boxBlur正在缩小图像-如何避免调整大小?

9
我正在对一个NSView的内容进行快照,应用CIFilter,并将结果放回到视图中。如果CIFilter是一种模糊形式,例如CIBoxBlurCIGuassianBlur,则过滤后的结果略小于原始大小。由于我要反复这样做,结果会变得越来越小,我想避免这种情况。
尽管在稍微不同的上下文(Quartz Composer)中提到了这个问题here。苹果公司的FunHouse演示应用程序应用了Gaussian blur而没有使图像缩小,但我还没有弄清楚这个应用程序是如何做到的(它似乎使用了我不熟悉的OpenGL)。
这是代码的相关部分(位于NSView子类内部):
NSImage* background = [[NSImage alloc] initWithData:[self dataWithPDFInsideRect:[self bounds]]];

CIContext* context = [[NSGraphicsContext currentContext] CIContext];
CIImage* ciImage = [background ciImage];

 CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"
 keysAndValues: kCIInputImageKey, ciImage,
 @"inputRadius", [NSNumber numberWithFloat:10.0], nil];

CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGImageRef cgImage = [context createCGImage:result
                                   fromRect:[result extent]];

NSImage* newBackground = [[NSImage alloc] initWithCGImage:cgImage size:background.size];

如果我尝试使用像CISepiaTone这样的颜色变换滤镜,它并不会改变像素的位置,那么缩小就不会发生。
我想知道是否有快速修复方法,而不需要深入研究openGL
3个回答

18

实际上他们并没有缩小图像,而是扩大了它(我想是在所有边缘周围增加7个像素),默认的UIView“缩放到视图”会让它看起来像已经被缩小了。

使用以下方法裁剪您的CIImage:

CIImage *cropped=[output imageByCroppingToRect:CGRectMake(0, 0, view.bounds.size.width*scale, view.bounds.size.height*scale)];

其中view是您绘制的NSView的原始边界,而'scale'是您的[UIScreen mainScreen]比例。


谢谢,我会尝试实现这个。但是你是否混淆了OSX和iOS?这是一个OSX应用程序,因此严格使用NSViews而不是UIViews,也没有[UIScreen mainScreen]比例。据我所知,您是在说我应该取过滤后的CIImage - 它将比输入图像__大__,然后将其裁剪回输入图像的大小。但是我想要居中裁剪(即从每个边缘裁剪相同),所以裁剪原点不会是{0,0},更像{(output.width - view.bounds.size.width)/2, (output.height - view.bounds.size.height)/2}? - foundry
我已经实现了这个功能,现在它运行得非常好 - 谢谢!你是正确的,原点是{0,0},以保持结果在正确的位置。这是我使用的代码(省略了比例):CIImage *cropped=[output imageByCroppingToRect:CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.height)] - foundry
3
我认为更简单的方法就是这样做: CGImageRef cgImage = [context createCGImage:result fromRect:[**ciImage** extent]];) 因此,范围来自于原始图像而不是过滤器的输出。 - EarlyRiser
@EarlyRiser 你的建议很有帮助!谢谢! - KamyFC

16

在使用模糊效果之前,您可能需要将图像夹紧:

- (CIImage*)imageByClampingToExtent {
    CIFilter *clamp = [CIFilter filterWithName:@"CIAffineClamp"];
    [clamp setValue:[NSAffineTransform transform] forKey:@"inputTransform"];
    [clamp setValue:self forKey:@"inputImage"];
    return [clamp valueForKey:@"outputImage"];
}

先模糊,然后剪裁到原始范围。这样会得到非透明的边缘。


1
解决了半透明边缘的问题!顺便提一下,有一个标准函数 - (CIImage *)imageByClampingToExtent NS_AVAILABLE(10_10, 8_0); - Fyodor Volchyok
这是唯一对我有效的方法。图像现在具有像素化,并保持其正确的大小和视觉位置。 - user3344977

5

@BBC_Z的解决方案是正确的。

虽然我认为按照图像而不是视图裁剪更加优雅。
并且你可以切掉无用的模糊边缘:

// Crop transparent edges from blur
resultImage = [resultImage imageByCroppingToRect:(CGRect){
    .origin.x = blurRadius,
    .origin.y = blurRadius,
    .size.width = originalCIImage.extent.size.width - blurRadius*2,
    .size.height = originalCIImage.extent.size.height - blurRadius*2
}];

有人应该制作一个自定义的CIFilter,可以模糊输入图像并为方便起见处理所有这些内容。我想我会... - Nicolas Miari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接