2012-12-04 6 views
24

Sto cercando di ottenere il colore meno utilizzato e il colore più utilizzato dalle copertine degli album dei file MP3 per un'applicazione di riproduzione musicale. Ho bisogno che i colori facciano effetto come il nuovo itunes 11. Dove il colore di sfondo del menu è il colore più utilizzato, e il colore meno utilizzato è il colore per le etichette delle canzoni e il nome dell'artista. Sto usandoObjective-c - Come ottenere il minimo utilizzo e il colore più utilizzato in un'immagine

`- (UIColor*) getPixelColorAtLocation:(CGPoint)point { 
    UIColor* color = nil; 
    CGImageRef inImage = self.image.CGImage; 
    // Create off screen bitmap context to draw the image into. Format ARGB is 4 bytes for each pixel: Alpa, Red, Green, Blue 
    CGContextRef cgctx = [self createARGBBitmapContextFromImage:inImage]; 
    if (cgctx == NULL) { return nil; /* error */ } 

    size_t w = CGImageGetWidth(inImage); 
    size_t h = CGImageGetHeight(inImage); 
    CGRect rect = {{0,0},{w,h}}; 

    // Draw the image to the bitmap context. Once we draw, the memory 
    // allocated for the context for rendering will then contain the 
    // raw image data in the specified color space. 
    CGContextDrawImage(cgctx, rect, inImage); 

    // Now we can get a pointer to the image data associated with the bitmap 
    // context. 
    unsigned char* data = CGBitmapContextGetData (cgctx); 
    if (data != NULL) { 
     //offset locates the pixel in the data from x,y. 
     //4 for 4 bytes of data per pixel, w is width of one row of data. 
     int offset = 4*((w*round(point.y))+round(point.x)); 
     int alpha = data[offset]; 
     int red = data[offset+1]; 
     int green = data[offset+2]; 
     int blue = data[offset+3]; 
     NSLog(@"offset: %i colors: RGB A %i %i %i %i",offset,red,green,blue,alpha); 
     color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)]; 
    } 

    // When finished, release the context 
    CGContextRelease(cgctx); 
    // Free image data memory for the context 
    if (data) { free(data); } 

    return color; 
} 

- (CGContextRef) createARGBBitmapContextFromImage:(CGImageRef) inImage { 

    CGContextRef context = NULL; 
    CGColorSpaceRef colorSpace; 
    void *   bitmapData; 
    int    bitmapByteCount; 
    int    bitmapBytesPerRow; 

    // Get image width, height. We'll use the entire image. 
    size_t pixelsWide = CGImageGetWidth(inImage); 
    size_t pixelsHigh = CGImageGetHeight(inImage); 

    // Declare the number of bytes per row. Each pixel in the bitmap in this 
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and 
    // alpha. 
    bitmapBytesPerRow = (pixelsWide * 4); 
    bitmapByteCount  = (bitmapBytesPerRow * pixelsHigh); 

    // Use the generic RGB color space. 
    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 
    if (colorSpace == NULL) 
    { 
     fprintf(stderr, "Error allocating color space\n"); 
     return NULL; 
    } 

    // Allocate memory for image data. This is the destination in memory 
    // where any drawing to the bitmap context will be rendered. 
    bitmapData = malloc(bitmapByteCount); 
    if (bitmapData == NULL) 
    { 
     fprintf (stderr, "Memory not allocated!"); 
     CGColorSpaceRelease(colorSpace); 
     return NULL; 
    } 

    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits 
    // per component. Regardless of what the source image format is 
    // (CMYK, Grayscale, and so on) it will be converted over to the format 
    // specified here by CGBitmapContextCreate. 
    context = CGBitmapContextCreate (bitmapData, 
            pixelsWide, 
            pixelsHigh, 
            8,  // bits per component 
            bitmapBytesPerRow, 
            colorSpace, 
            kCGImageAlphaPremultipliedFirst); 
    if (context == NULL) 
    { 
     free (bitmapData); 
     fprintf (stderr, "Context not created!"); 
    } 

    // Make sure and release colorspace before returning 
    CGColorSpaceRelease(colorSpace); 

    return context; 
}` 

per ottenere il colore nella parte inferiore dell'immagine per renderlo fondono a mio controller della vista che utilizza il colore per lo sfondo, e ha un ombra per renderlo omogeneo.

Domanda: Quindi, come si dice: come ottengo il minimo e il colore più utilizzato da un'immagine?

+0

Pensate qualcosa lungo questa linea, http://www.markj.net/iphone-uiimage-pixel-color/ o questo http://www.bobbygeorgescu.com/2011/08/finding-average-color-of -uiimage/ – iDev

+0

Ho visto il primo prima, ecco come ottengo il colore inferiore nel mio schermo, e ora sto usando lo stesso codice per ottenere l'etichetta ottenendo un colore in alto, ma questo è davvero pessimo. il colore medio può aiutare però:] grazie !:] – Maximilian

+0

Bene, scorrere i pixel e aggiungere le cose. Ma è meglio rompere i colori in "bande" in qualche modo - ci sono 16 milioni di colori possibili, e non si può ragionevolmente tenere un contatore per ognuno di essi. –

risposta

27

Non sono sicuro di trovare la maggior parte del colore o meno colore, ma here is a method per scoprire il colore medio.

- (UIColor *)averageColor { 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    unsigned char rgba[4]; 
    CGContextRef context = CGBitmapContextCreate(rgba, 1, 1, 8, 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 

    CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), self.CGImage); 
    CGColorSpaceRelease(colorSpace); 
    CGContextRelease(context); 

    if(rgba[3] > 0) { 
     CGFloat alpha = ((CGFloat)rgba[3])/255.0; 
     CGFloat multiplier = alpha/255.0; 
     return [UIColor colorWithRed:((CGFloat)rgba[0])*multiplier 
           green:((CGFloat)rgba[1])*multiplier 
           blue:((CGFloat)rgba[2])*multiplier 
           alpha:alpha]; 
    } 
    else { 
     return [UIColor colorWithRed:((CGFloat)rgba[0])/255.0 
           green:((CGFloat)rgba[1])/255.0 
           blue:((CGFloat)rgba[2])/255.0 
           alpha:((CGFloat)rgba[3])/255.0]; 
    } 
} 

Probabilmente è possibile seguire un approccio simile per scoprire il colore più utilizzato.

Anche check this answer sul conteggio dei pixel di colore rosso in un'immagine.

41

Il seguente metodo prende un'immagine e lo analizza per i colori principali, nelle seguenti fasi:

1.) ridurre l'immagine e determinare i principali colori dei pixel.

2.) aggiungere una certa flessibilità colore per consentire per la perdita durante scalatura

3.) distinguere i colori, eliminando quei simili

4.) restituire i colori come un array ordinato o con le loro percentuali

È possibile adattarlo per restituire un numero specifico di colori, ad es. i 10 migliori colori dell'immagine se hai bisogno di un numero garantito di colori restituiti, o semplicemente usa la variabile "dettagli" se non lo fai.

Le immagini di dimensioni maggiori impiegheranno molto tempo per l'analisi ad alto dettaglio.

Senza dubbio il metodo potrebbe essere ripulito un po ', ma potrebbe essere un buon punto di partenza.

Usa come questo:

NSDictionary * mainColours = [s mainColoursInImage:image detail:1]; 

Example images run through the method at detail "1"

-(NSDictionary*)mainColoursInImage:(UIImage *)image detail:(int)detail { 

//1. determine detail vars (0==low,1==default,2==high) 
//default detail 
float dimension = 10; 
float flexibility = 2; 
float range = 60; 

//low detail 
if (detail==0){ 
    dimension = 4; 
    flexibility = 1; 
    range = 100; 

//high detail (patience!) 
} else if (detail==2){ 
    dimension = 100; 
    flexibility = 10; 
    range = 20; 
} 

//2. determine the colours in the image 
NSMutableArray * colours = [NSMutableArray new]; 
CGImageRef imageRef = [image CGImage]; 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
unsigned char *rawData = (unsigned char*) calloc(dimension * dimension * 4, sizeof(unsigned char)); 
NSUInteger bytesPerPixel = 4; 
NSUInteger bytesPerRow = bytesPerPixel * dimension; 
NSUInteger bitsPerComponent = 8; 
CGContextRef context = CGBitmapContextCreate(rawData, dimension, dimension, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
CGColorSpaceRelease(colorSpace); 
CGContextDrawImage(context, CGRectMake(0, 0, dimension, dimension), imageRef); 
CGContextRelease(context); 

float x = 0; 
float y = 0; 
for (int n = 0; n<(dimension*dimension); n++){ 

    int index = (bytesPerRow * y) + x * bytesPerPixel; 
    int red = rawData[index]; 
    int green = rawData[index + 1]; 
    int blue = rawData[index + 2]; 
    int alpha = rawData[index + 3]; 
    NSArray * a = [NSArray arrayWithObjects:[NSString stringWithFormat:@"%i",red],[NSString stringWithFormat:@"%i",green],[NSString stringWithFormat:@"%i",blue],[NSString stringWithFormat:@"%i",alpha], nil]; 
    [colours addObject:a]; 

    y++; 
    if (y==dimension){ 
     y=0; 
     x++; 
    } 
} 
free(rawData); 

//3. add some colour flexibility (adds more colours either side of the colours in the image) 
NSArray * copyColours = [NSArray arrayWithArray:colours]; 
NSMutableArray * flexibleColours = [NSMutableArray new]; 

float flexFactor = flexibility * 2 + 1; 
float factor = flexFactor * flexFactor * 3; //(r,g,b) == *3 
for (int n = 0; n<(dimension * dimension); n++){ 

    NSArray * pixelColours = copyColours[n]; 
    NSMutableArray * reds = [NSMutableArray new]; 
    NSMutableArray * greens = [NSMutableArray new]; 
    NSMutableArray * blues = [NSMutableArray new]; 

    for (int p = 0; p<3; p++){ 

     NSString * rgbStr = pixelColours[p]; 
     int rgb = [rgbStr intValue]; 

     for (int f = -flexibility; f<flexibility+1; f++){ 
      int newRGB = rgb+f; 
      if (newRGB<0){ 
       newRGB = 0; 
      } 
      if (p==0){ 
       [reds addObject:[NSString stringWithFormat:@"%i",newRGB]]; 
      } else if (p==1){ 
       [greens addObject:[NSString stringWithFormat:@"%i",newRGB]]; 
      } else if (p==2){ 
       [blues addObject:[NSString stringWithFormat:@"%i",newRGB]]; 
      } 
     } 
    } 

    int r = 0; 
    int g = 0; 
    int b = 0; 
    for (int k = 0; k<factor; k++){ 

     int red = [reds[r] intValue]; 
     int green = [greens[g] intValue]; 
     int blue = [blues[b] intValue]; 

     NSString * rgbString = [NSString stringWithFormat:@"%i,%i,%i",red,green,blue]; 
     [flexibleColours addObject:rgbString]; 

     b++; 
     if (b==flexFactor){ b=0; g++; } 
     if (g==flexFactor){ g=0; r++; } 
    } 
} 

//4. distinguish the colours 
//orders the flexible colours by their occurrence 
//then keeps them if they are sufficiently disimilar 

NSMutableDictionary * colourCounter = [NSMutableDictionary new]; 

//count the occurences in the array 
NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:flexibleColours]; 
for (NSString *item in countedSet) { 
    NSUInteger count = [countedSet countForObject:item]; 
    [colourCounter setValue:[NSNumber numberWithInteger:count] forKey:item]; 
} 

//sort keys highest occurrence to lowest 
NSArray *orderedKeys = [colourCounter keysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2){ 
    return [obj2 compare:obj1]; 
}]; 

//checks if the colour is similar to another one already included 
NSMutableArray * ranges = [NSMutableArray new]; 
for (NSString * key in orderedKeys){ 
    NSArray * rgb = [key componentsSeparatedByString:@","]; 
    int r = [rgb[0] intValue]; 
    int g = [rgb[1] intValue]; 
    int b = [rgb[2] intValue]; 
    bool exclude = false; 
    for (NSString * ranged_key in ranges){ 
     NSArray * ranged_rgb = [ranged_key componentsSeparatedByString:@","]; 

     int ranged_r = [ranged_rgb[0] intValue]; 
     int ranged_g = [ranged_rgb[1] intValue]; 
     int ranged_b = [ranged_rgb[2] intValue]; 

     if (r>= ranged_r-range && r<= ranged_r+range){ 
      if (g>= ranged_g-range && g<= ranged_g+range){ 
       if (b>= ranged_b-range && b<= ranged_b+range){ 
        exclude = true; 
       } 
      } 
     } 
    } 

    if (!exclude){ [ranges addObject:key]; } 
} 

//return ranges array here if you just want the ordered colours high to low 
NSMutableArray * colourArray = [NSMutableArray new]; 
for (NSString * key in ranges){ 
    NSArray * rgb = [key componentsSeparatedByString:@","]; 
    float r = [rgb[0] floatValue]; 
    float g = [rgb[1] floatValue]; 
    float b = [rgb[2] floatValue]; 
    UIColor * colour = [UIColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f]; 
    [colourArray addObject:colour]; 
} 

//if you just want an array of images of most common to least, return here 
//return [NSDictionary dictionaryWithObject:colourArray forKey:@"colours"]; 


//if you want percentages to colours continue below 
NSMutableDictionary * temp = [NSMutableDictionary new]; 
float totalCount = 0.0f; 
for (NSString * rangeKey in ranges){ 
    NSNumber * count = colourCounter[rangeKey]; 
    totalCount += [count intValue]; 
    temp[rangeKey]=count; 
} 

//set percentages 
NSMutableDictionary * colourDictionary = [NSMutableDictionary new]; 
for (NSString * key in temp){ 
    float count = [temp[key] floatValue]; 
    float percentage = count/totalCount; 
    NSArray * rgb = [key componentsSeparatedByString:@","]; 
    float r = [rgb[0] floatValue]; 
    float g = [rgb[1] floatValue]; 
    float b = [rgb[2] floatValue]; 
    UIColor * colour = [UIColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f]; 
    colourDictionary[colour]=[NSNumber numberWithFloat:percentage]; 
} 

return colourDictionary; 

} 
+0

quindi come ottengo il colore rgb da questo dizionario? –

+0

Il dizionario di restituzione contiene oggetti UIColor, se si desidera ritrasferire i valori RGB non elaborati, è possibile racchiuderli in [NSNumber numberWithFloat: Red]; –

+0

Se si desidera accenti: http://stackoverflow.com/a/41401246/917802 –

2

Grazie mille per il vostro codice, @JohnnyRockex. È stato davvero utile per farmi iniziare verso il mio obiettivo (trovare colori accentati a seconda del colore più predominante in un'immagine).

Dopo averlo esaminato, ho trovato che il codice potrebbe essere semplificato e reso più facile da leggere, quindi mi piacerebbe restituire alla comunità la mia versione; il selettore -colors è in un'estensione UIImage.

- (NSArray *)colors { 
// Original code by Johnny Rockex http://stackoverflow.com/a/29266983/825644 

// Higher the dimension, the more pixels are checked against. 
const float pixelDimension = 10; 
// Higher the range, more similar colors are removed. 
const float filterRange = 60; 

unsigned char *rawData = (unsigned char*) calloc(pixelDimension * pixelDimension * kBytesPerPixel, sizeof(unsigned char)); 

NSUInteger bytesPerRow = kBytesPerPixel * pixelDimension; 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
CGContextRef context = CGBitmapContextCreate(rawData, pixelDimension, pixelDimension, kBitsInAByte, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
CGColorSpaceRelease(colorSpace); 
CGContextDrawImage(context, CGRectMake(0, 0, pixelDimension, pixelDimension), [self CGImage]); 
CGContextRelease(context); 

NSMutableArray * colors = [[NSMutableArray alloc] init]; 
float x = 0; 
float y = 0; 
const int pixelMatrixSize = pixelDimension * pixelDimension; 
for (int i = 0; i < pixelMatrixSize; i++){ 
    int index = (bytesPerRow * y) + x * kBytesPerPixel; 

    int red = rawData[index]; 
    int green = rawData[index + 1]; 
    int blue = rawData[index + 2]; 
    int alpha = rawData[index + 3]; 
    UIColor * color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:alpha]; 
    [colors addObject:color]; 

    y++; 
    if (y == pixelDimension){ 
     y = 0; 
     x++; 
    } 
} 
free(rawData); 


NSMutableDictionary * colorCounter = [[NSMutableDictionary alloc] init]; 
NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:colors]; 
for (NSString *item in countedSet) { 
    NSUInteger count = [countedSet countForObject:item]; 
    [colorCounter setValue:[NSNumber numberWithInteger:count] forKey:item]; 
} 

NSArray *orderedColors = [colorCounter keysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2){ 
    return [obj2 compare:obj1]; 
}]; 

NSMutableArray *filteredColors = [NSMutableArray new]; 
for (UIColor *color in orderedColors){ 

    bool filtered = false; 
    for (UIColor *rangedColor in filteredColors){ 
     if (abs(color.redRGBComponent - rangedColor.redRGBComponent) <= filterRange && 
      abs(color.greenRGBComponent - rangedColor.greenRGBComponent) <= filterRange && 
      abs(color.blueRGBComponent - rangedColor.blueRGBComponent) <= filterRange) { 

      filtered = true; 
      break; 
     } 
    } 

    if (!filtered) { 
     [filteredColors addObject:color]; 
    } 
} 

return [filteredColors copy]; 

Il codice per UIColor s' estensione aggiungendo la funzione -rgbComponent può essere trovata al di sotto, ma ho scritto in Swift (cercando di scrivere tutte le nuove classi di Swift, ma questo non era il caso per il selettore -colors):

extension UIColor { 

    open func redRGBComponent() -> UInt8 { 
     let colorComponents = cgColor.components! 
     return UInt8(colorComponents[0] * 255) 
    } 

    open func greenRGBComponent() -> UInt8 { 
     let colorComponents = cgColor.components! 
     return UInt8(colorComponents[1] * 255) 
    } 

    open func blueRGBComponent() -> UInt8 { 
     let colorComponents = cgColor.components! 
     return UInt8(colorComponents[2] * 255) 
    } 

} 

Divertiti!

Problemi correlati