Преобразуйте в шкалу полутонов - слишком медленный

Нет. Они испускают точно тот же самый IL.

Это - просто вопрос стиля.

var обладает преимуществом, которое помогает Вам изменить тип возврата функций, не изменяя другие части исходного кода. Например, измените тип возврата с IEnumerable<T> до List<T>. Однако это могло бы помочь представить ошибки.

5
задан Ilya Suzdalnitski 21 August 2009 в 09:46
поделиться

4 ответа

Способ узнать вашу проблему со скоростью - профилировать с помощью Shark. (В Xcode Run-> Start with Performance Tool-> Shark.) Однако в этом случае я достаточно уверен, что основными проблемами являются попиксельное malloc / free, арифметика с плавающей запятой и два вызова методов в внутренний цикл обработки.

Чтобы избежать malloc / free, вы хотите вместо этого сделать что-то вроде этого:

- (void) getColorForPixelX:(NSUInteger)x y:(NSUInteger)y pixel:(float[3])pixel
{ /* Write stuff to pixel[0], pixel[1], pixel[2] */ }

// To call:
float pixel[3];
for (each pixel)
{
    [self getColorForPixelX:x y:y pixel:pixel];
    // Do stuff
}

Второй вероятный источник замедления - использование чисел с плавающей запятой - или, скорее, стоимость преобразования в и с плавающей запятой. Для фильтра, который вы пишете, работать с целочисленной математикой просто - сложите значения целых пикселей и разделите на 255 * 3. (Между прочим, это довольно плохой способ преобразования в оттенки серого. См. http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale . )

Вызов методов происходит быстро, но все же довольно медленно по сравнению с базовой арифметикой фильтра. (Некоторые числа см. в этой статье .) Самый простой способ избавиться от вызовов методов - заменить их встроенными функциями.

3
ответ дан 18 December 2019 в 06:23
поделиться

Вы можете позволить Quartz выполнить преобразование оттенков серого за вас:

CGImageRef grayscaleCGImageFromCGImage(CGImageRef inputImage) {
    size_t width = CGImageGetWidth(inputImage);
    size_t height = CGImageGetHeight(inputImage);

    // Create a gray scale context and render the input image into that
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
    CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 
                             4*width, colorspace, kCGBitmapByteOrderDefault);
    CGContextDrawImage(context, CGRectMake(0,0, width,height), inputImage);

    // Get an image representation of the grayscale context which the input
    //    was rendered into.
    CGImageRef outputImage = CGBitmapContextCreateImage(context);

    // Cleanup
    CGContextRelease(context);
    CGColorSpaceRelease(colorspace);
    return (CGImageRef)[(id)outputImage autorelease];
}
13
ответ дан 18 December 2019 в 06:23
поделиться

Недавно мне пришлось решить ту же проблему, и я придумал следующий код (он также сохраняет альфа-канал):

@implementation UIImage (grayscale)

typedef enum {
    ALPHA = 0,
    BLUE = 1,
    GREEN = 2,
    RED = 3
} PIXELS;

- (UIImage *)convertToGrayscale {
    CGSize size = [self size];
    int width = size.width;
    int height = size.height;

    // the pixels will be painted to this array
    uint32_t *pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t));

    // clear the pixels so any transparency is preserved
    memset(pixels, 0, width * height * sizeof(uint32_t));

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // create a context with RGBA pixels
    CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, 
                                                 kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);

    // paint the bitmap to our context which will fill in the pixels array
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), [self CGImage]);

    for(int y = 0; y < height; y++) {
        for(int x = 0; x < width; x++) {
            uint8_t *rgbaPixel = (uint8_t *) &pixels[y * width + x];

            // convert to grayscale using recommended method: http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
            uint32_t gray = 0.3 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.11 * rgbaPixel[BLUE];

            // set the pixels to gray
            rgbaPixel[RED] = gray;
            rgbaPixel[GREEN] = gray;
            rgbaPixel[BLUE] = gray;
        }
    }

    // create a new CGImageRef from our context with the modified pixels
    CGImageRef image = CGBitmapContextCreateImage(context);

    // we're done with the context, color space, and pixels
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    free(pixels);

    // make a new UIImage to return
    UIImage *resultUIImage = [UIImage imageWithCGImage:image];

    // we're done with image now too
    CGImageRelease(image);

    return resultUIImage;
}

@end
8
ответ дан 18 December 2019 в 06:23
поделиться

Вы пробовали использовать режим наложения яркости? Белое изображение, смешанное с вашим оригиналом в этом режиме наложения, кажется, дает оттенки серого. Эти два, изображение переднего плана справа и фоновое изображение слева:

замещающий текст http://developer.apple.com/iphone/library/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/Art/both_images.jpg

смешанный с kCGBlendModeLuminosity приводит к следующему:

альтернативный текст http://developer.apple.com/iphone/library/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/Art/luminosity_image.jpg

Подробнее , см .: Рисование с помощью Quartz 2D: использование режимов наложения с изображениями

1
ответ дан 18 December 2019 в 06:23
поделиться
Другие вопросы по тегам:

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