适用于iOS的Luma Key(从图像创建alpha蒙版)

时间:2012-08-22 20:53:16

标签: objective-c ios gpuimage

我正在构建一个应用程序,允许人们在白色背景上上传自己的图像,该应用程序将创建一个人的轮廓。

我很难找出背景。我正在使用GPUImage框架,GPUImageChromaKeyBlendFilter非常适合颜色,但是如果你使用白色/黑色,很难找出其中一种颜色。如果我将键设置为白色或黑色,则键入相同的键。

有什么建议吗?

4 个答案:

答案 0 :(得分:1)

通常在电影制作中使用蓝色或绿色屏幕进行色度键控而不是白色,这是有原因的。照片中任何东西都可以是白色或足够接近白色,尤其是眼睛或高光或仅仅是皮肤的一部分。此外,很难找到一个没有阴影的均匀白墙,至少由你的主题投射。 我建议建立一个直方图,在最亮的颜色中找到最常用的颜色,然后使用一些阈值搜索该颜色的最大区域。然后从该区域进行洪水填充,直到遇到足够不同的颜色。除非您需要实时视频流,否则所有这一切都可以在软件中轻松完成。

答案 1 :(得分:0)

因此,要将白色更改为透明,我们可以使用此方法:

-(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]];
}

显然你会在后台线程中调用它,以保证一切顺利运行。

答案 2 :(得分:0)

使用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] forKey@"inputColor1"];
  [filter setValue:ciInput forKey:kCIInputImageKey];
  CIImage *outImage = [filter valueForKey:kCIOutputImageKey];
  CGImageRef result = [ciContext createCGImage:outImage fromRect:[ciInput extent]];
  return result;
}

答案 3 :(得分:0)

有时澄清你想要达到的目标然后理解差异可能有所帮助。你所谈论的是我对半透明与透明度的关系。

半透明考虑了alpha,允许根据图像像素的alpha值和在背景缓冲区上执行的评估类型将背景与前景混合。

透明度允许在具有硬alpha和阈值的部分中“遮盖”图像,并允许通过遮罩看到背景而不进行混合。阈值允许基于alpha值的有限混合直到阈值。

Chromokeying就像透明,因为它允许您将硬编码颜色设置为蒙版颜色(或混合键控的alpha阈值),这样可以通过拥有该颜色的前景部分看到背景。

如果您的图像格式支持alpha值的数据类型或pixelformat,那么计算它是非常简单的:

Alpha基于发光度=(R + G + B)/ 3;

基于渠道总部的Alpha = Max(R,G,B);

Alpha阈值为127的混合透明度意味着每个通过alpha测试的像素值为127或更低的像素将被混合,而127以上的像素将被硬屏蔽。

我希望这有助于澄清一点,以防万一不清楚。很棒的代码人。