链接过滤导致内存崩溃

时间:2013-10-29 14:58:21

标签: ios iphone memory uiimageview gpuimage

我们正在使用GPUImage和CIFIlter的组合创建多个自定义过滤器。我们过滤的图像大约是2048 X 2048像素。以下代码占用大约300MB的应用程序内存。我们需要将滤波器链接在一起以获得所需的效果,但图像的存储器占用空间永远不会被释放。有人可以建议吗?

    UIImage *filteredImage = [self getFilteredImage:initialImage Min:11 Gamma:1.09 Max:226 MinOut:46 MaxOut:208];
    filteredImage = [self getFilteredImage:filteredImage Min:34 Gamma:.91 Max:188 MinOut:12 MaxOut:220 forColor:@"red"];
    filteredImage = [self getFilteredImage:filteredImage Min:18 Gamma:.89 Max:209 MinOut:32 MaxOut:215 forColor:@"green"];
    filteredImage = [self getFilteredImage:filteredImage Min:9 Gamma:1.1 Max:216 MinOut:1 MaxOut:245 forColor:@"blue"];

    //Levels
    filteredImage = [self getFilteredImage:filteredImage Min:54 Gamma:1.28 Max:232 MinOut:44 MaxOut:179];
    filteredImage = [self getFilteredImage:filteredImage Min:15 Gamma:.92 Max:221 MinOut:39 MaxOut:211 forColor:@"red"];
    filteredImage = [self getFilteredImage:filteredImage Min:0 Gamma:.9 Max:244 MinOut:15 MaxOut:255 forColor:@"green"];
    filteredImage = [self getFilteredImage:filteredImage Min:0 Gamma:1 Max:248 MinOut:16 MaxOut:237 forColor:@"blue"];

+(UIImage*)getFilteredImage: (UIImage*)image Min:(float)min Gamma:(float)gamma Max:(float)max MinOut:(float)minOut MaxOut:(float)maxOut forColor: (NSString*) color
{
    GPUImagePicture *gpuImage = [[GPUImagePicture alloc] initWithImage:image];
    GPUImageLevelsFilter *levelsFilter = [[GPUImageLevelsFilter alloc] init];
    if ([color isEqualToString: @"red"])
    {
        [levelsFilter setRedMin:[self convertFloat:min] gamma:gamma max:[self convertFloat:max] minOut:[self convertFloat:minOut] maxOut:[self convertFloat:maxOut]];
    }else if([color isEqualToString: @"green"])
    {
        [levelsFilter setGreenMin:[self convertFloat:min] gamma:gamma max:[self convertFloat:max] minOut:[self convertFloat:minOut] maxOut:[self convertFloat:maxOut]];
    }
    else if([color isEqualToString: @"blue"])
    {
        [levelsFilter setBlueMin:[self convertFloat:min] gamma:gamma max:[self convertFloat:max] minOut:[self convertFloat:minOut] maxOut:[self convertFloat:maxOut]];
    }
    else
    {
        [levelsFilter setMin:[self convertFloat:min] gamma:gamma max:[self convertFloat:max] minOut:[self convertFloat:minOut] maxOut:[self convertFloat:maxOut]];
    }

    [gpuImage addTarget:levelsFilter];
    [gpuImage processImage];
    return [levelsFilter imageFromCurrentlyProcessedOutputWithOrientation:image.imageOrientation];
}

2 个答案:

答案 0 :(得分:2)

你真的不想像在这里一样在每一步创建新的图像。不仅从UIImage到GPUImage,再回到UIImage,由于中间图像的创建而耗费内存,由于需要将数据复制到GPU或从GPU复制数据,因此速度非常慢(通过Core Graphics的速度很慢)在两端)。

相反,你想尝试在一次通过中尽可能多地做,然后按顺序链过滤器。也没有必要分别设置红色,绿色和蓝色级别,这将减少第三级所需的通过次数(和中间图像)。

以下代码在功能上与上述代码相同:

GPUImagePicture *gpuImage = [[GPUImagePicture alloc] initWithImage:image];

GPUImageLevelsFilter *levelsFilter1 = [[GPUImageLevelsFilter alloc] init];
[levelsFilter1 setMin:[self convertFloat:11] gamma:1.09 max:[self convertFloat:226] minOut:[self convertFloat:46] maxOut:[self convertFloat:208]];

GPUImageLevelsFilter *levelsFilter2 = [[GPUImageLevelsFilter alloc] init];
[levelsFilter2 setRedMin:[self convertFloat:34] gamma:0.91 max:[self convertFloat:188] minOut:[self convertFloat:12] maxOut:[self convertFloat:220]];
[levelsFilter2 setGreenMin:[self convertFloat:18] gamma:0.89 max:[self convertFloat:209] minOut:[self convertFloat:32] maxOut:[self convertFloat:215]];
[levelsFilter2 setBlueMin:[self convertFloat:9] gamma:1.1 max:[self convertFloat:216] minOut:[self convertFloat:1] maxOut:[self convertFloat:245]];

GPUImageLevelsFilter *levelsFilter3 = [[GPUImageLevelsFilter alloc] init];
[levelsFilter3 setMin:[self convertFloat:54] gamma:1.28 max:[self convertFloat:232] minOut:[self convertFloat:44] maxOut:[self convertFloat:179]];

GPUImageLevelsFilter *levelsFilter4 = [[GPUImageLevelsFilter alloc] init];
[levelsFilter4 setRedMin:[self convertFloat:15] gamma:0.92 max:[self convertFloat:221] minOut:[self convertFloat:39] maxOut:[self convertFloat:211]];
[levelsFilter4 setGreenMin:[self convertFloat:0] gamma:0.9 max:[self convertFloat:244] minOut:[self convertFloat:15] maxOut:[self convertFloat:255]];
[levelsFilter4 setBlueMin:[self convertFloat:0] gamma:1 max:[self convertFloat:248] minOut:[self convertFloat:16] maxOut:[self convertFloat:237]];

[gpuImage addTarget:levelsFilter1];
[levelsFilter1 addTarget:levelsFilter2];
[levelsFilter2 addTarget:levelsFilter3];
[levelsFilter3 addTarget:levelsFilter4];
[levelsFilter4 prepareForImageCapture];
[gpuImage processImage];
return [levelsFilter4 imageFromCurrentlyProcessedOutputWithOrientation:image.imageOrientation];

但速度要快得多,而且会占用更少的内存。我在最后一个过滤器上放了一个-prepareForImageCapture,它可以在最后一个过滤器和输出UIImage之间进行直接内存映射。这进一步减少了内存使用量,并加快了图像处理速度。

如果可以的话,我会在这里重新思考一些色阶应用。你真的需要四次通过你的图像来平衡水平吗?有一个更好的方法可以在一次通过中执行此操作,即使它需要为此编写自定义过滤器。

此外,如果您要定期进行此类调整,我建议不要为每张图片分配新的关卡过滤器,而只是每次都将它们附加到不同的输入图片上。

另外,我可能会建议将-convertFloat方法设置为编译器定义的函数,如果只是为了清理代码一点。

答案 1 :(得分:0)

看看autoreleasepools:

https://developer.apple.com/library/ios/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

特别是关于“使用局部自动释放池块来减少峰值内存占用”的部分

我不打算在你的特定情况下发布一个完整的解决方案,但这绝对是“走的路”,以避免内存峰值