如何移除“绿幕”人像背景

12

我正在寻找一种自动地将大量照片中的“绿屏”人像背景去除(即透明化)的方法。

我自己的尝试一直以来都不太成功。

我正在寻找任何关于这个主题的提示、解决方案或论文。商业解决方案也完全可以。

在你发表评论并说这是不可能自动完成的之前,我要说不,这是可以的。实际上有一家公司提供了这样的服务,如果我不能想出另一个解决方案,我们就会使用他们。问题是,他们用命保护他们的算法,因此不会出售/授权他们的软件。相反,我们必须将所有图片FTP到他们的服务器进行处理,然后再将结果FTP回家。 (不,他们没有一个隐藏在菲律宾的低薪员工手动处理这些,因为我们每天处理的是数千张图片...) 然而,这种方法由于几个原因而受到限制。因此,我真的希望有一种解决方案,可以在离线状态下立即完成这项工作。

编辑: 我的“人像”描绘的是有头发的人,这是一个非常棘手的部分,因为绿色的背景会渗入头发。另一个棘手的部分是,如果可以区分出衣服中的绿色和背景中的绿色是否相同。上面提到的公司声称他们可以通过判断绿色区域是否处于对焦状态(清晰与模糊)来解决这个问题。


5
“地球上哪里提到了‘头发’的要求?这出现在你的评论中,但原始规格说明书中没有提到。我认为你可能应该在问题中加入更多细节。如果是你给那些答案投了反对票,那么这样做就相当糟糕,因为这显示出你没有完全说明问题。” - paxdiablo
4
抱歉造成混淆,但对我来说,肖像画描绘的是一个人,我错了吗?而且很多人都有头发... - Dan Byström
danbystrom,你解决了这个问题吗?我查看了@k00k发布的链接,我将尝试使用它来为我们的访客提供免费的旅行照片。我想和你一起合作完成它。 - Kelbizzle
嗨@Kelbizzle,我有一个相当不错的解决方案,我从头开始实现。它不是高清的,但如果我将其应用于高分辨率图片,然后将其缩小到384x512像素,那么几乎所有的瑕疵都变得看不见了。 - Dan Byström
如果您提供一些图片,也许一些开发人员就可以提供一些代码来测试想法。 - Gabriel Archanjo
显示剩余2条评论
5个回答

28

由于您没有提供任何图像,因此我从网络上选择了一张带有不同绿色阴影和显着的噪声(因为JPEG压缩)的图像进行抠图。

由于没有技术规格说明,所以我使用了Java和Marvin Framework

输入图像:

enter image description here

步骤1简单地将绿色像素转换为透明。基本上它使用了HSV颜色空间中的一个过滤规则。

enter image description here

正如您提到的,头发和一些边界像素呈现混合绿色的颜色。为了减少这个问题,第二步中过滤这些像素并平衡以减少其绿色比例。

之前:

enter image description here

之后:

enter image description here

最后,在第三步中,对所有边界像素应用渐变透明度。高质量图像将得到更好的结果。

最终输出:

enter image description here

源代码:

import static marvin.MarvinPluginCollection.*;

public class ChromaToTransparency {

    public ChromaToTransparency(){
        MarvinImage image = MarvinImageIO.loadImage("./res/person_chroma.jpg");
        MarvinImage imageOut = new MarvinImage(image.getWidth(), image.getHeight());
        // 1. Convert green to transparency
        greenToTransparency(image, imageOut);
        MarvinImageIO.saveImage(imageOut, "./res/person_chroma_out1.png");
        // 2. Reduce remaining green pixels
        reduceGreen(imageOut);
        MarvinImageIO.saveImage(imageOut, "./res/person_chroma_out2.png");
        // 3. Apply alpha to the boundary
        alphaBoundary(imageOut, 6);
        MarvinImageIO.saveImage(imageOut, "./res/person_chroma_out3.png");

    }

    private void greenToTransparency(MarvinImage imageIn, MarvinImage imageOut){
        for(int y=0; y<imageIn.getHeight(); y++){
            for(int x=0; x<imageIn.getWidth(); x++){

                int color = imageIn.getIntColor(x, y);
                int r = imageIn.getIntComponent0(x, y);
                int g = imageIn.getIntComponent1(x, y);
                int b = imageIn.getIntComponent2(x, y);

                double[] hsv = MarvinColorModelConverter.rgbToHsv(new int[]{color});

                if(hsv[0] >= 60 && hsv[0] <= 130 && hsv[1] >= 0.4 && hsv[2] >= 0.3){
                    imageOut.setIntColor(x, y, 0, 127, 127, 127);
                }
                else{
                    imageOut.setIntColor(x, y, color);
                }

            }
        }
    }

    private void reduceGreen(MarvinImage image){
        for(int y=0; y<image.getHeight(); y++){
            for(int x=0; x<image.getWidth(); x++){
                int r = image.getIntComponent0(x, y);
                int g = image.getIntComponent1(x, y);
                int b = image.getIntComponent2(x, y);
                int color = image.getIntColor(x, y);
                double[] hsv = MarvinColorModelConverter.rgbToHsv(new int[]{color});

                if(hsv[0] >= 60 && hsv[0] <= 130 && hsv[1] >= 0.15 && hsv[2] > 0.15){
                    if((r*b) !=0 && (g*g) / (r*b) >= 1.5){
                        image.setIntColor(x, y, 255, (int)(r*1.4), (int)g, (int)(b*1.4));
                    } else{
                        image.setIntColor(x, y, 255, (int)(r*1.2), g, (int)(b*1.2));
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        new ChromaToTransparency();
    }
}

2
嗨,Gabriel,我六年前写了这个问题,但显然有人对它进行了悬赏 - 我希望他会评论你的努力。我已经有一个可接受的解决方案在生产中运行多年了。您提供了一个具有重压缩伪影的低分辨率图像,因此对于我正在处理的领域来说不可表示,但有一天我会在我的测试图像上运行您的代码以查看差异。然而,我现在想解决的问题是如何区分相同颜色的背景和布料,但那是另一回事了。干得好 - 干杯! - Dan Byström
丹,你有一个穿着相同颜色衣服的人的框架吗?把它发送给我:gabriel at garchanjo dot com。让我看看。也许我可以帮忙。 - Gabriel Archanjo
我们能否使用类似的代码来从视频中去除背景?这段代码的性能如何?我认为将视频转换为单独的照片帧,对它们进行处理,然后重新组合以获得无背景视频将会消耗太多资源。 - Mustafa sabir
是的,你可以!你甚至可以在更复杂的情况下删除背景,就像这个视频中所示:https://www.youtube.com/watch?v=bwEGeI7E0n0 - Gabriel Archanjo
@GabrielAmbrósioArchanjo,关于if((r*b) !=0 && (g*g) / (r*b) >= 1.5),有没有相关的资源可以参考?不确定您是如何想到这个条件的,或者这只是为了阈值化特定图像而进行的试错? - c4da
显示剩余3条评论

2

我应该指出,我没有尝试过这个,而且你的情况可能会有所不同。特别是在抗锯齿和软边缘方面。 - k00k
这需要我花费相当长的时间来深入研究,但这似乎正是我想学习的东西!尽管我严重怀疑“相当简单”的部分! :-) - Dan Byström
嘿,我的意思是编写脚本部分很容易。 :) - k00k

2

如果您了解“绿色”,则可以使用OpenCV C/C++/Python编写一个小程序来提取该颜色并用透明像素替换。


3
我可以通过检查我知道应该包含大部分绿色的区域并计算中位数来找到绿色,但问题在于头发,头发,头发......绿色渗入头发并与头发混合......然后我们又遇到了同时穿着相同绿色衣服的问题...... - Dan Byström
1
根据您上面的描述,我的答案是正确的。但根据您的评论,它不是。但为什么我需要事先知道才能获得负评呢? 祝您搜索愉快。 - rics
是的,我也这么认为。我不是给你点踩的人。我认为你的回答完全有效(尽管不适用 - 如注所述)。 - Dan Byström
因为我认为负评并不公平,所以我点了赞。我误解了这个问题,可能其他人也会误解。如果你同意它不符合问题的话,你可能想要考虑在你还能拿回一些面子的时候删除这个答案。 - paxdiablo

2

123 Video Magic Green Screen Background Software是一款专门用于去除绿幕背景的软件,还有其他几款类似的软件也能达到同样的效果。希望这能帮到您。


我看不到他们提供我可以自己使用的API?"FXhome"有支持"热文件夹"的软件,但不幸的是那还不够好。幸运的是,我已经在自己的项目上取得了巨大进展,但还没有完全完成... - Dan Byström

1

PaintShop Pro 允许您基于选取颜色来删除背景。他们还提供一个“去除背景魔棒”,可以删除您触摸到的任何内容(将这些像素转换为透明)。您可以微调魔棒的“容差”,使其删除与您触摸到的像素相似的像素。这在过去对我来说效果不错。

要自动化它,您可以在 PSP 中编写脚本以实现所需功能,然后从您的程序中调用它。这可能是一种笨拙的自动替换方式,但它是最便宜、最快的解决方案,而不必编写大量的 C# / C++ 图像代码或支付商业机构。

话虽如此,您得到什么付出什么。


2
我相信他正在寻找一种自动化的“服务器端”解决方案。 - k00k
1
首先,我说的是“自动”的。但是这完全解决不了绿色反射和闪烁透过(特别是金发)头发的问题。这需要相当多的手动工作。而且,要对每天5000张图片进行这样的处理需要多少人呢...? - Dan Byström
1
PSP可以自动化。虽然可能有些笨拙,但您可以编写通过命令运行的脚本。 - sohtimsso1970
你已经多次提到了头发问题(在这里和下面的一个回答中)。这就是为什么我建议使用像PSP这样的商业产品进行编程。它已经包含了算法来确定哪些像素是“相似的绿色阴影”,哪些不是。你不想自己尝试做这些事情。找到一个提供脚本和外壳的商业产品(如PSP)并打开它。 - sohtimsso1970
1
因为我认为这个踩票是不公平的,所以我点了赞。我误解了问题,所以可能其他人也会误解 :-) 如果你同意它与问题不匹配,你可能想要考虑在你还有机会的时候删除这个答案。 - paxdiablo
1
阅读了这个帖子后(并且使用Paint Shop Pro多年),我意识到编写自己的基本“绿屏去除器”网页非常容易,然后可以将结果保存为.png文件。这比使用PSP容易得多!http://www.mikesknowledgebase.com/pages/Other/ImageBackgroundRemover.htm - Mike Gledhill

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