首页 文章

c#.NET绿屏背景删除

提问于
浏览
4

我正在研究适用于Windows 8的台式电脑照片软件 . 我希望能够通过色度键控从照片中删除绿色背景 .

我是图像处理的初学者,我发现了一些很酷的链接(比如http://www.quasimondo.com/archives/000615.php),但是我不能用c#代码转换它 .

我正在使用网络摄像头(使用aforge.net)查看预览并拍照 . 我尝试了彩色滤镜,但绿色背景并没有起作用 .

如何在C#中正确地做到这一点?

3 回答

  • 0

    它会工作,即使背景不统一,你只需要适当的策略,足以 grab 你的所有绿屏而不更换任何其他东西 .

    由于链接页面上至少有一些链接已经死亡,我尝试了自己的方法:

    • 基础知识很简单:将图像像素的颜色与某个参考值进行比较,或应用其他一些公式来确定它是否应该透明/替换 .

    • 最基本的公式将涉及“确定绿色是否是最大 Value ”这样简单的事情 . 虽然这适用于非常基本的场景,但它可以搞砸你(例如白色或灰色也会被过滤) .

    我使用一些简单的示例代码玩弄了一下 . 当我使用Windows Forms时,它应该是可移植的而没有问题,我很确定你能够解释代码 . 请注意,这不一定是执行此操作的最佳方式 .

    Bitmap input = new Bitmap(@"G:\Greenbox.jpg");
    
    Bitmap output = new Bitmap(input.Width, input.Height);
    
    // Iterate over all piels from top to bottom...
    for (int y = 0; y < output.Height; y++)
    {
        // ...and from left to right
        for (int x = 0; x < output.Width; x++)
        {
            // Determine the pixel color
            Color camColor = input.GetPixel(x, y);
    
            // Every component (red, green, and blue) can have a value from 0 to 255, so determine the extremes
            byte max = Math.Max(Math.Max(camColor.R, camColor.G), camColor.B);
            byte min = Math.Min(Math.Min(camColor.R, camColor.G), camColor.B);
    
            // Should the pixel be masked/replaced?
            bool replace =
                camColor.G != min // green is not the smallest value
                && (camColor.G == max // green is the biggest value
                || max - camColor.G < 8) // or at least almost the biggest value
                && (max - min) > 96; // minimum difference between smallest/biggest value (avoid grays)
    
            if (replace)
                camColor = Color.Magenta;
    
            // Set the output pixel
            output.SetPixel(x, y, camColor);
        }
    }
    

    我使用了example image from Wikipedia并获得了以下结果:

    Masked result (magenta would be replaced by your background)

    请注意,您可能需要不同的阈值(在上面的代码中为 896 ),您甚至可能希望使用不同的术语来确定是否应该替换某些像素 . 您还可以在帧之间添加平滑,混合(绿色差异较小)等,以减少硬边缘 .

  • 7

    我对我来说有点慢 . 我找了一个不同的解决方案,我找到了一个在这里使用更有效的方法的项目 . Github postworthy GreenScreen

    该项目需要一个文件夹并处理所有文件,我只需要一个图像所以我这样做:

    private Bitmap RemoveBackground(Bitmap input)
        {
            Bitmap clone = new Bitmap(input.Width, input.Height, PixelFormat.Format32bppArgb);
            {
                using (input)
                using (Graphics gr = Graphics.FromImage(clone))
                {
                    gr.DrawImage(input, new Rectangle(0, 0, clone.Width, clone.Height));
                }
    
                var data = clone.LockBits(new Rectangle(0, 0, clone.Width, clone.Height), ImageLockMode.ReadWrite, clone.PixelFormat);
    
                var bytes = Math.Abs(data.Stride) * clone.Height;
                byte[] rgba = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(data.Scan0, rgba, 0, bytes);
    
                var pixels = Enumerable.Range(0, rgba.Length / 4).Select(x => new {
                    B = rgba[x * 4],
                    G = rgba[(x * 4) + 1],
                    R = rgba[(x * 4) + 2],
                    A = rgba[(x * 4) + 3],
                    MakeTransparent = new Action(() => rgba[(x * 4) + 3] = 0)
                });
    
                pixels
                    .AsParallel()
                    .ForAll(p =>
                    {
                        byte max = Math.Max(Math.Max(p.R, p.G), p.B);
                        byte min = Math.Min(Math.Min(p.R, p.G), p.B);
    
                        if (p.G != min && (p.G == max || max - p.G < 7) && (max - min) > 20)
                            p.MakeTransparent();
                    });
    
                System.Runtime.InteropServices.Marshal.Copy(rgba, 0, data.Scan0, bytes);
                clone.UnlockBits(data);
    
                return clone;
            }
        }
    

    不要忘记丢弃输入位图并返回此方法 . 如果需要保存图像,只需使用位图的保存指令 .

    clone.Save(@"C:\your\folder\path", ImageFormat.Png);
    

    在这里,您可以找到更快地处理图像的方法 . Fast Image Processing in C#

  • 1

    照片上的Chromakey应采用模拟输入 . 在现实世界中,确切的值非常罕见 .

    你怎么补偿这个?在色调和色调方面围绕您选择的绿色提供阈值 . 此阈值(包括)内的任何颜色都应替换为您选择的背景;透明可能是最好的 . 在第一个链接中,Mask In和Mask Out参数实现了这一点 . 前后模糊参数尝试使背景更均匀,以减少编码噪声副作用,以便您可以使用更窄(首选)的阈值 .

    为了提高性能,您可能需要编写一个像素着色器来将“绿色”切换为透明,但这是在您使其工作之后的一个考虑因素 .

相关问题