2013-10-29 3 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]; 

아직까지 더 빨리, 그리고 훨씬 적은 메모리를 사용합니다. 마지막 필터와 출력 UIImage 사이의 직접 메모리 매핑을 가능하게하는 마지막 필터의 -prepareForImageCapture을 던졌습니다. 이렇게하면 메모리 사용이 줄어들고 이미지 처리가 빨라집니다.

가능한 경우 여기에서 색상 수준 적용 중 일부를 다시 생각해 보겠습니다. 레벨 균형을 맞추려면 이미지 위에 4 번 통과해야합니까? 이 경우 사용자 지정 필터를 작성해야하는 경우에도 단일 패스에서이 작업을 수행하는 것이 더 좋은 방법 일 수 있습니다.

또한 이러한 종류의 조정을 정기적으로 수행하려는 경우 각 이미지에 새로운 수준의 필터를 할당하지 말고 매번 다른 입력 사진에 첨부하는 것이 좋습니다.

코드를 조금만 정리하면 컴파일 된 함수 인 -convertFloat를 컴파일하는 것이 좋습니다.

관련 문제