objective c - que - Luma Key(crear máscara alfa de imagen) para iOS
sketch download for windows (4)
Estoy construyendo una aplicación que permite a las personas subir una imagen de sí mismos sobre un fondo blanco y la aplicación creará una silueta de la persona.
Me está costando sacar el fondo. Estoy usando el marco GPUImage
y el GPUImageChromaKeyBlendFilter
funciona muy bien para los colores, pero si llegas al blanco / negro es muy difícil GPUImageChromaKeyBlendFilter
uno de esos colores. Si configuro la tecla en blanco o negro, ambas teclas son iguales.
¿Algún consejo?
A veces, una aclaración de lo que intenta lograr y luego comprender las diferencias podría ayudar. Estás hablando de lo que encuentro translucidez versus transparencia.
La translucidez tiene en cuenta la alfa, lo que permite que el fondo se mezcle con el primer plano en función del valor alfa de los píxeles de la imagen y el tipo de evaluación realizada en el búfer de fondo.
La transparencia permite "enmascarar" una imagen en las partes con un alfa y un umbral duros, y permite ver el fondo a través de la máscara sin mezclar. El valor de umbral permite una combinación limitada basada en el valor alfa hasta el umbral.
Chromokeying es como la transparencia, ya que le permite establecer un color codificado como el color de la máscara (o umbral alfa para la incrustación combinada), lo que permite que se vea el fondo a través de partes del primer plano que poseen ese color.
Si su formato de imagen admite el tipo de datos o el formato de píxel para los valores alfa, es bastante trivial calcular:
Alfa basado en luminosidad = (R + G + B) / 3;
Alpha basado en la presidencia del canal = Max (R, G, B);
La transparencia combinada con un umbral alfa de 127 significaría que se mezclarían todos los píxeles que pasaron la prueba alfa con un valor de 127 o inferior y los que están por encima de 127 quedarían ocultos.
Espero que eso ayude a aclarar un poco, por si acaso no está claro. Código impresionante chicos.
Entonces, para cambiar un blanco a transparente podemos usar este método:
-(UIImage *)changeWhiteColorTransparent: (UIImage *)image {
CGImageRef rawImageRef=image.CGImage;
const float colorMasking[6] = {222, 255, 222, 255, 222, 255};
UIGraphicsBeginImageContext(image.size);
CGImageRef maskedImageRef=CGImageCreateWithMaskingColors(rawImageRef, colorMasking);
{
//if in iphone
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0.0, image.size.height);
CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1.0, -1.0);
}
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, image.size.width, image.size.height), maskedImageRef);
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
CGImageRelease(maskedImageRef);
UIGraphicsEndImageContext();
return result;
}
y para reemplazar los píxeles no transparentes con negro, podemos usar:
- (UIImage *) changeColor: (UIImage *)image {
UIGraphicsBeginImageContext(image.size);
CGRect contextRect;
contextRect.origin.x = 0.0f;
contextRect.origin.y = 0.0f;
contextRect.size = [image size];
// Retrieve source image and begin image context
CGSize itemImageSize = [image size];
CGPoint itemImagePosition;
itemImagePosition.x = ceilf((contextRect.size.width - itemImageSize.width) / 2);
itemImagePosition.y = ceilf((contextRect.size.height - itemImageSize.height) );
UIGraphicsBeginImageContext(contextRect.size);
CGContextRef c = UIGraphicsGetCurrentContext();
// Setup shadow
// Setup transparency layer and clip to mask
CGContextBeginTransparencyLayer(c, NULL);
CGContextScaleCTM(c, 1.0, -1.0);
CGContextClipToMask(c, CGRectMake(itemImagePosition.x, -itemImagePosition.y, itemImageSize.width, -itemImageSize.height), [image CGImage]);
CGContextSetFillColorWithColor(c, [UIColor blackColor].CGColor);
contextRect.size.height = -contextRect.size.height;
contextRect.size.height -= 15;
// Fill and end the transparency layer
CGContextFillRect(c, contextRect);
CGContextEndTransparencyLayer(c);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
entonces en la práctica esto sería:
-(UIImage *)silhouetteForImage:(UIImage *)img {
return [self changeColour:[self changeWhiteColorTransparent:img]];
}
Obviamente llamarías esto en un hilo de fondo, para mantener todo funcionando sin problemas.
Hay una razón por la cual las pantallas típicamente azules o verdes se utilizan en la producción de películas para la incrustación de croma, en lugar de blanco. Cualquier cosa puede ser blanca o lo suficientemente cerca del blanco en una foto, especialmente los ojos o reflejos o solo partes de la piel. Además, es bastante difícil encontrar una pared blanca uniforme sin sombras, al menos por el sujeto. Yo recomendaría construir un histograma, encontrar el color más utilizado entre los más brillantes, luego buscar el área más grande de ese color usando algún umbral. Luego haga un relleno de inundación desde esa área hasta que se encuentren colores suficientemente diferentes. Todo eso se puede hacer fácilmente en el software, a menos que desee una transmisión de video en tiempo real.
Jugar con el compositor Quartz y los filtros CoreImage puede ayudarte. Creo que este código debería hacerte una silueta:
- (CGImageRef)silhouetteOfImage:(UIImage *)input
{
CIContext *ciContext = [CIContext contextWithOptions:nil];
CIImage *ciInput = [CIImage imageWithCGImage:[input CGImage]];
CIFilter *filter = [CIFilter filterWithName:@"CIFalseColor"];
[filter setValue:[CIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0] forKey:@"inputColor0"];
[filter setValue:[CIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.0] forKey@"inputColor1"];
[filter setValue:ciInput forKey:kCIInputImageKey];
CIImage *outImage = [filter valueForKey:kCIOutputImageKey];
CGImageRef result = [ciContext createCGImage:outImage fromRect:[ciInput extent]];
return result;
}