VB .NET - Capturando imagens de uma WebCam


Este é um exemplo para captura de imagens de uma WebCam para VB.NET (VB 2005) , veja a versão para o VB6 no link:  VB6 -  Capturando imagens de uma WebCam.

Se você tiver a curiosidade de comparar o projeto VB6 com o projeto VB.NET perceberá que usamos a mesma API.

No VB 2005 Express  o projeto irá usar as APIs do Windows para efetuar a captura de vídeo. A DLL avicap32.dll possui funções  para conexão e obtenção de dispositivos de vídeos instalados no sistema Windows. As funções usadas serão:

a- capCreateCaptureWindowA
b- capGetDriverDescriptionA
c- SendMessage
d- SetWindowPos
e- DestroyWindow

Veja também a colaboração : VB - Usando uma Webcam. para obter detalhes das APIs usadas.

A seguir temos uma pequena explanação do processo como um todo:

O processo de captura de vídeo começa com a função capCreateCaptureWindowA. Quando chamada, esta função retorna um handle(identificador) para a nova janela. O handle(identificador) é um número de 32-bits que é usado para referenciar um objeto (neste caso, uma janela). Este handle é o fundamento para o restante do seu programa, e deve ser mantido em um local seguro.

Uma vez que a janela de captura é criada, você pode conectar a janela ao driver de vídeo. O driver de vídeo é instalado juntamente com sua câmera de vídeo. A conexão é feita com a mensagem WM_CAP_DRIVER_CONNECT. Isto irá "preencher" a janela com o primeiro driver de vídeo encontrado (índice 0).

Tenha em mente que poderia enviar esta mensagem para qualquer janela, mas somente esta janela especialmente criada com a capCreateCaptureWindow entenderá o que você está falando.

SendMessage lwnd, WM_CAP_DRIVER_CONNECT, 0, 0

A API SendMessage é sempre chamada passando-se 4 parâmetros:

1 - Um handle(identificador) de janela (hwnd);
2 - Alguma mensagem para enviar à esta janela (wMsg);
3 - Um parâmetro (wParam) - 16-bits.
4 - E parâmetro (lParam) - 32-bits.

Veja também meu artigo : API - Abrindo e fechando janelas MS-DOS

Vamos agora por a
'mão na massa' :

Inicie um novo projeto no Visual Basic 2005 Express do tipo Windows Application com o nome de WebCam e no formulário padrão form1.vb inclua os componentes: ListBox, PictureBox e Button conforme o leiaute da figura abaixo:

Para iniciar declare o namespace : Imports System.Runtime.InteropServices;

A seguir vamos declarar as funções das APIs usadas e as constantes relacionadas no formulário:

'constantes usadas na DLL
Const WM_CAP As Short = &H400S

Const WM_CAP_DRIVER_CONNECT As Integer = WM_CAP + 10
Const WM_CAP_DRIVER_DISCONNECT As Integer = WM_CAP + 11
Const WM_CAP_EDIT_COPY As Integer = WM_CAP + 30

Const WM_CAP_SET_PREVIEW As Integer = WM_CAP + 50
Const WM_CAP_SET_PREVIEWRATE As Integer = WM_CAP + 52
Const WM_CAP_SET_SCALE As Integer = WM_CAP + 53
Const WS_CHILD As Integer = &H40000000
Const WS_VISIBLE As Integer = &H10000000
Const SWP_NOMOVE As Short = &H2S
Const SWP_NOSIZE As Short = 1
Const SWP_NOZORDER As Short = &H4S
Const HWND_BOTTOM As Short = 1

Dim iDevice As Integer = 0 ' ID do dispositivo atual
Dim hHwnd As Integer ' manipulador da janela do visualizador

Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer,  <MarshalAs(UnmanagedType.AsAny)> ByVal lParam As Object) As Integer

Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Integer, _
ByVal hWndInsertAfter As Integer, ByVal x As Integer, ByVal y As Integer,  ByVal cx As Integer, ByVal cy As Integer, ByVal wFlags As Integer) As Integer

'A função DestroyWindow destroi a janela especificada.
'Envia as mensagens WM_DESTROY e WM_NCDESTROY para a
'janela para destivá-la e remove o foco do teclado da mesma
'Library - User32
'Parametros - hWnd - (identica a janela a ser destruida)
'Retorna um valor diferente de zero se for executada com sucesso, 'caso contrario retorna zero

Declare Function DestroyWindow Lib "user32" (ByVal hndw As Integer) As Boolean


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

Declare Function capGetDriverDescriptionA Lib "avicap32.dll" (ByVal wDriver As Short, _
ByVal lpszName As String, ByVal cbName As Integer, ByVal lpszVer As String, ByVal cbVer As Integer) As Boolean

Agora vamos definir o código para cada evento :

1- No evento Load do formulário vamos definir a carga dos dispositivos e a exibição do nome do mesmo no ListBox;

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'verifica e carrega os dispositivos
carregaDispositivos()

' se encontrou dispostivos instalados então exibe

If lstDispositivos.Items.Count > 0 Then
    btnIniciar.Enabled = True
    lstDispositivos.SelectedIndex = 0
    btnIniciar.Enabled = True
Else
    lstDispositivos.Items.Add("Não dispositivo de captura instalado.")
    btnIniciar.Enabled = False
End If

btnParar.Enabled = False
btnSalvar.Enabled = False
picCaptura.SizeMode = PictureBoxSizeMode.StretchImage
End Sub

A rotina carregaDispositivos() possui o seguinte código:

Private Sub carregaDispositivos()
Dim strNome As String = Space(100)
Dim strVer As String = Space(100)
Dim bRetorna As Boolean
Dim x As Integer = 0

'
' Carrega os dispositivos em lstDevices
Do

' Obtem o nome e a versão Driver
bRetorna = capGetDriverDescriptionA(x, strNome, 100, strVer, 100)

' se existir um dispositivo inclui o nome da lista

If bRetorna Then lstDispositivos.Items.Add(strNome.Trim)
    x += 1
Loop Until bRetorna = False
End Sub

Na rotina abreJanelaVisualização() iremos conectar com o drive e exibir as informações;

Private Sub abreJanelaVisualizacao()
Dim iHeight As Integer = picCaptura.Height
Dim iWidth As Integer = picCaptura.Width

' Abre a janela de visualização no picturebox
hHwnd = capCreateCaptureWindowA(iDevice, WS_VISIBLE Or WS_CHILD, 0, 0, 640, _
480, picCaptura.Handle.ToInt32, 0)

' Conecta com o drive
If SendMessage(hHwnd, WM_CAP_DRIVER_CONNECT, iDevice, 0) Then
'
'Define a escala de previsão
SendMessage(hHwnd, WM_CAP_SET_SCALE, True, 0)

'Define a taxa de visualização em milisegundos
SendMessage(hHwnd, WM_CAP_SET_PREVIEWRATE, 66, 0)

'Iniciar a visualização da imagem a partir da camara
SendMessage(hHwnd, WM_CAP_SET_PREVIEW, True, 0)

' Redimensiona a janela para se ajustar no picturebox
SetWindowPos(hHwnd, HWND_BOTTOM, 0, 0, picCaptura.Width, picCaptura.Height, SWP_NOMOVE Or SWP_NOZORDER)

btnSalvar.Enabled = True
btnParar.Enabled = True
btnIniciar.Enabled = False
Else
'
' Erro de conexão fecha a janela de dispostivos

DestroyWindow(hHwnd)

btnSalvar.Enabled = False
End If
End Sub

O código do evento Click do botão iniciar abre a janela de visualização após obter o dispositivo instalado

Private Sub btnIniciar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnIniciar.Click
    iDevice = lstDispositivos.SelectedIndex
   abreJanelaVisualizacao()
End Sub

A rotina fechaJanelaVisualização() envia uma mensagem para desconexão da janela e destrói a janela;

Private Sub fechaJanelaVisualizacao()
 
 ' Desconecta do dispositivo
  SendMessage(hHwnd, WM_CAP_DRIVER_DISCONNECT, iDevice, 0)

  ' fecha a chama a janela

  DestroyWindow(hHwnd)
End Sub
 

No evento Click do botão Parar fechamos a janela e definimos o estado de habilitação dos botões:

Private Sub btnParar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnParar.Click
   fechaJanelaVisualizacao()
   btnSalvar.Enabled = False
   btnIniciar.Enabled = True
   btnParar.Enabled = False
End Sub

O código do evento Click do botão Salvar é o seguinte:

Private Sub btnSalvar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSalvar.Click
Dim dados As IDataObject
Dim bmap As Image

' Copia a imagem para o clipboard
SendMessage(hHwnd, WM_CAP_EDIT_COPY, 0, 0)

' Obtem a imagem do clipboard e converte para bitmap

dados = Clipboard.GetDataObject()

If dados.GetDataPresent(GetType(System.Drawing.Bitmap)) Then
   bmap = CType(dados.GetData(GetType(System.Drawing.Bitmap)), Image)
   picCaptura.Image = bmap
   fechaJanelaVisualizacao()
    btnSalvar.Enabled = False
    btnParar.Enabled = False
    btnIniciar.Enabled = True

     If sfdImage.ShowDialog = System.Windows.Forms.DialogResult.OK Then
          bmap.Save(sfdImage.FileName, Imaging.ImageFormat.Bmp)
     End If

End If
End Sub

Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
If btnParar.Enabled Then
     fechaJanelaVisualizacao()
End If
End Sub

Executando o projeto e acionando o dispositivo da Webcam  (Estou usando uma Microsoft LifeCam) iremos obter: 

Pegue o projeto aqui:  webCamNet.zip

Veja neste artigo como usar este recurso em um cadastro de clientes para capturar a foto do cliente:

Até o próximo artigo ...

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

 Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter
 

Referências:


José Carlos Macoratti