【问题标题】:Luma Key (create alpha mask from image) for iOS适用于 iOS 的 Luma Key(从图像创建 Alpha 蒙版)
【发布时间】:2012-08-22 20:53:16
【问题描述】:

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

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

有什么建议吗?

【问题讨论】:

  • 当你需要他时,@Brad Larson 在哪里!
  • 尝试创建基于 GPUImageAlphaBlendFilter 的自定义过滤器,仅将最后混合操作中的 alpha 通道 (textureColor.a) 替换为红色通道 (textureColor.r)。如果您在输入之前将图像转换为亮度,我相信应该根据第一张图像的亮度选择性地混合。您可能还需要调整混合顺序以达到您想要的效果。
  • 非常感谢您抽出宝贵时间!不幸的是,该应用程序现在正在崩溃。需要明确的是,这是您所指的行: gl_FragColor = vec4(mix(textureColor.rgb, textureColor2.rgb, textureColor2.a * mixPercent), textureColor.a);我如何只通过红色?我尝试的一切都以崩溃告终:-[GPUImageAlphaBlendFilter initWithVertexShaderFromString:fragmentShaderFromString:] 中的断言失败
  • 您还应该知道,亮度键很难拉好。大多数用户没有适当的照明和曝光来使这项工作非常好。任何皮肤浅且光线明亮的人肯定会有斑点,这些斑点会使相机上的图像传感器饱和并看起来像白色的键控器。即使在 FCP 中,他们有一个很好的亮度键控,如果你没有正确拍摄它,它最终看起来很糟糕。
  • 假设您找到了解决方案,请选择答案或自行回答以关闭此问题。您的问题获得了投票,因为人们想知道!

标签: objective-c ios gpuimage


【解决方案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 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;
      }
      

      【讨论】:

        【解决方案4】:

        有时,澄清您要达到的目标,然后了解差异可能会有所帮助。你说的是我收集的半透明与透明度。

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

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

        Chromokeying 类似于透明度,因为它允许您将硬编码颜色设置为遮罩颜色(或混合抠像的 Alpha 阈值),从而允许通过具有该颜色的前景部分看到背景。

        如果您的图像格式支持 alpha 值的数据类型或像素格式,则计算起来相当简单:

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

        基于通道的Alpha = Max(R,G,B);

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

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

        【讨论】:

          猜你喜欢
          • 2011-03-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-20
          • 2012-02-23
          • 2011-09-18
          • 2015-07-07
          • 2012-12-26
          相关资源
          最近更新 更多