Text overlay on a webcam

vb6 Romania
  • 13 years ago

    This has been annoying me for ages and I wonder if anyone could please help.  I am fairly new to Visual Basic, although I have done some quite advanced stuff with it I am learning it on the hoof and my knowledge is patchy.  I am using Visual Basic 2008.

    I am using a PictureBox to display a webcam image by creating a capture window (CapCreateCaptureWindowA) with the drawing styles WS_CHILD and WS_VISIBLE flags set.  The webcam works fine.  I am trying to overlay text directly on top of the webcam picturebox so that just the text appears and not the control background that the text is written on.  Everything I have tried has failed: A drawstring is written over by the webcam and any attempt to make a control transparent, even with the control parent set to the webcam picturebox either results in a 'hole' in the form or the background set to the form background.

    I have a couple of ideas this might be done however I cannot find anything on them and my lack of programming experience hinders me in exploring them further:

    1.  Apply WS_LAYERED or WS_TRANSPARENT to a control overlayed on the webcam picturebox? 

    2.  Change the Webcam  capture drawing style flags to prevent frames being drawn on top of the drawstring text?

    3.  Alpha blending a controls background with a pixel(s) close to the control on the webcam picturebox?

    4.  Send a Handle Message to the capture window including the text to be written?

     I really dont care how the text is written onto the capture window providing that it is just text with no background.  Help with this is much appreciated! Thank you.

      

  • 13 years ago

    Without sight of the code, it is tricky to be sure how you are filling the window with a picture.

    Quick thoughts:

    try doing a drawstring as the last action in the picturebox's Paint event, or maybe write the webcam image into the picturebox's background image property, and have a transparent label sitting over the top.

  • 13 years ago

    Thank you.  The iCam class is shown below.  Private myCam As New iCam is defined and the capturebox is establised by: myCam.InitCam(me.PictureBox.Handle.ToInt32). (The iCam Clase also has a copyframe subclass however this is irrelevent for the running of the camera and just captures a frame).  A parent must be supplied to CapCreateCaptureWindow and unfortunately, there is no paintevent which I could tap into.Ta

     

    Public Class iCam

    #Region "Api/constants"

    Private Const WS_CHILD As Integer = &H40000000

    Private Const WS_VISIBLE As Integer = &H10000000

    Private Const WM_USER As Short = &H400S

    Private Const WM_CAP_DRIVER_CONNECT As Integer = WM_USER + 10

    Private Const WM_CAP_DRIVER_DISCONNECT As Integer = WM_USER + 11

    Private Const WM_CAP_SET_PREVIEW As Integer = WM_USER + 50

    Private Const WM_CAP_SET_PREVIEWRATE As Integer = WM_USER + 52

    Private Const WM_CAP_START As Long = WM_USER

    Private Const WM_CAP_STOP As Long = (WM_CAP_START + 68)

    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Short, ByVal lParam As String) As Integer

    Private Declare Function capCreateCaptureWindowA Lib "avicap32.dll" (ByVal lpszWindowName As String, ByVal dwStyle As Integer, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Short, ByVal hWndParent As Integer, ByVal nID As Integer) As Integer

    Private Declare Function BitBlt Lib "GDI32.DLL" (ByVal hdcDest As IntPtr, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, ByVal dwRop As Int32) As Boolean

    #End Region

    Private iDevice As String

    Private hHwnd As Long

    Private lwndC As Integer

    Public iRunning As Boolean

    'Set-able parameters

    Private CamFrameRate As Integer = 24 'frames per second

    Private OutputHeight As Integer = 240 'Height of window

    Private OutputWidth As Integer = 360 'Width of window

    Public Sub resetCam()

    'resets the camera after setting change

    If iRunning Then

    closeCam()

    Application.DoEvents()

    If setCam() = False Then

    MessageBox.Show("Errror Setting/Re-Setting Camera")

    End If

    End If

    End Sub

    'Recieves hHWnd handle to set camera up

    Public Sub initCam(ByVal parentH As Integer)

    hHwnd = capCreateCaptureWindowA(iDevice, WS_VISIBLE Or WS_CHILD, 0, 0, OutputWidth, CShort(OutputHeight), parentH, 0)

    End Sub

    'Sets the Frame Rate of the Camera

    Public Sub setFrameRate(ByVal iRate As Long)CamFrameRate = CInt(1000 / iRate)

    resetCam()

    End Sub

    Private Function setCam() As Boolean

    If SendMessage(hHwnd, WM_CAP_DRIVER_CONNECT, CShort(iDevice), CType(0, String)) = 1 Then

    SendMessage(hHwnd, WM_CAP_SET_PREVIEWRATE, CShort(CamFrameRate), CType(0, String))

    SendMessage(hHwnd, WM_CAP_SET_PREVIEW, 1, CType(0, String))

    Me.iRunning = True

    Return True

    Else

    Me.iRunning = False

    Return False

    End If

    End Function

    Public Function closeCam() As Boolean

    closeCam = CBool(SendMessage(hHwnd, WM_CAP_DRIVER_DISCONNECT, 0, CType(0, String)))

    Me.iRunning = False

    End Function

    Public Function FPS() As Integer

    Return CInt(1000 / (CamFrameRate))

    End Function

    End Class

  • 13 years ago

    All pictureboxes have a paint event.

    Have you tried putting some code in it?

    It may be that the camera fills it then the normal paint event is handled by VB, in which case drawstring there will work.

    If the camera stuff gets the paint event second, then your text will appear and be replaced quickly by the update.

    Slowing down the refresh rate may help, as might adding a short loop after the drawstring.

     

    If all else fails, you could get the webcam to populate an offscreen picturebox, and copy the contents to another visible one , followed by the drawstring , as often as you like.

     

  • 13 years ago

    The Drawstring event seems to be 'ignored' as soon as the Capture window is established and the picturebox just displays the webcam image.  Also, slowing the frame rate down to 1 frame per second does not allow the drawstring to appear.  The Offscreen Picture Box also does not work, this may seem odd, but when I try to save the webcam image to an invisble picturebox and copy to a visible one every second or so, nothing appears.  I have managed to get text onto the webcam by this method, however the webcam picturebox must be visible and on the form which is not what I need.  As soon as I try to shrink the WebcamPictureBox or take it off screen then then the display picturebox does not show the picture updates (For example, if the webcamPictureBox is shrunk to half the size then the display picturebox will display only 1/2 the image)

    Cheers for your continued help 

     

  • 13 years ago

    Pity I dont have a webcam to try this out.

    It seems that your code actually creates a window as a child of the picturebox.

    You would normally make the child window the same size as the box.

    If the picture box is smaller than the image you get from the cam, you will see only the part that fits.

    If you grab the image from the picture box, you get waht the picture box gets.

    But the full picture lives in the child window, not the parent.

    The child can be identified by the hWnd created in the initialisation.

    You should be able to grab its data using the BitBlt function you have included, but you will probably need to add CreateDC and or GetDC to the mix, to turn the handle into a device context.

    Then your copy will be a BitBlt from the child window into your own, followed by a drawstring into your own.

    And that should (?) work even if the picturebox is positioned at -300 off your main form, as long as it is set to visible.

     

  • 13 years ago

    Cheers for your help with this.  I have managed it....although it seems a bit of a Jippo way of doing it.... Algorithm as follows:

    Set up a circular loop 1 - 20 with timer set fast (5)

    If loopcount = 1 send overlayed picturebox to the back

    If loopcount = 2 BitBlt the webcamdisplay at the coordinates of the overlayed picturebox and bring overlayed picturebox to front

    Drawstring with text in overlayed picturebox.

    It does flicker a little bit but as the text occupies a small area (scrolling text), and the 'transparency' is not quite accurate when the camera is moving around or the picture changes rapidly, it creates quite a good effect and is more than acceptable.

    The GetDC function was not required.

     Cheers for your help.Problem sorted.  

  • 11 years ago
    hello... i have the same problem.. please can you contact me asap directly to my email? adskippe(AT)gmail.com very very thanks!!! tony
  • 11 years ago
    sorry, i did a mistake in my email address... the correct is: adskipper(AT)gmail.com please please contact me!!!! regards tony

Post a reply

Enter your message below

Sign in or Join us (it's free).

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Weeks of coding can save you hours of planning.”