GPUImage - 使用NSMutableArray串行应用过滤器

时间:2014-05-21 18:42:07

标签: ios objective-c gpuimage

我正在尝试构建一个动态系统来串联应用多个GPUImage过滤器。

如果我静态定义所有过滤器,如下所示:

[sourceImage addTarget:filter1];
[filter1 addTarget:filter2];
[filter2 addTarget:filter3];

......等等,这很好。

由于我想拥有可变数量的过滤器,但这会变得很麻烦。我想我会尝试使用mutableArray并存储过滤器来执行此操作。不幸的是,我收到了错误:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?'

Researching this error已经表明问题在于过滤器不是很强大'再次引用,并且一旦迭代了数组,它们就会被破坏。

如果我在这个假设中是正确的,有没有办法重写这个以便引用没有被销毁?

这是我的类别实施:

@implementation UIImage (FilterEngine)

- (UIImage*)imageProcessedWithFilterEngine:(FilterProperties*)properties
{

    // Mutable array of filters, for dynamic iteration through only those filters which require applying
    NSMutableArray* filtersList = [NSMutableArray new];

    GPUImagePicture *source = [[GPUImagePicture alloc] initWithImage:self];

    GPUImageCustomFilterEngine* filterEngine;
    if (properties.lookupImageName)
    {
        filterEngine = [[GPUImageCustomFilterEngine alloc] initWithLookupImageName:properties.lookupImageName];
        [filtersList addObject:filterEngine];
    }

    GPUImageBrightnessFilter *brightnessFilter = [GPUImageBrightnessFilter new];
    if (properties.brightness != 0.0)
    {
        brightnessFilter.brightness = properties.brightness;
        [filtersList addObject:brightnessFilter];
    }

    GPUImageContrastFilter *contrastFilter = [GPUImageContrastFilter new];
    if (properties.contrast != 1.0)
    {
        contrastFilter.contrast = properties.contrast;
        [filtersList addObject:contrastFilter];
    }

    GPUImageSaturationFilter *saturationFilter = [GPUImageSaturationFilter new];
    if (properties.saturation != 1.0)
    {
        saturationFilter.saturation = properties.saturation;
        [filtersList addObject:saturationFilter];
    }

    if (filtersList.count > 0)
    {
        [source addTarget:filtersList.firstObject];
        for (int i = 0; i < filtersList.count - 1; i++)
        {
            [(id)[filtersList objectAtIndex:i] addTarget:[filtersList objectAtIndex:i + 1]];
        }

        [source addTarget:filtersList.lastObject];

        [(id)filtersList.lastObject useNextFrameForImageCapture];

        [source processImage];

        return [filtersList.lastObject imageFromCurrentFramebuffer];
    }
    else
        return self;
}

@end

2 个答案:

答案 0 :(得分:3)

要扩展我的评论,此处的问题似乎是

[source addTarget:filtersList.lastObject];

对于其余的逻辑,您可以通过将过滤器定位到下一个过滤器来适当地逐步执行和附加过滤器。但是,最后一行通过将源直接附加到链中的最后一个过滤器来扰乱排序。

如果最后一个过滤器只接受输入,那么您的输入将覆盖该输入。这将导致悬挂的过滤器链在您的源之后由双方向框架分叉(一个到现在不完整的过滤器链,一个直接到最后一个过滤器)。我可能没有恰当地解释这一点,因此我在这个断言中警告过帧缓冲的过度释放。

如果我可以做最后一次评论,那么在创建基于UIImage的GPUImagePicture时会有一些开销,所以如果你能找到一种方法,每次你需要为你的图像应用一个过滤器时都不需要创建它处理速度会快得多。同样,如果您可以保留可以重复使用的过滤器,则可以节省一些初始过滤器设置。这可能不适用于您的架构,但需要注意的事项。

答案 1 :(得分:1)

这就是我将GPUImageFilters链接起来的方式:

- (UIImage *)runFilterOnImage:(UIImage *)imageToFilter
{ 
        __block UIImage *filteredImage;

        GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:imageToFilter];

        [_filterChain enumerateObjectsUsingBlock:^(GPUImageFilter *filter, NSUInteger idx, BOOL *stop) {
            if (idx == 0) {
                [stillImageSource addTarget:filter];
            }

            if (idx < _filterChain.count - 1) {
                GPUImageFilter *nextFilter = [_filterChain objectAtIndex:idx + 1];
                [filter addTarget:nextFilter];
            }

            [filter useNextFrameForImageCapture];

            if (idx == _filterChain.count - 1) {
                [stillImageSource processImage];
                filteredImage = [filter imageFromCurrentFramebufferWithOrientation:imageToFilter.imageOrientation];
            }
        }];

    return filteredImage;

}

其中_filterChain是GPUImageFilter对象的数组