2013-10-29 131 views
1

我們正在使用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

你真的不想要在每一步創造新的圖像,就像你在這裏做的一樣。不僅從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方法編譯器定義的函數,如果只是爲了清理代碼一點點。