objective-c - varias - que color de auto elegir
Objective-c-Obtener el color menos usado y más usado en una imagen (3)
Estoy tratando de obtener el color menos usado y el color más usado de las ilustraciones del álbum de MP3 para una aplicación de reproducción de música. Necesito los colores para hacer un efecto como el nuevo itunes 11. Donde el color de fondo del menú es el color más usado, y el color menos usado es el color de las etiquetas de las canciones y el nombre del artista. estoy usando
`- (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;
}`
para obtener el color en la parte inferior de la imagen para que se mezcle en el controlador de mi vista, que usa el color para el fondo y tiene una sombra para hacerlo.
Pregunta: Entonces, como dice: ¿Cómo obtengo el color mínimo y más usado de una imagen?
El siguiente método toma una imagen y la analiza en busca de sus colores principales, en los siguientes pasos:
1.) reducir la imagen y determinar los colores del píxel principal.
2.) agregue un poco de flexibilidad de color para permitir la pérdida durante la escala
3.) Distinguir colores, eliminando los similares.
4.) devuelve los colores como una matriz ordenada o con sus porcentajes
Puede adaptarlo para devolver un número específico de colores, por ejemplo, los 10 mejores colores de la imagen si necesita un número garantizado de colores, o simplemente use la variable "detalle" si no lo hace.
Las imágenes más grandes tardarán mucho tiempo en analizarse con gran detalle.
Sin duda, el método se podría limpiar un poco, pero podría ser un buen punto de partida.
Use así:
NSDictionary * mainColours = [s mainColoursInImage:image 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;
}
Muchas gracias por su código, @JohnnyRockex. Fue de gran ayuda para que comencara mi meta (encontrar colores de acento según el color más predominante en una imagen).
Después de leerlo, encontré que el código podría simplificarse y facilitar su lectura, por lo que me gustaría devolverle a la comunidad mi propia versión; -colors
selector -colors
está en una extensión de UIImage
.
- (NSArray *)colors {
// Original code by Johnny Rockex http://.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];
El código para la extensión de -rgbComponent
agrega la función -rgbComponent
se puede encontrar debajo, pero lo escribí en Swift (tratando de escribir todas las nuevas clases en Swift, pero este no fue el caso para el selector de -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)
}
}
¡Disfrutar!
No estoy seguro de encontrar la mayoría del color o el menos, pero bobbygeorgescu.com/2011/08/finding-average-color-of-uiimage para averiguar el color promedio.
- (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];
}
}
Probablemente pueda seguir un enfoque similar para descubrir el color más utilizado.
También verifique esta respuesta sobre el conteo de píxeles de color rojo en una imagen.