如何在iOS中释放CGImageRef

我正在写这个方法来计算图像的平均R,G,B值。 以下方法将UIImage作为input,并返回包含input图像的R,G,B值的数组。 我有一个问题:如何/我在哪里正确地释放CGImageRef?

-(NSArray *)getAverageRGBValuesFromImage:(UIImage *)image { CGImageRef rawImageRef = [image CGImage]; //This function returns the raw pixel values const UInt8 *rawPixelData = CFDataGetBytePtr(CGDataProviderCopyData(CGImageGetDataProvider(rawImageRef))); NSUInteger imageHeight = CGImageGetHeight(rawImageRef); NSUInteger imageWidth = CGImageGetWidth(rawImageRef); //Here I sort the R,G,B, values and get the average over the whole image int i = 0; unsigned int red = 0; unsigned int green = 0; unsigned int blue = 0; for (int column = 0; column< imageWidth; column++) { int r_temp = 0; int g_temp = 0; int b_temp = 0; for (int row = 0; row < imageHeight; row++) { i = (row * imageWidth + column)*4; r_temp += (unsigned int)rawPixelData[i]; g_temp += (unsigned int)rawPixelData[i+1]; b_temp += (unsigned int)rawPixelData[i+2]; } red += r_temp; green += g_temp; blue += b_temp; } NSNumber *averageRed = [NSNumber numberWithFloat:(1.0*red)/(imageHeight*imageWidth)]; NSNumber *averageGreen = [NSNumber numberWithFloat:(1.0*green)/(imageHeight*imageWidth)]; NSNumber *averageBlue = [NSNumber numberWithFloat:(1.0*blue)/(imageHeight*imageWidth)]; //Then I store the result in an array NSArray *result = [NSArray arrayWithObjects:averageRed,averageGreen,averageBlue, nil]; return result; } 

我尝试了两件事:选项1:我保持原样,但是经过几个周期(5+)之后,程序崩溃,出现“内存不足警告错误”

选项2:在方法返回之前,我添加一行CGImageRelease(rawImageRef)。 现在它在第二个周期后崩溃,我得到了传递给方法的UIImage的EXC_BAD_ACCESS错误。 当我尝试在Xcode中分析(而不是运行)时,我在这一行中得到以下警告:“调用者此时不拥有的对象的引用计数的错误递减”

在哪里以及如何释放CGImageRef?

谢谢!

正如其他人所说,你的记忆问题是由复制的数据产生的。 但是这里有另外一个想法:使用Core Graphics的优化像素插值来计算平均值。

  1. 创build一个1×1位图上下文。
  2. 将插值质量设置为中等(请参阅后面的内容)。
  3. 绘制您的图像缩小到正是这一个像素。
  4. 从上下文的缓冲区中读取RGB值。
  5. (当然,释放上下文。)

这可能会导致更好的性能,因为核心graphics高度优化,甚至可能使用GPU的缩减。

testing表明,中等质量似乎通过取颜色值的平均值来插入像素。 这就是我们想要的。

值得一试,至less。

编辑:好的,这个想法似乎太有趣了,不要尝试。 所以这里是一个示例项目,显示了不同之处。 下面的测量是使用包含的512x512testing图像进​​行的,但是您可以根据需要更改图像。

通过遍历图像数据中的所有像素来计算平均值大约需要12.2 ms。 绘制到一个像素的方法需要3毫秒,所以它大约快4倍。 使用kCGInterpolationQualityMedium时似乎产生相同的结果。

我认为巨大的性能增益是Quartz的一个结果,它注意到它不必完全解压缩JPEG,而是只能使用DCT的较低频率部分。 在合成小于0.5的JPEG压缩像素时,这是一个有趣的优化策略。 但我只是在这里猜测。

有趣的是,当使用你的方法时,70%的时间花在CGDataProviderCopyData而在像素数据遍历中只花了30%。 这提示了在JPEG解压缩中花费的大量时间。

像素迭代截图绘制到一个像素的截图

您不拥有CGImageRef rawImageRef因为您使用[image CGImage]获取它。 所以你不需要释放它。

但是,您拥有rawPixelData因为您使用CGDataProviderCopyData获取了它,并且必须释放它。

CGDataProviderCopyData

返回值:包含提供者数据副本的新数据对象。 你有责任释放这个对象。

我相信你的问题在这个声明中:

 const UInt8 *rawPixelData = CFDataGetBytePtr(CGDataProviderCopyData(CGImageGetDataProvider(rawImageRef))); 

您应该释放CGDataProviderCopyData的返回值。

您的mergedColor在从文件加载的图像上效果很好,但不适用于相机捕获的图像。 由于从捕获的示例缓冲区创build的上下文上的CGBitmapContextGetData()不返回位图。 我改变了你的代码如下。 它适用于任何图像,并且与代码一样快。

 - (UIColor *)mergedColor { CGImageRef rawImageRef = [self CGImage]; // scale image to an one pixel image uint8_t bitmapData[4]; int bitmapByteCount; int bitmapBytesPerRow; int width = 1; int height = 1; bitmapBytesPerRow = (width * 4); bitmapByteCount = (bitmapBytesPerRow * height); memset(bitmapData, 0, bitmapByteCount); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate (bitmapData,width,height,8,bitmapBytesPerRow, colorspace,kCGBitmapByteOrder32Little|kCGImageAlphaPremultipliedFirst); CGColorSpaceRelease(colorspace); CGContextSetBlendMode(context, kCGBlendModeCopy); CGContextSetInterpolationQuality(context, kCGInterpolationMedium); CGContextDrawImage(context, CGRectMake(0, 0, width, height), rawImageRef); CGContextRelease(context); return [UIColor colorWithRed:bitmapData[2] / 255.0f green:bitmapData[1] / 255.0f blue:bitmapData[0] / 255.0f alpha:1]; } 
 CFDataRef abgrData = CGDataProviderCopyData(CGImageGetDataProvider(rawImageRef)); const UInt8 *rawPixelData = CFDataGetBytePtr(abgrData); ... CFRelease(abgrData); 

另一个类似的问题先前被问过,并有一些真正有用的答案,以帮助您更好地理解:

CGImageRef内存泄漏