我写此方法来计算平均R,G,图像的B值。 下面的方法采用一个UIImage作为输入,并返回包含输入图像的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尝试(而不是RUN)来分析,我得到以下警告在此行“未此时调用者所拥有的对象的引用计数错误减量”
在哪里,我应该怎么释放CGImageRef?
谢谢!
你的内存问题从复制的数据结果,正如其他人说。 但这里的另一个想法:使用核芯显卡的优化像素插值计算平均值。
- 创建一个1x1的位图上下文。
- 设置插值质量中等(见下文)。
- 绘制缩小到正是这一个像素的图像。
- 阅读从上下文的缓冲区中的RGB值。
- (版本的上下文中,当然)。
这可能会导致更好的性能,因为核芯显卡是高度优化的,甚至可能使用GPU进行降尺度。
测试表明,中等质量似乎采取的颜色值的平均值进行插值像素。 这就是我们想在这里。
值得一试,至少。
编辑:OK,这个想法似乎太有趣不要尝试。 所以这里有一个例子项目显示的差异。 下面测量是用包含512 * 512的测试图像,但如果你愿意,你可以改变图像。
大约需要12.2毫秒通过在图像数据遍历所有像素计算平均值。 平局对一个象素的方法需要3毫秒,所以它的速度更快约4倍。 看来使用时产生相同的结果kCGInterpolationQualityMedium
。
我认为巨大的性能提升是从石英注意到,它并没有完全解压缩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从文件加载图像上的伟大工程,而不是由相机的图像捕捉。 因为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内存泄漏