Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 16222
  • Last Modified:

Capturing a webcam image using directshow and saving it to a picture box image

The following VB.Net code, uses DirectShow to capture an image from a webcam and show it in a picture box. When the button 'Grab' is pressed, I want to capture the image into a second picture box.
It's just about working, except the image is not not set in the picture box. Clicking 'Grab' - returns 'nothing' as the picture box image.
If anyone can help - it would be much appreciated.

Regards

BeagleDog



Imports DirectShowLib
Imports System
Imports System.Diagnostics
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Runtime.InteropServices.ComTypes

Public Class Form1

    Dim D As Integer = Convert.ToInt32("0X8000", 16)
    Public WM_GRAPHNOTIFY As Integer = D + 1

    Dim VideoWindow As IVideoWindow = Nothing
    Dim MediaControl As IMediaControl = Nothing
    Dim MediaEventEx As IMediaEventEx = Nothing
    Dim GraphBuilder As IGraphBuilder = Nothing
    Dim CaptureGraphBuilder As ICaptureGraphBuilder2 = Nothing

    Enum PlayState
        Stopped
        Paused
        Running
        Init
    End Enum
    Dim CurrentState As PlayState = PlayState.Stopped

    Dim rot As DsROTEntry = Nothing

    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        closeinterfaces()
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        CaptureVideo()
        PictureBox1.Visible = True
    End Sub

    Private Sub CaptureVideo()
        Dim hr As Integer = 0
        Dim sourceFilter As IBaseFilter = Nothing
        Try
            GetInterfaces()

            hr = CaptureGraphBuilder.SetFiltergraph(GraphBuilder) 'Specifies filter graph "graphbuilder" for the capture graph builder "captureGraphBuilder" to use.

            sourceFilter = FindCaptureDevice()

            hr = GraphBuilder.AddFilter(sourceFilter, "Video Capture")

            hr = CaptureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, Nothing, Nothing)

            Marshal.ReleaseComObject(sourceFilter)

            SetupVideoWindow()

            rot = New DsROTEntry(GraphBuilder)

            hr = MediaControl.Run()

            CurrentState = PlayState.Running

        Catch ex As Exception
            MessageBox.Show("An unrecoverable error has occurred.With error : " & ex.ToString)
        End Try
    End Sub

    Private Sub GetInterfaces()
        Dim hr As Integer = 0
        GraphBuilder = CType(New FilterGraph, IGraphBuilder)
        CaptureGraphBuilder = CType(New CaptureGraphBuilder2, ICaptureGraphBuilder2)
        MediaControl = CType(GraphBuilder, IMediaControl)
        VideoWindow = CType(GraphBuilder, IVideoWindow)
        MediaEventEx = CType(GraphBuilder, IMediaEventEx)
        hr = MediaEventEx.SetNotifyWindow(Me.Handle, WM_GRAPHNOTIFY, IntPtr.Zero) 'This method designates a window as the recipient of messages generated by or sent to the current DirectShow object
    End Sub

    Public Function FindCaptureDevice() As IBaseFilter

        Dim hr As Integer = 0
        Dim classEnum As IEnumMoniker = Nothing
        Dim moniker As IMoniker() = New IMoniker(0) {}
        Dim source As Object = Nothing
        Dim devEnum As ICreateDevEnum = CType(New CreateDevEnum, ICreateDevEnum)
        hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, classEnum, 0)

        Marshal.ReleaseComObject(devEnum)
        If classEnum Is Nothing Then
            Throw New ApplicationException("No video capture device was detected.\r\n\r\n" & _
                           "This sample requires a video capture device, such as a USB WebCam,\r\n" & _
                           "to be installed and working properly.  The sample will now close.")
        End If
        If classEnum.Next(moniker.Length, moniker, IntPtr.Zero) = 0 Then
            Dim iid As Guid = GetType(IBaseFilter).GUID
            moniker(0).BindToObject(Nothing, Nothing, iid, source)
        Else
            Throw New ApplicationException("Unable to access video capture device!")
        End If
        Marshal.ReleaseComObject(moniker(0))
        Marshal.ReleaseComObject(classEnum)
        Return CType(source, IBaseFilter)
    End Function

    Public Sub SetupVideoWindow()
        Dim hr As Integer = 0
        'set the video window to be a child of the main window
        'putowner : Sets the owning parent window for the video playback window. 
        hr = VideoWindow.put_Owner(PictureBox1.Handle) 'Me.Handle)
        PictureBox1.Visible = False

        hr = VideoWindow.put_WindowStyle(WindowStyle.Child Or WindowStyle.ClipChildren)

        'Use helper function to position video window in client rect of main application window
        ResizeVideoWindow()

        'Make the video window visible, now that it is properly positioned
        'put_visible : This method changes the visibility of the video window. 
        hr = VideoWindow.put_Visible(OABool.True)

    End Sub

    Public Sub ResizeVideoWindow()
        'Resize the video preview window to match owner window size
        'left , top , width , height
        If Not (VideoWindow Is Nothing) Then 'if the videopreview is not nothing
            VideoWindow.SetWindowPosition(0, 0, Me.Width, Me.ClientSize.Height)
        End If
    End Sub

    Public Sub closeinterfaces()
        '//stop previewing data
        If Not (Me.MediaControl Is Nothing) Then
            Me.MediaControl.StopWhenReady()
        End If

        Me.CurrentState = PlayState.Stopped

        '//stop recieving events
        If Not (Me.MediaEventEx Is Nothing) Then
            Me.MediaEventEx.SetNotifyWindow(IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero)
        End If

        '// Relinquish ownership (IMPORTANT!) of the video window.
        '// Failing to call put_Owner can lead to assert failures within
        '// the video renderer, as it still assumes that it has a valid
        '// parent window.
        If Not (Me.VideoWindow Is Nothing) Then
            Me.VideoWindow.put_Visible(OABool.False)
            Me.VideoWindow.put_Owner(IntPtr.Zero)
        End If

        ' // Remove filter graph from the running object table
        If Not (rot Is Nothing) Then
            rot.Dispose()
            rot = Nothing
        End If

        '// Release DirectShow interfaces
        Marshal.ReleaseComObject(Me.MediaControl) : Me.MediaControl = Nothing
        Marshal.ReleaseComObject(Me.MediaEventEx) : Me.MediaEventEx = Nothing
        Marshal.ReleaseComObject(Me.VideoWindow) : Me.VideoWindow = Nothing
        Marshal.ReleaseComObject(Me.GraphBuilder) : Me.GraphBuilder = Nothing
        Marshal.ReleaseComObject(Me.CaptureGraphBuilder) : Me.CaptureGraphBuilder = Nothing

    End Sub

    Private Sub btnGrab_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGrab.Click
        GrabImage()
    End Sub

    Public Sub GrabImage()
        '
        ' Get image from clipboard and convert it to a bitmap
        Try
            MediaControl.Pause()

            Clipboard.SetImage(PictureBox1.Image)
            '
            If Clipboard.ContainsImage Then
                PictureBox2.Image = Clipboard.GetImage()
            End If
        Catch
        End Try
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MediaControl.Run()
    End Sub
End Class

Open in new window

0
BeagleDog
Asked:
BeagleDog
  • 2
  • 2
1 Solution
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
The .Image() property in your PictureBox is never actually used for the webcam video rendering!...

One approach is to simply grab a screenshot of your PictureBox:
Public Sub GrabImage()
        Try
            MediaControl.Pause()
            Dim bmp As New Bitmap(PictureBox1.Width, PictureBox1.Height)
            Using g As Graphics = Graphics.FromImage(bmp)
                Dim pt As Point = PictureBox1.PointToScreen(New Point(0, 0))
                g.CopyFromScreen(pt.X, pt.Y, 0, 0, bmp.Size)
            End Using
            PictureBox2.Image = bmp
            MediaControl.Run()
        Catch
        End Try
    End Sub

Open in new window

0
 
BeagleDogAuthor Commented:
Looks good - modified the code as below - but the PictureBox2 is completely empty 'grey'. It appears that PictureBox1 is 'nothing'...............(that's what I am seeing when I place a code break........)

Thanks for your help - very much appreciate it.

Regards

BeagleDog
Public Sub GrabImage()
        '
        ' Get image from clipboard and convert it to a bitmap
        'Try
        'MediaControl.Pause()

        'Clipboard.SetImage(PictureBox1.Image)
        '
        'If Clipboard.ContainsImage Then
        'PictureBox2.Image = Clipboard.GetImage()
        'End If
        'Catch
        'End Try

        Try
            MediaControl.Pause()
            PictureBox1.Visible = False

            Dim bmp As New Bitmap(PictureBox1.Width, PictureBox1.Height)
            Using g As Graphics = Graphics.FromImage(bmp)
                Dim pt As Point = PictureBox1.PointToScreen(New Point(0, 0))
                g.CopyFromScreen(pt.X, pt.Y, 0, 0, bmp.Size)
            End Using
            PictureBox2.Image = bmp
            PictureBox2.Visible = True
            'MediaControl.Run()
        Catch
        End Try

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MediaControl.Run()
        PictureBox1.Visible = True
        PictureBox2.Visible = False
    End Sub

Open in new window

0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
You can't expect to get a screenshot of PictureBox if you hide it first!

            PictureBox1.Visible = False

Hide it AFTER you've got the screenshot:   =)


Public Sub GrabImage()
        Try
            MediaControl.Pause()

            Dim bmp As New Bitmap(PictureBox1.Width, PictureBox1.Height)
            Using g As Graphics = Graphics.FromImage(bmp)
                Dim pt As Point = PictureBox1.PointToScreen(New Point(0, 0))
                g.CopyFromScreen(pt.X, pt.Y, 0, 0, bmp.Size)
            End Using
            PictureBox2.Image = bmp
            PictureBox2.Visible = True

            PictureBox1.Visible = False
        Catch
        End Try
    End Sub

Open in new window

0
 
BeagleDogAuthor Commented:
That was easy! Excellent - thanks very much - really appreciate it.

Regards

Beagle Dog
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now