Применение эффекта размытия для UIImage в iPhone - PullRequest
2 голосов
/ 30 августа 2010

Я использую следующий код для установки эффекта размытия для изображения на основе значения слайдера.значение ленты колеблется от 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 ]

3 голосов
/ 18 июня 2011

Я думаю, что ваша цель может быть достигнута быстрее, используя что-то вроде 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 голос
/ 01 сентября 2010

Почти наверняка вы обращаетесь к освобожденной памяти.Я предполагаю, что tempImgView.image - это @property с использованием опции retain.Если нет, вам нужно сохранить результат blurredCopyUsingGuassFactor.

Самый простой способ проверить это запустить Build and Analyze и посмотреть на проблемы, связанные с вызовом retain слишком мало.

Если это ничего не показывает, попробуйте включить зомби

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

Это делает объект не освобожденным, но записывает в консоль, если сообщения отправляются им после вызова deallocна них.К сожалению, это не поможет с памятью, которую вы размещаете и освобождаете.

Последнее, на что нужно обратить внимание, это то, что вы не повредите кучу, выходя за пределы своих ошибочных данных.Один из способов проверки состоит в том, чтобы использовать Enable Guard Malloc, а затем следовать указаниям в разделе «Обнаружение повреждения кучи»:

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

Наконец, то, что в симуляторе не происходит сбой, не приводит кЭто означает, что ошибки тоже нет - просто не разыменовывается неверный указатель, который указывает на не отображенную память.Обнаружение проблем с памятью не гарантировано - у вас могут быть ошибки памяти, но вы все равно не получите EXC_BAD_ACCESS - это не значит, что ошибки нет.

0 голосов
/ 09 мая 2011

Было бы намного проще, если бы вы указали исходный код для своего кода - (c) Jeff LaMarche

Как вы увидите из цепочки обсуждений,Ответ - правильно использовать обратный вызов поставщика данных, который освобождает память в нужное время.

0 голосов
/ 27 февраля 2011

Я нашел промежуточное решение.Проблема в том, что destData освобождается.Я не знаю достаточно о том, как Какао работает под капотом, чтобы диагностировать это далее.Это около дна:

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

Я подозреваю, что cgImage каким-то образом загружается лениво?Я не знаю.Если вы не освобождаете destData, все работает нормально.За исключением, конечно, что сейчас у тебя утечка памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...