如何释放的iOS一CGImageRef(How do I release a CGImageRef

2019-06-17 22:02发布

我写此方法来计算平均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?

谢谢!

Answer 1:

你的内存问题从复制的数据结果,正如其他人说。 但这里的另一个想法:使用核芯显卡的优化像素插值计算平均值。

  1. 创建一个1x1的位图上下文。
  2. 设置插值质量中等(见下文)。
  3. 绘制缩小到正是这一个像素的图像。
  4. 阅读从上下文的缓冲区中的RGB值。
  5. (版本的上下文中,当然)。

这可能会导致更好的性能,因为核芯显卡是高度优化的,甚至可能使用GPU进行降尺度。

测试表明,中等质量似乎采取的颜色值的平均值进行插值像素。 这就是我们想在这里。

值得一试,至少。

编辑:OK,这个想法似乎太有趣不要尝试。 所以这里有一个例子项目显示的差异。 下面测量是用包含512 * 512的测试图像,但如果你愿意,你可以改变图像。

大约需要12.2毫秒通过在图像数据遍历所有像素计算平均值。 平局对一个象素的方法需要3毫秒,所以它的速度更快约4倍。 看来使用时产生相同的结果kCGInterpolationQualityMedium

我认为巨大的性能提升是从石英注意到,它并没有完全解压缩JPEG,但它只能使用DCT的较低频率的部分结果。 与小于0.5的比例合成JPEG压缩像素时是一个有趣的优化策略。 但我只是猜测这里。

有趣的是,使用方法时,的70%的时间花费在CGDataProviderCopyData和在象素数据的遍历只有30%。 这暗示了很多的JPEG压缩花费的时间。



Answer 2:

你没有自己的CGImageRef rawImageRef因为你使用它获得[image CGImage] 所以,你不需要将其释放。

但是,你自己rawPixelData ,因为你得到它使用CGDataProviderCopyData ,必须将其释放。

CGDataProviderCopyData

返回值:包含提供商的数据的副本的新的数据对象。 你是负责释放该对象。



Answer 3:

我相信你的问题是,在此声明:

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

你应该释放CGDataProviderCopyData的返回值。



Answer 4:

你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];
}


Answer 5:

CFDataRef abgrData = CGDataProviderCopyData(CGImageGetDataProvider(rawImageRef));

const UInt8 *rawPixelData = CFDataGetBytePtr(abgrData);

...

CFRelease(abgrData);


Answer 6:

另一个类似的问题以前问及有一些非常有用的答案,帮助你更好地理解:

CGImageRef内存泄漏



文章来源: How do I release a CGImageRef in iOS