【问题标题】:How do I perform a fast pixellation filter on an image?如何对图像执行快速像素化过滤器?
【发布时间】:2011-06-30 06:15:17
【问题描述】:

我的像素化图像处理算法有点问题。

我从一开始就将图像加载到unsigned char* 类型的数组中 之后,在需要时,我会修改这些数据并且必须更新图像。 此更新耗时过长。我就是这样做的:

CGDataProviderRef dataProvider = CGProviderCrateWithData(.....);
CGImageRef cgImage = CGImageCreate(....);
[imageView setImage:[UIImage imageWithCGImage:cgImage]]];

一切正常,但处理大图像非常慢。我尝试在后台线程上运行它,但没有帮助。

所以基本上,这需要很长时间。有谁知道如何改进它?

【问题讨论】:

  • 线程可能会影响您的性能,因为它是一种单核计算绑定的东西。不能说太多了。

标签: iphone ios image-processing


【解决方案1】:

正如其他人所建议的那样,您需要将这项工作从 CPU 转移到 GPU 上,以便在这些移动设备上获得任何不错的处理性能。

为此,我创建了an open source framework for iOS called GPUImage,这使得执行这种加速图像处理变得相对简单。它确实需要 OpenGL ES 2.0 支持,但过去几年销售的每一台 iOS 设备都有这个(统计数据显示,该领域的所有 iOS 设备中有 97% 支持)。

作为该框架的一部分,我捆绑的初始过滤器之一是像素化过滤器。 SimpleVideoFilter 示例应用程序展示了如何使用它,通过一个滑块来控制已处理图像中的像素宽度:

这个过滤器是片段着色器的结果,带有以下 GLSL 代码:

 varying highp vec2 textureCoordinate;
 uniform sampler2D inputImageTexture;
 uniform highp fractionalWidthOfPixel;

 void main()
 {
    highp vec2 sampleDivisor = vec2(fractionalWidthOfPixel);

    highp vec2 samplePos = textureCoordinate - mod(textureCoordinate, sampleDivisor);
    gl_FragColor = texture2D(inputImageTexture, samplePos );
 }

在我的基准测试中,像这样的基于 GPU 的过滤器在 iOS 上对图像和视频的同等 CPU 密集型处理例程的执行速度要快 6-24 倍。上面链接的框架应该可以相当容易地整合到应用程序中,并且源代码可以免费提供给您,您可以根据需要进行自定义。

【讨论】:

  • BL,关于这个历史悠久的经典答案:一个常见的需求是只对一个区域进行像素化。 (通常:(i) 一张脸 (ii) 车牌 (iii) T 恤或帽子上的徽标。)也许您可以包括如何仅对图像中的给定矩形进行像素化,干杯。
  • @JoeBlow - 有两种方法可以解决这个问题:使用原始未过滤图像渲染一个四边形,然后在使用上述过滤的地方渲染第二个更小的四边形,或者创建一个使用某种条件语句来限制过滤区域。前者会比后者快得多,但需要使用第二组顶点和纹理坐标进行第二次渲染。
  • 您知道,我有一个非常快速的问题(令人惊讶的是我一直无法搜索答案)。如果一个人只使用 GPUImage 中的一个过滤器,实际上可以只用那个类构建 GPUImage(即删除其他 120 多个过滤器类)吗?还是不切实际,或毫无意义?如果只使用一个过滤器,它似乎更有效。一如既往的感谢!
  • @JoeBlow - 您需要一些基类,并且一些过滤器类之间存在依赖关系,但如果您不需要它们,通常可以去掉一些其他的类。一些过滤器看起来很简单,但实际上其中包含多个过滤器,因此某些过滤器的依赖关系可能比您想象的要多。您还需要编辑核心项目本身,这可能会使您在我更新它时与存储库不同步。我知道有人在他们的项目中对代码进行了更极端的精简,甚至拆散了一些基类。
  • 一如既往的感谢!听起来,真的,这里的简短答案是 KISS 只坚持整个项目。再次感谢
【解决方案2】:

如何使用名为CIPixellateCore Image 过滤器? 这是我如何实现它的代码sn-p。您可以使用kCIInputScaleKey 来获得您想要的强度:

// initialize context and image
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *logo = [CIImage imageWithData:UIImagePNGRepresentation([UIImage imageNamed:@"test"])];

// set filter and properties
CIFilter *filter = [CIFilter filterWithName:@"CIPixellate"];
[filter setValue:logo forKey:kCIInputImageKey];
[filter setValue:[[CIVector alloc] initWithX:150 Y:150] forKey:kCIInputCenterKey]; // default: 150, 150
[filter setValue:[NSNumber numberWithDouble:100.0] forKey:kCIInputScaleKey]; // default: 8.0

// render image
CIImage *result = (CIImage *) [filter valueForKey:kCIOutputImageKey];
CGRect extent = result.extent;
CGImageRef cgImage = [context createCGImage:result fromRect:extent];

// result
UIImage *image = [[UIImage alloc] initWithCGImage:cgImage];

这是官方的Apple Filter TutorialList of available Filters

更新 #1

我刚刚写了一个在后台执行渲染工作的方法:

- (void) pixelateImage:(UIImage *) image withIntensity:(NSNumber *) intensity completionHander:(void (^)(UIImage *pixelatedImage)) handler {

    // async task
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // initialize context and image
        CIContext *context = [CIContext contextWithOptions:nil];
        CIImage *logo = [CIImage imageWithData:UIImagePNGRepresentation(image)];

        // set filter and properties
        CIFilter *filter = [CIFilter filterWithName:@"CIPixellate"];
        [filter setValue:logo forKey:kCIInputImageKey];
        [filter setValue:[[CIVector alloc] initWithX:150 Y:150] forKey:kCIInputCenterKey]; // default: 150, 150
        [filter setValue:intensity forKey:kCIInputScaleKey]; // default: 8.0

        // render image
        CIImage *result = (CIImage *) [filter valueForKey:kCIOutputImageKey];
        CGRect extent = result.extent;
        CGImageRef cgImage = [context createCGImage:result fromRect:extent];

        // result
        UIImage *image = [[UIImage alloc] initWithCGImage:cgImage];

        // dispatch to main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            handler(image);
        });
    });
}

这样称呼它:

[self pixelateImage:[UIImage imageNamed:@"test"] withIntensity:[NSNumber numberWithDouble:100.0] completionHander:^(UIImage *pixelatedImage) {
    self.logoImageView.image = pixelatedImage;
}];

【讨论】:

    【解决方案3】:

    iPhone 不是执行图像处理等计算密集型任务的好设备。如果您希望提高显示超高分辨率图像的性能——可能同时执行一些图像处理任务,请考虑使用CATiledLayer。它以平铺块的形式显示内容,因此您可以仅根据需要在单个图块上显示/处理内容数据。

    【讨论】:

    • 谢谢卢卡斯,这可能会派上用场。让我试试。
    【解决方案4】:

    将@Kai Burghardt 的答案转换为 Swift 3

    func pixelateImage(_ image: UIImage, withIntensity intensity: Int) -> UIImage {
    
        // initialize context and image
            let context = CIContext(options: nil)
            let logo = CIImage(data: UIImagePNGRepresentation(image)!)!
            // set filter and properties
            let filter = CIFilter(name: "CIPixellate")
            filter?.setValue(logo, forKey: kCIInputImageKey)
            filter?.setValue(CIVector(x:150,y:150), forKey: kCIInputCenterKey)
            filter?.setValue(intensity, forKey: kCIInputScaleKey)
            let result = filter?.value(forKey: kCIOutputImageKey) as! CIImage
            let extent = result.extent
            let cgImage = context.createCGImage(result, from: extent)
            // result
            let processedImage = UIImage(cgImage: cgImage!)
            return processedImage
    
    }
    

    将此代码称为

    self.myImageView.image =  pixelateImage(UIImage(named:"test"),100)
    

    【讨论】:

      【解决方案5】:

      我同意@Xorlev。我唯一希望的是(假设您使用大量浮点运算)您正在为 arm6 构建并使用 thumb isa。在这种情况下,不使用 -mthumb 选项进行编译,性能可能会提高。

      【讨论】:

      • 我正在为 armv6 和 armv7(标准)构建。将看看 thumb isa 和 -mthumb 的东西。谢谢!
      【解决方案6】:

      其实就这么简单。更高的输入比例键意味着更多的像素化。

      let filter = CIFilter(name: "CIPixellate")
      filter?.setValue(inputImage, forKey: kCIInputImageKey)
      filter?.setValue(30, forKey: kCIInputScaleKey)
      
      let pixellatedCIImage = filter?.outputImage
      

      结果是 CIImage,你可以使用 UIImage 转换它

      UIImage(ciImage: pixellatedCIImage)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-23
        • 2016-12-18
        • 2011-10-30
        • 2017-08-01
        • 2021-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多