Luma Key(从图像创建alpha掩码)适用于iOS。

35

我正在开发一个应用程序,允许用户上传自己的白色背景照片并生成其轮廓。

我在抠出背景方面遇到了困难。我正在使用GPUImage框架,GPUImageChromaKeyBlendFilter对于颜色效果很好,但是如果遇到白色/黑色,则很难将其抠出。如果我将关键色设置为白色或黑色,则两者都会被抠掉。

你有什么建议吗?


1
当你需要@Brad Larson的时候,他在哪里啊! - Mick MacCallum
尝试创建一个基于GPUImageAlphaBlendFilter的自定义滤镜,只需在最后的混合操作中用红色通道(textureColor.r)替换alpha通道(textureColor.a)。如果您在输入之前将图像转换为亮度,则应该根据第一张图像的亮度进行选择性混合。您可能还需要调整混合顺序以实现所需的效果。 - Brad Larson
6
你也应该知道,拉取良好的亮度键非常困难。大多数用户可能没有足够的照明和曝光来使其效果良好。任何肤色较浅且光线明亮的人都会在他们身上留下过度饱和的斑点,这些斑点会影响相机的图像传感器,并被键控器误认为是白色。即使在FCP中有一个很好的亮度键控器,如果你没能拍摄得当,最终结果看起来也会很糟糕。 - user1118321
1
假设您已经找到了解决方案,请选择答案或自我回答以关闭问题。您的问题得到了赞同,因为人们想知道! - David H
我有同样的问题 http://stackoverflow.com/questions/34989942/gpuimagemovie-not-support-alpha-channel/35004399#35004399 - Allan
显示剩余2条评论
4个回答

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

显然,您应该在后台线程中调用此函数,以保持一切运行顺畅。


0

尝试使用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;
}

0
有时候,澄清你想要实现的目标并理解差异可能有所帮助。根据我的理解,你正在讨论半透明和透明之间的区别。
半透明度考虑了alpha值,允许背景基于图像像素的alpha值以及在背景缓冲区上执行的评估进行与前景混合。
透明度允许在具有硬边缘(hard alpha)和阈值的部分“遮盖”图像,并允许通过遮罩看到背景而不会混合。阈值允许基于alpha值进行有限混合,直到阈值为止。
色键(Chromokeying)类似于透明度,它允许您将硬编码颜色设置为掩码颜色(或混合键阈值),从而允许通过拥有该颜色的前景部分看到背景。
如果你的图像格式支持alpha值的数据类型或像素格式,计算起来就相对简单:
基于亮度的Alpha = (R + G + B) / 3;
基于通道优先级的Alpha = Max(R, G, B);
带有阈值为127的混合透明度意味着每个通过alpha测试且值为127或更低的像素都将被混合,而那些大于127的像素将被硬遮罩。

希望这能稍微澄清一下,以防不清楚。厉害的代码,伙计们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接