查找 UIImage 的左边缘颜色

Posted

技术标签:

【中文标题】查找 UIImage 的左边缘颜色【英文标题】:Finding left edge colour of UIImage 【发布时间】:2014-06-24 09:43:50 【问题描述】:

我正在尝试将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 循环来实现。

【讨论】:

谢谢,。我正在尝试使用它,但它返回的颜色完全错误。除了左边之外,我要为所有边排除哪些循环?谢谢! 您需要确保传入缩放的图像。我建议你看看完整的 slcolorart 类,看看它是如何工作的。 谢谢,我浏览了文档和示例代码。颜色更好。但并不完美。有什么建议么?感谢您的所有帮助。 您可以发布您的示例图片吗? 我发现了问题 - 这与此处发布的问题无关。由于图像下载,代码有时会执行,有时不会执行。我需要找出它失败的原因。但是对于这个问题,我对答案感到很讽刺,因为它对我有很大帮助。我将在我的另一个问题上发布另一个问题。再次感谢您的帮助!

以上是关于查找 UIImage 的左边缘颜色的主要内容,如果未能解决你的问题,请参考以下文章

设置 UIImage 颜色

如何删除 UIImage 背景颜色并使其透明?

模板 UIImage 更改颜色 [重复]

如何计算 UIImage 的平均颜色?

检查 UIImage 是不是具有 alpha(透明)颜色的问题

截取UIImage指定大小区域