Luma Key (создать альфа-маску из изображения) для iOS
Я создаю приложение, которое позволяет людям загружать изображение себя на белом фоне, и приложение создаст силуэт человека.
Мне сложно найти фона. Я использую рамки GPUImage
, а GPUImageChromaKeyBlendFilter
отлично подходит для цветов, но если вы добираетесь до белого/черного, очень сложно выделить один из этих цветов. Если я установил ключ в белый или черный, он будет одинаковым.
Любые советы?
Ответы
Ответ 1
Существует причина, по которой типичные синие или зеленые экраны используются в производстве фильмов для обработки цветности, вместо белого. Все может быть белым или достаточно близко к белому на фотографии, особенно глаза или блики или только части кожи. Кроме того, довольно сложно найти сплошную белую стену без теней, на которую, по крайней мере, наносится ваш предмет.
Я бы рекомендовал построить гистограмму, найдя наиболее часто используемый цвет среди самых ярких, а затем поиск самой большой области этого цвета с использованием определенного порога. Затем заливайте заливку из этой области до тех пор, пока не будут встречены достаточно разные цвета. Все это можно легко сделать в программном обеспечении, если вы не хотите видеопотока в реальном времени.
Ответ 2
Итак, чтобы изменить белый на прозрачный, мы можем использовать этот метод:
-(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;
}
и для замены непрозрачных пикселей на черный, мы можем использовать:
- (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;
}
поэтому на практике это будет:
-(UIImage *)silhouetteForImage:(UIImage *)img {
return [self changeColour:[self changeWhiteColorTransparent:img]];
}
Очевидно, вы бы назвали это в фоновом потоке, чтобы все работало плавно.
Ответ 3
Игра с композитором Quartz и фильтрами CoreImage может вам помочь. Я считаю, что этот код должен сделать вам силуэт:
- (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] [email protected]"inputColor1"];
[filter setValue:ciInput forKey:kCIInputImageKey];
CIImage *outImage = [filter valueForKey:kCIOutputImageKey];
CGImageRef result = [ciContext createCGImage:outImage fromRect:[ciInput extent]];
return result;
}
Ответ 4
Иногда разъяснение того, чего вы пытаетесь достичь, а затем понимание различий может помочь. Вы говорите о том, что я собираю прозрачность и прозрачность.
Прозрачность учитывает альфа, позволяя смешивать фон с передним планом на основе значения альфа для пикселей изображения и вида оценки, выполняемой в фоновом буфере.
Прозрачность позволяет "замаскировать" изображение на участках с жесткой альфой и порогом и позволяет фон просматриваться через маску без смешивания. Пороговое значение позволяет ограничить смешивание на основе значения альфа до порога.
Chromokeying похож на прозрачность, поскольку позволяет вам устанавливать жестко закодированный цвет в качестве цвета маски (или альфа-порога для смешанной клавиатуры), что позволяет видеть фон через части переднего плана, которые обладают этим цветом.
Если ваш формат изображения поддерживает тип данных или pixelformat для альфа-значений, довольно просто вычислить:
Альфа на основе светимости = (R + G + B)/3;
Альфа на основе допущения канала = Макс (R, G, B);
Смешанная прозрачность с альфа-порогом 127 означает, что каждый пиксель, который прошел альфа-тест со значением 127 или ниже, будет смешан, а те, что выше 127, будут жестко маскироваться.
Я надеюсь, что это поможет прояснить немного, на случай, если это не ясно. Удивительные кодовые парни.