我正在构建一个应用程序,允许人们在白色背景下上传自己的图像,该应用程序将创建一个人的剪影。
我很难键入背景。我正在使用该GPUImage
框架,并且该框架GPUImageChromaKeyBlendFilter
非常适合颜色,但是如果您使用白色/黑色,则很难抠出其中一种颜色。如果我将键设置为白色或黑色,则两者的键相同。
有什么建议吗?
我正在构建一个应用程序,允许人们在白色背景下上传自己的图像,该应用程序将创建一个人的剪影。
我很难键入背景。我正在使用该GPUImage
框架,并且该框架GPUImageChromaKeyBlendFilter
非常适合颜色,但是如果您使用白色/黑色,则很难抠出其中一种颜色。如果我将键设置为白色或黑色,则两者的键相同。
有什么建议吗?
电影制作中通常使用蓝色或绿色屏幕而不是白色来进行色度键控是有原因的。照片中的任何东西都可以是白色或足够接近白色,尤其是眼睛或亮点或只是部分皮肤。此外,很难找到一堵没有阴影的统一白墙,至少由你的主体投射。我建议建立一个直方图,在最亮的颜色中找到最常用的颜色,然后使用某个阈值搜索该颜色的最大区域。然后从该区域进行泛光填充,直到遇到足够不同的颜色。除非您想要实时视频流,否则所有这些都可以在软件中轻松完成。
因此,要将白色更改为透明,我们可以使用以下方法:
-(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]];
}
显然你会在后台线程中调用它,以保持一切顺利运行。
玩一下 Quartz composer 和 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] forKey@"inputColor1"];
[filter setValue:ciInput forKey:kCIInputImageKey];
CIImage *outImage = [filter valueForKey:kCIOutputImageKey];
CGImageRef result = [ciContext createCGImage:outImage fromRect:[ciInput extent]];
return result;
}
有时,澄清您要达到的目标,然后了解差异可能会有所帮助。你说的是我收集的半透明与透明度。
半透明考虑了 alpha,允许基于图像像素的 alpha 值和在背景缓冲区上执行的评估类型将背景与前景混合。
透明度允许图像在具有硬 alpha 和阈值的部分中被“遮蔽”,并允许通过遮罩看到背景而不进行混合。阈值允许基于 alpha 值的有限混合,直到阈值。
Chromokeying 类似于透明度,因为它允许您将硬编码颜色设置为遮罩颜色(或混合抠像的 alpha 阈值),这允许通过具有该颜色的前景部分看到背景。
如果您的图像格式支持 alpha 值的数据类型或像素格式,则计算起来相当简单:
基于亮度的 Alpha = (R + G + B) / 3;
Alpha基于通道的predence = Max(R,G,B);
alpha 阈值为 127 的混合透明度意味着通过 alpha 测试且值为 127 或更低的每个像素都将被混合,而高于 127 的像素将被硬屏蔽。
我希望这有助于澄清一点,以防万一不清楚。很棒的代码家伙。