Solved

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

Posted on 2011-03-09
4
15,738 Views
Last Modified: 2012-05-11
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
Comment
Question by:BeagleDog
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
  • 2
4 Comments
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 35090059
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
 

Author Comment

by:BeagleDog
ID: 35090352
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
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 500 total points
ID: 35090446
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
 

Author Closing Comment

by:BeagleDog
ID: 35090535
That was easy! Excellent - thanks very much - really appreciate it.

Regards

Beagle Dog
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
In this video, viewers are given an introduction to using the Windows 10 Snipping Tool, how to quickly locate it when it's needed and also how make it always available with a single click of a mouse button, by pinning it to the Desktop Task Bar. Int…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question