gpt4 book ai didi

ios - 在 iOS 上使用 Core Image 的内存高效方式?

转载 作者:IT王子 更新时间:2023-10-28 23:33:57 26 4
gpt4 key购买 nike

我在我的应用程序中使用 Core Image 过滤器,在运行 iOS 7 的 iPhone 5 设备上一切正常,但是当我在总内存仅为 512MB 的 iPhone 4s 上测试它时,应用程序崩溃了。

情况是这样,我从相机拍摄了 2 张图像,每张图像的分辨率为 2448x3264。在我的 iPhone 5 中,根据仪器,整个过程在峰值时占用 150MB。

instruments memory usage

但是,当我尝试在 iPhone 4s 上运行相同的代码时,即使整个内存使用量非常低(大约 8 MB),仪器也会一直给我内存不足的警告。这是下面的屏幕截图。

iphone 4s memory usage

这是代码,基本上,我从我的应用程序的文档文件夹中加载了两张图片,并连续应用了 2 个过滤器:

    CIImage *foreground = [[CIImage alloc] initWithContentsOfURL:foregroundURL];
CIImage *background = [[CIImage alloc] initWithContentsOfURL:backgroundURL];
CIFilter *softLightBlendFilter = [CIFilter filterWithName:@"CISoftLightBlendMode"];
[softLightBlendFilter setDefaults];
[softLightBlendFilter setValue:foreground forKey:kCIInputImageKey];
[softLightBlendFilter setValue:background forKey:kCIInputBackgroundImageKey];

foreground = [softLightBlendFilter outputImage];
background = nil;
softLightBlendFilter = nil;

CIFilter *gammaAdjustFilter = [CIFilter filterWithName:@"CIGammaAdjust"];
[gammaAdjustFilter setDefaults];
[gammaAdjustFilter setValue:foreground forKey:kCIInputImageKey];
[gammaAdjustFilter setValue:[NSNumber numberWithFloat:value] forKey:@"inputPower"];
foreground = [gammaAdjustFilter valueForKey:kCIOutputImageKey];

gammaAdjustFilter = nil;

CIContext *context = [CIContext contextWithOptions:nil];
CGRect extent = [foreground extent];
CGImageRef cgImage = [context createCGImage:foreground fromRect:extent];

UIImage *image = [UIImage imageWithCGImage:cgImage scale:1.0 orientation:imgOrientation];
CFRelease(cgImage);
foreground = nil;

return image;

应用在这一行崩溃:CGImageRef cgImage = [context createCGImage:foreground fromRect:extent];

有没有更节省内存的方法来处理这种情况,或者我在这里做错了什么?

非常感谢!

最佳答案

短版:

虽然在概念上看起来微不足道,但对于相关设备而言,这实际上是一项相当消耗内存的任务。

加长版:

考虑一下:2 张图像 * RGBA 各 8 位 * 2448 * 3264 ~= 64MB。然后 CoreImage 将需要另外约 32MB 用于过滤操作的输出。然后从 CIContextCGImage 可能会再消耗 32MB。我希望 UIImage 副本至少通过使用带有写时复制的 VM 映射图像来共享 CGImage 的内存表示,尽管您可能会为无论如何,双重使用,因为尽管没有消耗“真实”内存,它仍然计入映射的页面。

因此,至少,您正在使用 128MB(加上您的应用碰巧使用的任何其他内存)。对于像 4S 这样只有 512MB 开始的设备来说,这是一个相当大的 RAM。 IME,我会说这将是可能的。我希望它至少在某些时候可以工作,但听到它收到内存警告和内存压力终止,我并不感到惊讶。您需要确保 CIContext 和所有输入图像在制作 CGImage 之后,在制作 UIImage 来自 CGImage

一般来说,缩小图片尺寸会更容易。

在没有测试的情况下,假设 ARC,我提出以下作为潜在改进:

- (UIImage*)imageWithForeground: (NSURL*)foregroundURL background: (NSURL*)backgroundURL orientation:(UIImageOrientation)orientation value: (float)value
{
CIImage* holder = nil;
@autoreleasepool
{
CIImage *foreground = [[CIImage alloc] initWithContentsOfURL:foregroundURL];
CIImage *background = [[CIImage alloc] initWithContentsOfURL:backgroundURL];
CIFilter *softLightBlendFilter = [CIFilter filterWithName:@"CISoftLightBlendMode"];
[softLightBlendFilter setDefaults];
[softLightBlendFilter setValue:foreground forKey:kCIInputImageKey];
[softLightBlendFilter setValue:background forKey:kCIInputBackgroundImageKey];

holder = [softLightBlendFilter outputImage];
// This probably the peak usage moment -- I expect both source images as well as the output to be in memory.
}
// At this point, I expect the two source images to be flushed, leaving the one output image
@autoreleasepool
{
CIFilter *gammaAdjustFilter = [CIFilter filterWithName:@"CIGammaAdjust"];
[gammaAdjustFilter setDefaults];
[gammaAdjustFilter setValue:holder forKey:kCIInputImageKey];
[gammaAdjustFilter setValue:[NSNumber numberWithFloat:value] forKey:@"inputPower"];
holder = [gammaAdjustFilter outputImage];
// At this point, I expect us to have two images in memory, input and output
}
// Here we should be back down to just one image in memory
CGImageRef cgImage = NULL;

@autoreleasepool
{
CIContext *context = [CIContext contextWithOptions:nil];
CGRect extent = [holder extent];
cgImage = [context createCGImage: holder fromRect:extent];
// One would hope that CG and CI would be sharing memory via VM, but they probably aren't. So we probably have two images in memory at this point too
}
// Now I expect all the CIImages to have gone away, and for us to have one image in memory (just the CGImage)
UIImage *image = [UIImage imageWithCGImage:cgImage scale:1.0 orientation:orientation];
// I expect UIImage to almost certainly be sharing the image data with the CGImageRef via VM, but even if it's not, we only have two images in memory
CFRelease(cgImage);
// Now we should have only one image in memory, the one we're returning.
return image;
}

正如评论中所指出的,高水位线将是采用两张输入图像并创建一张输出图像的操作。无论如何,这总是需要 3 张图像在内存中。要从那里进一步降低高水位线,您必须在部分/平铺中制作图像或将它们缩小到更小的尺寸。

关于ios - 在 iOS 上使用 Core Image 的内存高效方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20761940/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com