Generating masks from green screen pictures when the green pixel isn't green enough?

Hello,

I’d like to handle pictures that have some kind of green screen in the background. The problem is the green pixels aren’t pure green, because that’s not a professional background and lights aren’t projectors either. I don’t have much influence on the equipment used.

The principle is already coded (looping thru every pixel, determining if it’s green or not and filling the mask with white or black). But the determination step causes problems.

Currently, I’m using this check:

Result=Green<35 or Red>Green or Blue>Green
(code found on the Internet, as my attempts have all been overcomplicated and not working :sweat_smile:)

With this, the result looks almost good, but near-white pixels and bright areas are also considered as transparent. It’s close, but not enough (and I tested only on one picture).

I’m attaching here an example picture. The green background appears rather yellowish (but the shadows are also a problem). I’m not even sure any code could work with that… :thinking:

Any idea for a working check?

Try looking into “color distance” - how similar two colors are by calculating the distance between them in 3D space (one dimension for each channel of color in the RGB image). If you’re familiar with the Pythagorean Theorem, it will click right into place. :wink:

Essentially you’ll be calculating how far each pixel’s color is from the key green, and you’ll be able to give the user pretty good controls if the detection parameters needs fine tuning.

1 Like

Thank you.
And I was so close with my code.
The Result computation was actually right, but the bug was earlier.

In my previous design, Green, Blue and Red (in the formula) were the difference between each of the pixel’s channel and a colour chosen by the user (a colour to be chosen near the background one).
Now, I’m just comparing each pixel against plain green and it works!

1 Like

from my greenscreen pic tool but not optimized

Public Function RemoveGreen(picIn As Picture) As Picture
  
  Var picOut As New Picture(picIn.Width,picIn.Height)
  picOut.Graphics.DrawPicture(picIn,0,0)
  
  Var surf As RGBSurface = picOut.RGBSurface
  
  Var c As Color
  For x As Integer = 0 To picIn.Width-1
    For y As Integer = 0 To picIn.Height-1
      c = surf.Pixel(x,y)
      
      If Alpha(c.Red,c.Green,c.Blue) > 3  Then '<- threshold
        surf.Pixel(x,y) = Color.Clear
      Else
        'surf.Pixel(x,y) = c
      End If
    Next
  Next
  
  Return picOut
  
End Function

Public Function Alpha(red as Integer, green as Integer, blue as Integer) As Integer
  'Color Difference Key
  
  Return green-Max(red,blue)
  
End Function

The edge areas are not yet ok
I still have to work manually

rem Line
If mend <> Nil Then
Var fx As Double = mypic.Width/Me.Width
Var fy As Double = mypic.Height/Me.height
Var x As Double = mend.xfx
Var y As Double = mend.y * fy
Var xx As Double = mstart.x
fx
Var yy As Double = mstart.y * fy
Var brx As Double = TextField4.Text.Val * fx
Var bry As Double = TextField4.Text.Val * fy
mypic.graphics.PenSize = brx
mypic.graphics.DrawingColor = Color.clear // rem Color.clear ??
mypic.graphics.drawline(xx-brx/2,yy-bry/2,xfx-brx/2,yfy-bry/2)

Var mymask As picture = mypic.copymask
mymask.graphics.PenSize = brx
mymask.graphics.DrawingColor = Color.White // transparent
mymask.graphics.drawline(xx-brx/2,yy-bry/2,xfx-brx/2,yfy-bry/2)
mypic.ApplyMask(mymask)

mend = Nil

End If

Thanks for sharing your code.
Your is faster than the one I came with (which would have been nice), but it’s also less precise (more pixels stay green).

I’m confused. Your code doesn’t compare against green at all and I fail to see when your code should be used (or what it exactly does).