I saw this thread and was fascinated by the code. It works! And its so simple!
Hats off to Cedron for the code, and to cogier for the example project.
And I agree with you Cedron. While the high level allows this to code to be short and simple, its also limiting for those who want to use webcam video to a fuller potential.
After much Googling, I found a great Gambas project that uses
gb.v4l to capture webcam video, instead of
gb.media.form. Cedron, this code is a step lower in level, and may be what you're looking for in trying to capture the current image to an Image object.
Thanks and credit for this Gambas project goes to
justlostintime, who uploaded it to GitHub 4 years ago.
https://github.com/justlostintime/gamba ... a/MyWebCam
The code loads and works great in Gambas 3.13.0. However, it does crash when I stop the capture, on the line
hWebCam = Null
The reason for the crash is unclear to me, but I modified it to
Try hWebCam = Null
and that seems to fix it. I didn't test every feature, so there could be other crashes due to the age of the code. I'm sure if the code were to be brought up to current-version specs (by someone more capable than me), it should work flawlessly.
Lastly, I should point out that the video source
/dev/video0
or
/dev/video1
can be unreliable. I found this out the hard way, using motion-activated security-camera software called
Motion.
My webcam can switch between the two at random, for no good reason. This switching would render my security software useless for hours at a time. I researched this, and found the solution is to use a symbolic link to your webcam, which never changes and can be created.
However, apparently most modern webcams will have like a "built-in" symbolic link, which has worked flawlessly for me. Its found under
/dev/v4l/by-id
so in my case I'd simply use
/dev/v4l/by-id/usb-Chicony_Electronics_Co._Ltd._USB2.0_HD_UVC_WebCam_0x0001-video-index0
in place of
/dev/videoX
This trick not only works for
Motion, but for these Gambas webcam code examples as well.
I hope
justlostintime's project is useful to Cedron and to everyone who finds this kind of thing interesting.
EDIT:
After posting this message, I played around with this project further. And to my dismay, I discovered that changing the webcam settings (i.e. brightness, contrast, whiteness, hue) appears to
alter the webcam settings permanently! I apologize for that. I'm providing code to properly initialize the sliders, and to reset your webcam settings to their default values.
1) Add a Public Sub Form_Open() and paste this code. This initializes each slider's min, max, and default values to match your webcam's specifications.
Dim TheStart As Integer
Dim TheLength As Integer
Dim TheResult As String
Dim TheLine As String[]
Dim TheCounter As Integer
OnSet = True
' Shell "v4l2-ctl -d /dev/video0 --list-ctrls" To TheResult
'or
Shell "v4l2-ctl -d " & Trim$(TxtDevice.Text) & " --list-ctrls" To TheResult
TheLine = Split(TheResult, gb.CrLf)
For TheCounter = 0 To TheLine.Max
TheStart = 0
TheLength = 0
TheLine[TheCounter] = Trim$(TheLine[TheCounter])
If IsNull(TheLine[TheCounter]) = False Then
If InStr(TheLine[TheCounter], "inactive", 1, gb.Binary) = 0 Then
Select Case True
Case InStr(TheLine[TheCounter], "brightness", 1, gb.IgnoreCase) > 0
TheStart = InStr(TheLine[TheCounter], "min=", 1, gb.Binary) + Len("min=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Bright.MinValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "max=", 1, gb.Binary) + Len("max=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Bright.MaxValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "step=", 1, gb.Binary) + Len("step=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Bright.Step = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
Case InStr(TheLine[TheCounter], "contrast", 1, gb.IgnoreCase) > 0
TheStart = InStr(TheLine[TheCounter], "min=", 1, gb.Binary) + Len("min=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Contrast.MinValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "max=", 1, gb.Binary) + Len("max=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Contrast.MaxValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "step=", 1, gb.Binary) + Len("step=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Contrast.Step = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
Case InStr(TheLine[TheCounter], "gamma", 1, gb.IgnoreCase) > 0 'whiteness
TheStart = InStr(TheLine[TheCounter], "min=", 1, gb.Binary) + Len("min=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Whiteness.MinValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "max=", 1, gb.Binary) + Len("max=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Whiteness.MaxValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "step=", 1, gb.Binary) + Len("step=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Whiteness.Step = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
Case InStr(TheLine[TheCounter], "hue", 1, gb.IgnoreCase) > 0
TheStart = InStr(TheLine[TheCounter], "min=", 1, gb.Binary) + Len("min=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Hue.MinValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "max=", 1, gb.Binary) + Len("max=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Hue.MaxValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "step=", 1, gb.Binary) + Len("step=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Hue.Step = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
Case InStr(TheLine[TheCounter], "saturation", 1, gb.IgnoreCase) > 0
TheStart = InStr(TheLine[TheCounter], "min=", 1, gb.Binary) + Len("min=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Colour.MinValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "max=", 1, gb.Binary) + Len("max=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Colour.MaxValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = InStr(TheLine[TheCounter], "step=", 1, gb.Binary) + Len("step=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
Colour.Step = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
End Select
Endif
Endif
Next
OnSet = False
2) Add a new button to that project. Call it Reset or whatever you like. Paste this code to its click event. This code resets your webcam's values for brightness, contrast, etc. to its default values.
Dim TheStart As Integer
Dim TheLength As Integer
Dim TheResult As String
Dim TheLine As String[]
Dim TheCounter As Integer
Dim TheDefault As Integer
Dim TheValue As Integer
Dim TheName As String
Dim TheMessage As String
' Shell "v4l2-ctl -d /dev/video0 --list-ctrls" To TheResult
'or
Shell "v4l2-ctl -d " & Trim$(TxtDevice.Text) & " --list-ctrls" To TheResult
TheLine = Split(TheResult, gb.CrLf)
OnSet = True
For TheCounter = 0 To TheLine.Max
TheLine[TheCounter] = Trim$(TheLine[TheCounter])
If IsNull(TheLine[TheCounter]) = False Then
If InStr(TheLine[TheCounter], "inactive", 1, gb.Binary) = 0 Then
TheStart = 0
TheLength = 0
TheName = Null
TheStart = 1
TheLength = InStr(TheLine[TheCounter], Space(1), 1, gb.Binary) - Len(Space(1))
TheName = Mid$(TheLine[TheCounter], TheStart, TheLength)
TheStart = 0
TheLength = 0
TheStart = InStr(TheLine[TheCounter], "default=", 1, gb.Binary) + Len("default=")
TheLength = InStr(TheLine[TheCounter], Space(1), TheStart, gb.Binary) - TheStart
TheDefault = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
TheStart = 0
TheLength = 0
TheStart = InStr(TheLine[TheCounter], "value=", 1, gb.Binary) + Len("value=")
TheLength = Len(TheLine[TheCounter])
TheValue = CInt(Mid$(TheLine[TheCounter], TheStart, TheLength))
If TheDefault <> TheValue Then
TheMessage &= TheName & " - Resetting " & CStr(TheValue) & " to " & CStr(TheDefault) & "." & gb.CrLf
Shell "v4l2-ctl -c " & TheName & "=" & CStr(TheDefault)
Select Case True
Case InStr(TheName, "brightness", 1, gb.IgnoreCase) > 0
Bright.Value = TheDefault
Case InStr(TheName, "contrast", 1, gb.IgnoreCase) > 0
Contrast.Value = TheDefault
Case InStr(TheName, "gamma", 1, gb.IgnoreCase) > 0
Whiteness.Value = TheDefault
Case InStr(TheName, "hue", 1, gb.IgnoreCase) > 0
Hue.Value = TheDefault
Case InStr(TheName, "saturation", 1, gb.IgnoreCase) > 0
Colour.Value = TheDefault
End Select
Endif
Endif
Endif
Next
OnSet = False
If IsNull(TheMessage) = False Then
Message(TheMessage)
Else
Message("Values are already set to their defaults. No changes are necessary.")
Endif
3) Optional, but its helpful to add these lines to the bottom of each respective slider _Change event. These lines of code show a tooltip for the respective slider that displays your webcam's minimum value, current value per the slider position, and maximum value.
Bright.Tooltip = Bright.MinValue & " - " & Bright.Value & " - " & Bright.MaxValue
Contrast.Tooltip = Contrast.MinValue & " - " & Contrast.Value & " - " & Contrast.MaxValue
Whiteness.Tooltip = Whiteness.MinValue & " - " & Whiteness.Value & " - " & Whiteness.MaxValue 'gamma
Colour.Tooltip = Colour.MinValue & " - " & Colour.Value & " - " & Colour.MaxValue
Hue.Tooltip = Hue.MinValue & " - " & Hue.Value & " - " & Hue.MaxValue
I hope you find these modifications useful. I apologize that I posted yesterday before realizing some major shortcomings in
justlostintime's otherwise awesome project. And before coding and posting proper modifications to the code (albeit probably crude, to more advanced coders).
Please feel free to post any further modifications and/or fixes to justlostintime's code.This stuff is quite cool!