这是一个奇怪的问题–我什至不知道如何开始。

我正在使用CIFilter来模糊图像。这是代码的本质,实现为UIImage的类别:

- (void)imageByApplyingBlur:(CGFloat)radius completion:(void (^)(UIImage *))completion {

  // If no completion, then nothing to do
  if (completion == nil) {
    return;
  }

  // If no radius, self is the result
  if (radius == 0.0) {
    completion(self);
    return;
  }

  UIApplicationState appState = [UIApplication sharedApplication].applicationState;
  CIImage *imageToBlur = [CIImage imageWithCGImage:self.CGImage];
  CGFloat scale = [UIScreen mainScreen].scale;

  // Do the thread-safe CIImage blurring on a high-priority concurrent thread.
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

    NSDictionary *contextOptions = nil;

    // Always include the kCIContextPriorityRequestLow : @(YES) pair, because
    // otherwise, the foreground animation framerate suffers while blurring.
    if (appState == UIApplicationStateBackground) {
      contextOptions = @{
                         kCIContextPriorityRequestLow  : @(YES),
                         // If we're not active, force CIContext to use the CPU renderer
                         // CPU rendering should be allowed even in the background
                         kCIContextUseSoftwareRenderer : @(YES)
                         };
    } else {
      contextOptions = @{
                         kCIContextPriorityRequestLow  : @(YES),
                         };
    }

    CIContext *context = [CIContext contextWithOptions:contextOptions];

    CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [gaussianBlurFilter setValue:imageToBlur forKey:@"inputImage"];
    [gaussianBlurFilter setValue:@(radius) forKey:@"inputRadius"];

    CIImage *resultImage = [gaussianBlurFilter valueForKey:@"outputImage"];

    CGRect cropRect = {
      .origin.x = radius,
      .origin.y = radius,
      .size.width = (imageToBlur.extent.size.width - (2 * radius)),
      .size.height = (imageToBlur.extent.size.height - (2 * radius))
    };

    // Crop transparent edges from blur
    resultImage = [resultImage imageByCroppingToRect:cropRect];

    // Generate returnable UIImage (important to make the image "from" a CGImage, not a CIImage)
    CGImageRef resultCGImage = [context createCGImage:resultImage fromRect:resultImage.extent];
    UIImage *resultUIImage = [UIImage imageWithCGImage:resultCGImage
                                                 scale:scale
                                           orientation:UIImageOrientationUp];
    CGImageRelease(resultCGImage);

    // The completion block has to happen on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
      completion(resultUIImage);
    });
  });
}

大约90%的时间,这种方法都可以正常工作。但是,有时,它从不向回调块提交有效的图像,而且我看到了难以置信的错误日志。错误日志很长,因此我将等到问题结束将其复制粘贴。

一些注意事项:
  • 在并发调度队列上进行模糊处理之前,我先进行了同步处理。速度很慢,但我从未见过此类问题。难道代码中的某些内容不能同时在队列中发生?就在我的应用启动时,它使用此方法提交了两张要模糊的图像,这是我唯一发现该方法无法正常工作的情况。
  • This question talks about requirements for using CIFilter from multiple threads safely,但是据我所知,我已经满足了这些要求。从理论上讲,我可以为此移到串行队列中,但是我不明白为什么这样做一定有帮助。
  • 我得到的错误确实很奇怪–我对CoreImage在内部的工作方式不甚了解,但是看起来应该编译为在GPU上执行的代码某种程度上是无效的。但是只有一些时间?我真的很为难。

  • 那么,我的问题是怎么回事?而且,理想情况下,我该如何解决?

    以下是我没有图像时的相关日志输出:
    liblib:3:15: error: :unkown type or function name: 'mix'
    3:15: error: unkown type or function name: 'mix'
        return mix(y, z, step(0.0,x));
                  ^
        return mix(y, z, step(0.0,x));
                  ^
    lib:lib:1:16:6:: error : error: non-void function should return a value
    non-void function should return a value
    vec4 compare (vec4 x, vec4 y, vec4 z)
         ^
    vec4 compare (vec4 x, vec4 y, vec4 z)
         ^
    lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
        return tan(x);
               ^~~
               tan_
    lib:51:26: error: unkown type or function name: 'max'
        return vec4(s.rgb/max(s.a,0.00001), s.a);
                             ^
    lib:49:6: error: non-void function should return a value
    vec4 unpremultiply (vec4 s)
         ^
    lib:56:28: error: unkown type or function name: 'mix'
        s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                               ^
    lib:62:28: error: unkown type or function name: 'mix'
        s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                               ^
    filter:4:12: error: unkown type or function name: 'clamp'
      x = clamp(min(x, x.yzwx), 0.0, 1.0);
               ^
    filter:1:55: error: unkown type or function name: 'max'
    vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
                                                          ^
    filter:1:6: error: non-void function should return a value
    lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
        return tan(x);
    vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
         ^
               ^~~
               tan_
    filter:3:26: error: unkown type or function name: 'mix'
    lib:51:26: error: unkown type or function name: 'max'
      s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                             ^
        return vec4(s.rgb/max(s.a,0.00001), s.a);
                             ^
    lib:49:6: error: non-void function should return a value
    vec4 unpremultiply (vec4 s)
         ^
    lib:56:28: error: unkown type or function name: 'mix'
        s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                               ^
    lib:62:28: error: unkown type or function name: 'mix'
        s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                               ^
    lib:3:15: error: unkown type or function name: 'mix'
        return mix(y, z, step(0.0,x));
                  ^
    lib:1:6: error: non-void function should return a value
    vec4 compare (vec4 x, vec4 y, vec4 z)
         ^
    filter:4:12: error: unkown type or function name: 'clamp'
      x = clamp(min(x, x.yzwx), 0.0, 1.0);
               ^
    lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
    filter:1:    return tan(x);
    55:           ^~~
               tan_error
    : unkown type or function name: 'max'
    vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
                                                          ^
    libfilter::511::266::  errorerror: : unkown type or function name: 'max'
    non-void function should return a value
        return vec4(s.rgb/max(s.a,0.00001), s.a);
                             ^
    lib:49:vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }6
    :     ^
     error: non-void function should return a value
    vec4 unpremultiply (vec4 s)
         ^
    filter:3:26: error: unkown type or function name: 'mix'
    lib:56:28: error: unkown type or function name: 'mix'
      s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                             ^
        s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                               ^
    lib:62:28: error: unkown type or function name: 'mix'
        s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                               ^
    lib:3:15: error: unkown type or function name: 'mix'
        return mix(y, z, step(0.0,x));
                  ^
    filter:lib1:1:6::55: error : error: unkown type or function name: 'max'non-void function should return a value
    
    vec4 compare (vec4 x, vec4 y, vec4 z)
         ^
    vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
                                                          ^
    filter:1:6: error: non-void function should return a value
    vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
         ^
    filter:3:26: error: unkown type or function name: 'mix'
    lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
      s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));    return tan(x);
    
                             ^
               ^~~
               tan_
    filter:1:47: error: unkown type or function name: 'clamp'
    lib:51:26: errorvec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
                                                  ^
    filter:1:6: error: non-void function should return a value
    : unkown type or function name: 'max'
    vec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
         ^
        return vec4(s.rgb/max(s.a,0.00001), s.a);
                             ^
    lib:49:6: error: non-void function should return a value
    vec4 unpremultiply (vec4 s)
         ^
    lib:56:28: error: unkown type or function name: 'mix'
        s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                               ^
    lib:62:28: error: unkown type or function name: 'mix'
        s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                               ^
    filter:1:55: error: unkown type or function name: 'max'
    vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
                                                          ^
    filter:1:6: error: non-void function should return a value
    vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
         ^
    filter:3:26: error: unkown type or function name: 'mix'
      s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                             ^
    filter:1:47: error: unkown type or function name: 'clamp'
    vec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
                                                  ^
    filter:1:6: error: non-void function should return a value
    vec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
         ^
    ERROR - could not find uniform for argument 0
    ERROR - could not find uniform for argument 0
    ERROR - could not find uniform for argument 1
    ERROR - could not find uniform for argument 1
    ERROR - could not find uniform for argument 2
    ERROR - could not find uniform for argument 2
    ERROR - could not find uniform for argument 3
    ERROR - could not find uniform for argument 3
    

    最佳答案

    这与您的主要问题无关,但是有一种更好的方法来“从模糊中裁剪透明边缘”。试试这个:

    CGRect originalExtent = img.extent;
    img = [img imageByClampingToExtent:originalExtent];
    img = [img imageByApplyingFilter:@"CIGaussianBlur"
                              params:@{@"inputRadius" : @(radius)}];
    img = [imageByCroppingToRect:originalExtent]
    

    关于ios - CIFilter似乎在GPU上失败,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29593839/

    10-11 14:54