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 )
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…
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.
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.
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!
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
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.xfx
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)
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).