在iPhone中为UIImage应用模糊效果

时间:2010-08-30 10:49:03

标签: iphone image-processing

我正在使用以下代码根据滑块值为uiimage设置模糊效果。条子值范围从0,5,10,15,20。这种逻辑在模拟器中运行良好,但它在设备中崩溃。请告诉我这个逻辑中有什么错误,或者是否还有比这更好的逻辑。

我是这个目标的新手 - c。请帮我解决这个问题。

提前致谢.........

这是崩溃日志

Program received signal:  “EXC_BAD_ACCESS”.
(gdb) bt
#0  0x320d27c4 in CGSConvertABGR8888toRGBA8888 ()
#1  0x31fdb184 in argb32_image ()
#2  0x3126fb60 in ripl_Mark ()
#3  0x31272dd0 in ripl_BltImage ()
#4  0x312649c0 in RIPLayerBltImage ()
#5  0x3126954c in ripc_RenderImage ()
#6  0x3126be34 in ripc_DrawImage ()
#7  0x31fd5054 in CGContextDelegateDrawImage ()
#8  0x31fd4e78 in CGContextDrawImage ()
#9  0x31c8af38 in CA::Render::create_image_by_rendering ()
#10 0x31c8460c in CA::Render::create_image_from_image_data ()
#11 0x31c84498 in CA::Render::create_image ()
#12 0x31c84154 in CA::Render::copy_image ()
#13 0x31c8407c in CA::Render::prepare_image ()
#14 0x31c7e9a0 in CALayerPrepareCommit_ ()
#15 0x31c7e9d8 in CALayerPrepareCommit_ ()
#16 0x31c7e9d8 in CALayerPrepareCommit_ ()
#17 0x31c7e9d8 in CALayerPrepareCommit_ ()
#18 0x31c7e9d8 in CALayerPrepareCommit_ ()
#19 0x31c7e9d8 in CALayerPrepareCommit_ ()
#20 0x31c7e9d8 in CALayerPrepareCommit_ ()
#21 0x31c7e86c in CALayerPrepareCommit ()
#22 0x31c7bbd0 in CA::Context::commit_transaction ()
#23 0x31c7b7e0 in CA::Transaction::commit ()
#24 0x31c839e0 in CA::Transaction::observer_callback ()
#25 0x3223524a in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#26 0x32236da4 in __CFRunLoopDoObservers ()
#27 0x322382fc in __CFRunLoopRun ()
#28 0x321df0c2 in CFRunLoopRunSpecific ()
#29 0x321defd0 in CFRunLoopRunInMode ()
#30 0x3390ff90 in GSEventRunModal ()
#31 0x34b0ab48 in -[UIApplication _run] ()
#32 0x34b08fc0 in UIApplicationMain ()
#33 0x00002db2 in main (argc=1, argv=0x2ffff570) at   /Users/Desktop/SampleProject/Shared/main.m:14

这是调用方法:

 tempImgView.image = [self blurredCopyUsingGuassFactor:value andPixelRadius:value];

CGContextRef CreateARGBBitmapContext (CGImageRef inImage)
{
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;

    size_t pixelsWide = CGImageGetWidth(inImage);
    size_t pixelsHigh = CGImageGetHeight(inImage);
    bitmapBytesPerRow   = (pixelsWide * 4);
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);


    colorSpace = CGColorSpaceCreateDeviceRGB();
    if (colorSpace == NULL)
        return NULL;

    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL) 
        CGColorSpaceRelease( colorSpace );

    context = CGBitmapContextCreate (bitmapData,
                                     pixelsWide,
                                     pixelsHigh,
                                     8,    
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedFirst);
    if (context == NULL)
        free (bitmapData);

    CGColorSpaceRelease( colorSpace );

    return context;
}


CGImageRef CreateCGImageByBlurringImage(CGImageRef inImage, NSUInteger pixelRadius, NSUInteger gaussFactor)
{
    unsigned char *srcData, *destData, *finalData;

    CGContextRef context = CreateARGBBitmapContext(inImage);
    if (context == NULL) 
        return NULL;

    size_t width = CGBitmapContextGetWidth(context);
    size_t height = CGBitmapContextGetHeight(context);
    size_t bpr = CGBitmapContextGetBytesPerRow(context);
    size_t bpp = (CGBitmapContextGetBitsPerPixel(context) / 8);
    CGRect rect = {{0,0},{width,height}}; 

    CGContextDrawImage(context, rect, inImage); 

    // Now we can get a pointer to the image data associated with the bitmap
    // context.
    srcData = (unsigned char *)CGBitmapContextGetData (context);
    if (srcData != NULL)
    {

        size_t dataSize = bpr * height;
        finalData = malloc(dataSize);
        destData = malloc(dataSize);
        memcpy(finalData, srcData, dataSize);
        memcpy(destData, srcData, dataSize);

        int sums[gaussFactor];
        int i, x, y, k;
        int gauss_sum=0;
        int radius = pixelRadius * 2 + 1;
        int *gauss_fact = malloc(radius * sizeof(int));

        for (i = 0; i < pixelRadius; i++)
        {

            gauss_fact[i] = 1 + (gaussFactor*i);
            gauss_fact[radius - (i + 1)] = 1 + (gaussFactor * i);
            gauss_sum += (gauss_fact[i] + gauss_fact[radius - (i + 1)]);
        }
        gauss_fact[(radius - 1)/2] = 1 + (gaussFactor*pixelRadius);
        gauss_sum += gauss_fact[(radius-1)/2];

        unsigned char *p1, *p2, *p3;

        for ( y = 0; y < height; y++ ) 
        {
            for ( x = 0; x < width; x++ ) 
            {
                p1 = srcData + bpp * (y * width + x); 
                p2 = destData + bpp * (y * width + x);

                for (i=0; i < gaussFactor; i++)
                    sums[i] = 0;

                for(k=0;k<radius;k++)
                {
                    if ((y-((radius-1)>>1)+k) < height)
                        p1 = srcData + bpp * ( (y-((radius-1)>>1)+k) * width + x); 
                    else
                        p1 = srcData + bpp * (y * width + x);

                    for (i = 0; i < bpp; i++)
                        sums[i] += p1[i]*gauss_fact[k];

                }
                for (i=0; i < bpp; i++)
                    p2[i] = sums[i]/gauss_sum;
            }
        }
        for ( y = 0; y < height; y++ ) 
        {
            for ( x = 0; x < width; x++ ) 
            {
                p2 = destData + bpp * (y * width + x);
                p3 = finalData + bpp * (y * width + x);


                for (i=0; i < gaussFactor; i++)
                    sums[i] = 0;

                for(k=0;k<radius;k++)
                {
                    if ((x -((radius-1)>>1)+k) < width)
                        p1 = srcData + bpp * ( y * width + (x -((radius-1)>>1)+k)); 
                    else
                        p1 = srcData + bpp * (y * width + x);

                    for (i = 0; i < bpp; i++)
                        sums[i] += p2[i]*gauss_fact[k];

                }
                for (i=0; i < bpp; i++)
                {
                    p3[i] = sums[i]/gauss_sum;
                }
            }
        }
    }

    size_t bitmapByteCount = bpr * height;


    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, destData, bitmapByteCount, NULL);

    CGImageRef cgImage = CGImageCreate(width, height, CGBitmapContextGetBitsPerComponent(context),
                                           CGBitmapContextGetBitsPerPixel(context), CGBitmapContextGetBytesPerRow(context), CGBitmapContextGetColorSpace(context), CGBitmapContextGetBitmapInfo(context), 
                                       dataProvider, NULL, true, kCGRenderingIntentDefault);


CGDataProviderRelease(dataProvider);
CGContextRelease(context); 
if (destData)
    free(destData);
if (finalData)
    free(finalData);

return cgImage;
 }


- (UIImage *)blurredCopyUsingGuassFactor:(int)gaussFactor andPixelRadius:(int)pixelRadius
{
    CGImageRef retCGImage = CreateCGImageByBlurringImage(refImage.CGImage, pixelRadius, gaussFactor);
    UIImage *retUIImage = [UIImage imageWithCGImage:retCGImage];
    CGImageRelease(retCGImage);
    return retUIImage;

}

4 个答案:

答案 0 :(得分:3)

我认为使用像opencv这样的东西可以更快地实现你的目标。

这是使用opencv创建高斯模糊的概念验证:

- (UIImage *)gaussianBlurWithUIImage:(UIImage *)anImage {

// Create an IplImage from UIImage
IplImage *img_color = [self CreateIplImageFromUIImage:anImage];

//obtain a 4channel RGB reference from the above
IplImage *img = cvCreateImage(cvGetSize(img_color), IPL_DEPTH_8U, 4);

//release the source. we don't care any more about it
cvReleaseImage(&img_color);

//make the Blur
cvSmooth(img, img, CV_GAUSSIAN, 7, 7, 0, 0);

//return the resulting image
UIImage *retUIImage = [self UIImageFromIplImage:img];

//release any allocated memory
cvReleaseImage(&img);

return retUIImage;
}

答案 1 :(得分:1)

几乎肯定你正在访问释放的内存。我假设使用tempImgView.image选项@propertyretain。如果没有,您需要保留blurredCopyUsingGuassFactor的结果。

最简单的检查方法是运行构建和分析,并查看与调用retain几次相关的问题。

如果没有显示任何内容,请尝试打开僵尸

http://loufranco.com/blog/files/debugging-memory-iphone.html

这使得对象不能解除分配,但是如果在对它们调用dealloc之后向它们发送消息,则写入控制台。不幸的是,这对你对malloc和free的记忆没有帮助。

要确保的最后一件事是你不要通过超出malloced数据的界限来破坏堆。检查的一种方法是使用Enable Guard Malloc,然后按照检测堆腐败下的说明进行操作:

http://developer.apple.com/iphone/library/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html

最后,仅仅因为它在模拟器中没有崩溃并不意味着bug也不存在 - 它只是没有取消引用恰好指向未映射内存的坏指针。检测内存问题无法保证 - 你可能有内存错误但仍然无法获得EXC_BAD_ACCESS - 这并不意味着错误不存在。

答案 2 :(得分:0)

我找到了一个中间解决方案。问题是destData正在被释放。我不太了解Cocoa如何在引擎盖下工作以进一步诊断它。它接近底部:

CGDataProviderRelease(dataProvider);
CGContextRelease(context); 
if (destData)
    free(destData); // this line breaks things
if (finalData)
    free(finalData);

我怀疑cgImage是以某种方式懒散加载的?我不知道。如果你没有释放destData,一切正常。当然,除了你现在正在泄露记忆。

答案 3 :(得分:0)

如果您引用了代码的原始来源,那会更容易 - 这是(c)Jeff LaMarche

正如您将从讨论主题中看到的那样,答案是正确使用dataprovider回调,它会在正确的时间释放内存。