W.K.S
W.K.S

Reputation: 10095

iOS: How can I determine the most frequenct colour in a CGRect within a UIView?

I'd like to implement a method which, given a CGRect within a UIView, returns the most used colour in that rect.

I've read answers to similar questions and I've gone through the Apple documentation to understand the code listed in those answers and the end result is a huge headache.

I'd appreciate it if someone could explain how to do this.

UPDATE

I've managed to create a working function by extending the colorAtPixel method demonstrated in rojkarc's link. I'm pretty sure this is not as efficient as it could. If anyone has suggestions for improving it, I'd be really grateful.

- (UIColor *) dominantColorInRect:(CGRect)rect
{
    UIColor * dominantColor = nil;
    NSMutableDictionary * dictionary = [[NSMutableDictionary alloc] init];

    int bytesPerPixel = 4;
    int bytesPerRow = bytesPerPixel * 1;
    NSUInteger bitsPerComponent = 8;
    unsigned char pixelData[4] = { 0, 0, 0, 0 };

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixelData, 1, 1, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);

    for (int x = rect.origin.x; x <= rect.size.width; x++) {
        for (int y = 0; y <= rect.size.height; y++) {

            context = CGBitmapContextCreate(pixelData, 1, 1, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);

            CGContextTranslateCTM(context, -x, -y);

            [self.layer renderInContext:context];

            CGContextRelease(context);

            UIColor *color = [UIColor colorWithRed:pixelData[0]/255.0 green:pixelData[1]/255.0 blue:pixelData[2]/255.0 alpha:pixelData[3]/255.0];

            if (color) {

                NSInteger count = [[dictionary objectForKey:color] integerValue];
                count++;
                [dictionary setObject:[NSNumber numberWithInt:count] forKey:color];
            }
        }
    }


    CGColorSpaceRelease(colorSpace);

    int highestFrequency = 0;
    for (id color in dictionary) {
        NSInteger count = [[dictionary objectForKey:color] integerValue];
        //NSInteger count = [object[1] integerValue];
        if (count > highestFrequency) {
            highestFrequency = count;
            dominantColor = color;
        }
    }

    return dominantColor;
}

Upvotes: 3

Views: 841

Answers (1)

Balazs Nemeth
Balazs Nemeth

Reputation: 2332

The following algorithm:

  1. create a png image from the UIView inside the rect (code see below)
  2. You have to iterate through the image (vertical and horisontal)
  3. You have to create a colour histogram:

To create a color histogram, you have to get the colour of a pixel in a given location (like here:http://www.markj.net/iphone-uiimage-pixel-color/) And than you have to count (and collect) the frequency of a given color.

Create image:

if(UIGraphicsBeginImageContextWithOptions != NULL){
                UIGraphicsBeginImageContextWithOptions(self.view.layer.frame.size, NO, 0.0);
            }else {
                UIGraphicsBeginImageContext(self.view.layer.frame.size);
            }
            [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
            img = UIGraphicsGetImageFromCurrentImageContext();
            size_t imageSize = CGImageGetBytesPerRow(img.CGImage) * CGImageGetHeight(img.CGImage);
            NSLog(@"imageSize: %zu",(imageSize/(1024*1024)));
            UIGraphicsEndImageContext();

Create histogram: Google it, a lot of pseudocode/ objective-C code is available.

Upvotes: 2

Related Questions