12

Вопрос по ios – UIImage стал нечетким, когда он был масштабирован. Почему? (IOS 5.0)

UIImage всегда становится нечетким, когда его масштабируют. Что я могу сделать, если сделать так, чтобы он сохранял четкость?

- (UIImage *)rescaleImageToSize:(CGSize)size {
    CGRect rect = CGRectMake(0.0, 0.0, size.width, size.height);
    UIGraphicsBeginImageContext(rect.size);
    [self drawInRect:rect];  // scales image to rect
    UIImage *resImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resImage;
}
4 ответа
5

Я пытался ответить @Dondragmer с помощью VImage

но качество результата было недостаточно хорошим (я уменьшал размер изображения с соотношением 1/10).

Это решение работает для меня, хотя:UImage 's drawInrect: сглаживает изображение

По сути, это просто говорит о том, что при отображении сетчатки необходимо создать графический контекст с параметром сетчатки:

UIGraphicsBeginImageContextWithOptions(size, NO, 2.0f);

Error: User Rate Limit Exceeded

от 
2

Попробуй поставить:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);

перед нанесением получить качественную интерполяцию.

Error: User Rate Limit Exceeded

от shuiyouren

Error: User Rate Limit Exceeded

от 
46

Прежде всего

Rounding

убедитесь, что вы округлили свой размер, прежде чем масштабировать.drawInRect: В этом случае изображение может быть размыто. Чтобы округлить до ближайшего целого числа:

size.width = truncf(size.width);
size.height = truncf(size.height);

Для определенных задач вы можете захотеть округлить (этаж) или округлить (потолок).

CILanczosScaleTransform not available

Тогда не обращайте внимания на мою предыдущую рекомендацию CILanczosScaleTransform. Хотя части Core Image доступны в iOS 5.0, масштабирование Lanczos недоступно. Если это когда-либо станет доступным, используйте это. Для людей, работающих на Mac OS, он доступен, используйте его.

vImage Scaling

Тем не менее, существует высококачественный алгоритм масштабирования, доступный вvImage, На следующих рисунках показано, как метод, использующий его (vImageScaledImage), сравнивается с различными вариантами интерполяции контекста. Также обратите внимание, как эти параметры ведут себя по-разному при разных уровнях масштабирования.

На этомдиаграммасохранилась самая строчная деталь: Scaling comparison on diagram

На этомфотография, сравните листья внизу слева: Scaling comparison on tree photograph

На этомфотографияСравните текстуры в правом нижнем углу: Scaling comparison on rock photograph

Не используйте его напиксель арт; это создает странные артефакты масштабирования: Scaling comparison on pixel art, showing scaling artifacts

Хотя это нанекоторые изображения имеет интересные эффекты округления: Scaling comparison on Space Invader

Performance

Не удивительно, что kCGImageInterpolationHigh - самая медленная стандартная опция интерполяции изображения. vImageScaledImage, как реализовано здесь, еще медленнее. Чтобы уменьшить фрактальное изображение до половины его первоначального размера, потребовалось 110% времени UIImageInterpolationHigh. Для сокращения до четверти потребовалось 340% времени.

Вы можете думать иначе, если вы запустите его в симуляторе; там это может быть намного быстрее, чем kCGImageInterpolationHigh. Предположительно, многоядерные оптимизации vImage дают ему относительное преимущество на рабочем столе.

Code
// Method: vImageScaledImage:(UIImage*) sourceImage withSize:(CGSize) destSize
// Returns even better scaling than drawing to a context with kCGInterpolationHigh.
// This employs the vImage routines in Accelerate.framework.
// For more information about vImage, see https://developer.apple.com/library/mac/#documentation/performance/Conceptual/vImage/Introduction/Introduction.html#//apple_ref/doc/uid/TP30001001-CH201-TPXREF101
// Large quantities of memory are manually allocated and (hopefully) freed here.  Test your application for leaks before and after using this method.
- (UIImage*) vImageScaledImage:(UIImage*) sourceImage withSize:(CGSize) destSize;
{
    UIImage *destImage = nil;

    if (sourceImage)
    {
        // First, convert the UIImage to an array of bytes, in the format expected by vImage.
        // Thanks: http://stackoverflow.com/a/1262893/1318452
        CGImageRef sourceRef = [sourceImage CGImage];
        NSUInteger sourceWidth = CGImageGetWidth(sourceRef);
        NSUInteger sourceHeight = CGImageGetHeight(sourceRef);
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        unsigned char *sourceData = (unsigned char*) calloc(sourceHeight * sourceWidth * 4, sizeof(unsigned char));
        NSUInteger bytesPerPixel = 4;
        NSUInteger sourceBytesPerRow = bytesPerPixel * sourceWidth;
        NSUInteger bitsPerComponent = 8;
        CGContextRef context = CGBitmapContextCreate(sourceData, sourceWidth, sourceHeight,
                                                     bitsPerComponent, sourceBytesPerRow, colorSpace,
                                                     kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
        CGContextDrawImage(context, CGRectMake(0, 0, sourceWidth, sourceHeight), sourceRef);
        CGContextRelease(context);

        // We now have the source data.  Construct a pixel array
        NSUInteger destWidth = (NSUInteger) destSize.width;
        NSUInteger destHeight = (NSUInteger) destSize.height;
        NSUInteger destBytesPerRow = bytesPerPixel * destWidth;
        unsigned char *destData = (unsigned char*) calloc(destHeight * destWidth * 4, sizeof(unsigned char));

        // Now create vImage structures for the two pixel arrays.
        // Thanks: https://github.com/dhoerl/PhotoScrollerNetwork
        vImage_Buffer src = {
            .data = sourceData,
            .height = sourceHeight,
            .width = sourceWidth,
            .rowBytes = sourceBytesPerRow
        };

        vImage_Buffer dest = {
            .data = destData,
            .height = destHeight,
            .width = destWidth,
            .rowBytes = destBytesPerRow
        };

        // Carry out the scaling.
        vImage_Error err = vImageScale_ARGB8888 (
                                                 &src,
                                                 &dest,
                                                 NULL,
                                                 kvImageHighQualityResampling 
                                                 );

        // The source bytes are no longer needed.
        free(sourceData);

        // Convert the destination bytes to a UIImage.
        CGContextRef destContext = CGBitmapContextCreate(destData, destWidth, destHeight,
                                                         bitsPerComponent, destBytesPerRow, colorSpace,
                                                         kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
        CGImageRef destRef = CGBitmapContextCreateImage(destContext);

        // Store the result.
        destImage = [UIImage imageWithCGImage:destRef];

        // Free up the remaining memory.
        CGImageRelease(destRef);

        CGColorSpaceRelease(colorSpace);
        CGContextRelease(destContext);

        // The destination bytes are no longer needed.
        free(destData);

        if (err != kvImageNoError)
        {
            NSString *errorReason = [NSString stringWithFormat:@"vImageScale returned error code %d", err];
            NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
                                       sourceImage, @"sourceImage", 
                                       [NSValue valueWithCGSize:destSize], @"destSize",
                                       nil];

            NSException *exception = [NSException exceptionWithName:@"HighQualityImageScalingFailureException" reason:errorReason userInfo:errorInfo];

            @throw exception;
        }
    }
    return destImage;
}

Error: User Rate Limit Exceededgithub.com/dhoerl/PhotoScrollerNetwork :-)

от 
0

В особом случае увеличения изображения,

and желая сохранить острые углы, вы хотите отключить интерполяцию изображения. Если ваше изображение - пиксельная графика, это то, что вы хотите. В большинстве других случаев это не так.

UIGraphicsBeginImageContext(rect.size);

// Turn off interpolation to keep the scaled image from being blurred.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);

[self drawInRect:rect];  // scales image to rect
UIImage *resImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Если вы уменьшаете масштаб, просто рисование с помощью kCGInterpolationHigh также не является наилучшим вариантом.It's good, but CILanczosScaleTransform немного острее.

Edit: Начиная с iOS 5.1, CILanczosScaleTransform недоступен. Смотрите мой другой ответ для высококачественной процедуры масштабирования, которую вы можете использовать.

Error: User Rate Limit Exceeded

от shuiyouren

Error: User Rate Limit Exceeded

от shuiyouren

Error: User Rate Limit Exceeded

от shuiyouren

Error: User Rate Limit Exceeded

от 

Error: User Rate Limit Exceeded

от 

Похожие вопросы