Поиск цвета левого края пользовательского интерфейса

#ios #objective-c #macos #uiview #uiimage

#iOS #objective-c #macos #uiview #uiimage

Вопрос:

Я пытаюсь установить UIView цвет фона на цвет цвета левого края UIImage. Я думаю, это позволит установить цвет фона на UIView фоне изображения довольно близко.

Я пробовал средний цвет, и иногда это работает не очень хорошо — мой цвет UIView обычно на несколько оттенков отличается или имеет неправильный оттенок от цвета фона изображения. Итак, я решил, что просмотр левого края UIImage должен дать нам достаточно точное представление о UIImage цвете фона.

Выполнив некоторый поиск и просмотрев вопросы SO — я нашел этот фрагмент кода, который делает именно то, что мне нужно. Однако это код для OS X, а не для iOS.

     - (NSColor*)findEdgeColor:(NSImage*)image imageColors:(NSCountedSet**)colors
{
    NSBitmapImageRep *imageRep = [[image representations] lastObject];

    if ( ![imageRep isKindOfClass:[NSBitmapImageRep class]] ) // sanity check
        return nil;

    NSInteger pixelsWide = [imageRep pixelsWide];
    NSInteger pixelsHigh = [imageRep pixelsHigh];

    NSCountedSet *imageColors = [[NSCountedSet alloc] initWithCapacity:pixelsWide * pixelsHigh];
    NSCountedSet *leftEdgeColors = [[NSCountedSet alloc] initWithCapacity:pixelsHigh];

    for ( NSUInteger x = 0; x < pixelsWide; x   )
    {
        for ( NSUInteger y = 0; y < pixelsHigh; y   )
        {
            NSColor *color = [imageRep colorAtX:x y:y];

            if ( x == 0 )
            {
                [leftEdgeColors addObject:color];
            }

            [imageColors addObject:color];
        }
    }

    *colors = imageColors;


    NSEnumerator *enumerator = [leftEdgeColors objectEnumerator];
    NSColor *curColor = nil;
    NSMutableArray *sortedColors = [NSMutableArray arrayWithCapacity:[leftEdgeColors count]];

    while ( (curColor = [enumerator nextObject]) != nil )
    {
        NSUInteger colorCount = [leftEdgeColors countForObject:curColor];

        NSInteger randomColorsThreshold = (NSInteger)(pixelsHigh * kColorThresholdMinimumPercentage);

        if ( colorCount <= randomColorsThreshold ) // prevent using random colors, threshold based on input image height
            continue;

        PCCountedColor *container = [[PCCountedColor alloc] initWithColor:curColor count:colorCount];

        [sortedColors addObject:container];
    }

    [sortedColors sortUsingSelector:@selector(compare:)];


    PCCountedColor *proposedEdgeColor = nil;

    if ( [sortedColors count] > 0 )
    {
        proposedEdgeColor = [sortedColors objectAtIndex:0];

        if ( [proposedEdgeColor.color pc_isBlackOrWhite] ) // want to choose color over black/white so we keep looking
        {
            for ( NSInteger i = 1; i < [sortedColors count]; i   )
            {
                PCCountedColor *nextProposedColor = [sortedColors objectAtIndex:i];

                if (((double)nextProposedColor.count / (double)proposedEdgeColor.count) > .3 ) // make sure the second choice color is 30% as common as the first choice
                {
                    if ( ![nextProposedColor.color pc_isBlackOrWhite] )
                    {
                        proposedEdgeColor = nextProposedColor;
                        break;
                    }
                }
                else
                {
                    // reached color threshold less than 40% of the original proposed edge color so bail
                    break;
                }
            }
        }
    }

    return proposedEdgeColor.color;
}
 

Кто-нибудь знает, как я могу сделать то же самое для iOS?

Ответ №1:

Как это сделано в https://github.com/lukaswelte/ColorArt

Вы можете сделать это с помощью:

 - (UIColor*)_findEdgeColor:(UIImage*)image imageColors:(NSArray**)colors {

CGImageRef imageRep = image.CGImage;

NSUInteger pixelRange = 32;
NSUInteger scale = 256 / pixelRange;
NSUInteger rawImageColors[pixelRange][pixelRange][pixelRange];
NSUInteger rawEdgeColors[pixelRange][pixelRange][pixelRange]; 
// Should probably just switch to calloc, but this doesn't show up in instruments
// So I guess it's fine
for(NSUInteger b = 0; b < pixelRange; b  ) {
    for(NSUInteger g = 0; g < pixelRange; g  ) {
        for(NSUInteger r = 0; r < pixelRange; r  ) {
            rawImageColors[r][g][b] = 0;
            rawEdgeColors[r][g][b] = 0;
        }
    }
}


NSInteger width = CGImageGetWidth(imageRep);// [imageRep pixelsWide];
NSInteger height = CGImageGetHeight(imageRep); //[imageRep pixelsHigh];

CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, 4 * width, cs, kCGImageAlphaNoneSkipLast);
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = height}, image.CGImage);
CGColorSpaceRelease(cs);
const RGBAPixel* pixels = (const RGBAPixel*)CGBitmapContextGetData(bmContext);
for (NSUInteger y = 0; y < height; y  )
{
    for (NSUInteger x = 0; x < width; x  )
    {
        const NSUInteger index = x   y * width;
        RGBAPixel pixel = pixels[index];
        Byte r = pixel.red / scale;
        Byte g = pixel.green / scale;
        Byte b = pixel.blue / scale;
        rawImageColors[r][g][b] = rawImageColors[r][g][b]   1;
        if(0 == x) {
            rawEdgeColors[r][g][b] = rawEdgeColors[r][g][b]   1;
        }
    }
}
CGContextRelease(bmContext);

NSMutableArray* imageColors = [NSMutableArray array];
NSMutableArray* edgeColors = [NSMutableArray array];

for(NSUInteger b = 0; b < pixelRange; b  ) {
    for(NSUInteger g = 0; g < pixelRange; g  ) {
        for(NSUInteger r = 0; r < pixelRange; r  ) {
            NSUInteger count = rawImageColors[r][g][b];
            if(count > _randomColorThreshold) {
                UIColor* color = [UIColor colorWithRed:r / (CGFloat)pixelRange green:g / (CGFloat)pixelRange blue:b / (CGFloat)pixelRange alpha:1];
                PCCountedColor* countedColor = [[PCCountedColor alloc] initWithColor:color count:count];
                [imageColors addObject:countedColor];
            }

            count = rawEdgeColors[r][g][b];
            if(count > _randomColorThreshold) {
                UIColor* color = [UIColor colorWithRed:r / (CGFloat)pixelRange green:g / (CGFloat)pixelRange blue:b / (CGFloat)pixelRange alpha:1];
                PCCountedColor* countedColor = [[PCCountedColor alloc] initWithColor:color count:count];
                [edgeColors addObject:countedColor];
            }
        }
    }
}

*colors = imageColors;

NSMutableArray* sortedColors = edgeColors;
[sortedColors sortUsingSelector:@selector(compare:)];

PCCountedColor *proposedEdgeColor = nil;

if ( [sortedColors count] > 0 )
{
    proposedEdgeColor = [sortedColors objectAtIndex:0];

    if ( [proposedEdgeColor.color pc_isBlackOrWhite] ) // want to choose color over black/white so we keep looking
    {
        for ( NSInteger i = 1; i < [sortedColors count]; i   )
        {
            PCCountedColor *nextProposedColor = [sortedColors objectAtIndex:i];

            if (((double)nextProposedColor.count / (double)proposedEdgeColor.count) > .4 ) // make sure the second choice color is 40% as common as the first choice
            {
                if ( ![nextProposedColor.color pc_isBlackOrWhite] )
                {
                    proposedEdgeColor = nextProposedColor;
                    break;
                }
            }
            else
            {
                // reached color threshold less than 40% of the original proposed edge color so bail
                break;
            }
        }
    }
}

return proposedEdgeColor.color;
}
 

Если вам нужен только левый край, вы можете добиться этого, просто исключив цикл for для других краев.

Комментарии:

1. Спасибо,. Я пытаюсь его использовать, но цвет, который он возвращает, совершенно неправильный. Какие циклы я исключаю для всех ребер, кроме левого? Спасибо!

2. Вы должны быть уверены, что передаете масштабированное изображение. я бы посоветовал вам ознакомиться с полным классом slcolorart, чтобы увидеть, как он работает.

3. Спасибо, я просмотрел документы и пример кода. цвет лучше. Но не идеально. Есть предложения? Ценю всю вашу помощь.

4. Не могли бы вы опубликовать свой образец изображения?

5. Я обнаружил проблему, которая не связана с опубликованным здесь вопросом. Код иногда выполняется, а иногда нет — из-за загрузки изображения. Мне нужно выяснить, почему он выходит из строя. Однако на этот вопрос я удовлетворен ответом, поскольку он мне очень помог. Я опубликую еще один вопрос по моей другой проблеме. Еще раз спасибо за вашу помощь!