» Primeiros passos com OpenCV e Emgu - Acessando a webcam
03/12/2016    C#.NET

Olá!
Nesse artigo vou falar um pouco sobre a OpenCV e como dar os primeiros passos com essa biblioteca utilizando a linguagem C#.NET acessando a webcam.
O que vou mostrar nesse artigo é como preparar o ambiente para utilizar a biblioteca, visualizar os exemplos das funcionalidades e como ter acesso a webcam do computador dentro do seu projeto desktop.


Introdução à OpenCV

A OpenCV(Open Source Computer Vision) é uma biblioteca sob a licença BSD, então pode ser utilizada livremente para fins acadêmicos ou comerciais.
Essa biblioteca possui poderosos algoritmos de visões computacionais, como por exemplo reconhecimento facial, de placas de veículos, de formas, pequenas reconstruções 3D a partir de uma imagem em 2D, recriação de uma imagem a partir de várias, detecção de movimentos etc. Seu foco é nesse tipo de funcionalidade e em tempo real, é usado em desde aplicativos recreativos até robóticos.
Mais adiante nesse artigo ainda vou mostrar como visualizar facilmente exemplos de todas essas funcionalidades.
Mais informações em http://opencv.org/.


Introdução ao Emgu

A biblioteca OpenCV suporta Windows, Linux, Mac OS, iOS e Android, porém somente tem interface para as linguagens C++, C, Python e Java.
Devido a necessidade de se trabalhar com a bilioteca nas linguagens da prataforma .NET foi criado o Emgu, que é um wrapper da biblioteca OpenCV.
Mais informações em http://www.emgu.com/wiki/index.php/Main_Page.


Acessando os Exemplos de Funcionalidades

Para termos uma visão mais clara das funcionalidades da biblioteca vamos baixar o Emgu e visualizar seus exemplos, acesse o link para download: https://sourceforge.net/projects/emgucv/

Após a instalação concluída acesse a pasta Emgu.CV.Example; Nela você verá exemplos de vários algoritmos da OpenCV porém sendo utilizadaos em C# através do nosso amigo Emgu, basta acessar a pasta de alguma e então abrir o projeto, como por exemplo o projeto LicensePlateRecognition:


Preparando o Projeto

Como quase todas as funcionalidades do OpenCV utilizam uma imagem ou vídeo em tempo real, o princípio é utilizarmos a webcam.
Na própria pasta de exemplos existe um projeto chamado CameraCapture na qual existe na tela a imagem da webcam e também aplica vários efeitos em tempo real, caso seu objetivo seja somente visualizar a imagem, este projeto pronto pode lhe servir, porém nesse artigo vou explicar passo a passo desse mesmo processo e também como salvar a imagem da webcam no seu computador.

Então vamos criar um novo projeto do tipo Windows Forms Application. O Emgu que instalamos não é necessário para desenvolver nem para rodar a aplicação final, somente o fizemos para termos acesso aos seus exemplos que com certeza são de grande ajuda.
Em nosso projeto iremos instalar o Emgu através do Nuget, para isso abra o Package Manager Console e execute o comando Install-Package EmguCV.

Mais informações sobre esse pacote: https://www.nuget.org/packages/EmguCV/

Adicione as seguintes referências:

            using Emgu.CV;
            using Emgu.CV.CvEnum;
            using Emgu.CV.Structure;
            using Emgu.Util;
        


Criando os Componentes

Adicione no form 3 botões, com os noms de: btnMostrar, btnParar e btnSalvar.
Posicione os elementos da seguinte forma:

O próximo passo é criarmos o componente especial que irá mostrar a imagem da webcam capturada pelo OpenCV.
Iremos criar esse objeto somente por código, pois é um objeto do tipo Emgu.CV.UI.ImageBox, que não se encontra na Toolbox padrão.
Abra o arquivo o Form.Designer.CS.

Dentro do bloco InitializeComponent vamos inserir 3 blocos de códigos:
No começo, antes de this.SuspendLayout(); iremos inserir:

            this.CamImageBox = new Emgu.CV.UI.ImageBox();
            ((System.ComponentModel.ISupportInitialize)(this.CamImageBox)).BeginInit();
        

O código a cima faz com que o nosso componente especial seja criado e logo inicializado.

Antes de // Form1 insira o seguinte bloco de código:

            //
            // CamImageBox
            //
            this.CamImageBox.BackColor = System.Drawing.Color.Transparent;
            this.CamImageBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.CamImageBox.Location = new System.Drawing.Point(13, 13);
            this.CamImageBox.Name = "CamImageBox";
            this.CamImageBox.Size = new System.Drawing.Size(390, 265);
            this.CamImageBox.TabIndex = 2;
            this.CamImageBox.TabStop = false;
        
O código a cima estabelece as configurações do nosso componente, não se preocupe pois poderemos alterar essas configurações mais a frente através da paleta do Visual Studio.

O próximo bloco de códigos será o responsável por incluir o componente dentro do nosso Form, deve ser inserido após o bloco // Form1:

            this.Controls.Add(this.CamImageBox);
        

E por fim, antes do comando private System.Windows.Forms.Button btnMostrar; devemos inserir o código:
            private Emgu.CV.UI.ImageBox CamImageBox;
        

O código do seu arquivo Form.Designer.cs deve estar da seguinte forma:

                        namespace TesteAcessoCamera
{
    partial class Form1
    {
        /// 
        /// Required designer variable.
        /// 
        private System.ComponentModel.IContainer components = null;
        
        /// 
        /// Clean up any resources being used.
        /// 
        /// true if managed resources should be disposed; otherwise, false.
        
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code
        /// 
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// 
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.btnMostrar = new System.Windows.Forms.Button();
            this.btnSalvar = new System.Windows.Forms.Button();
            this.btnParar = new System.Windows.Forms.Button();
            this.CamImageBox = new Emgu.CV.UI.ImageBox();
            ((System.ComponentModel.ISupportInitialize)(this.CamImageBox)).BeginInit();
            this.SuspendLayout();
            // 
            // btnMostrar
            // 
            this.btnMostrar.Location = new System.Drawing.Point(409, 12);
            this.btnMostrar.Name = "btnMostrar";
            this.btnMostrar.Size = new System.Drawing.Size(75, 37);
            this.btnMostrar.TabIndex = 1;
            this.btnMostrar.Text = "Mostrar";
            this.btnMostrar.UseVisualStyleBackColor = true;
            this.btnMostrar.Click += new System.EventHandler(this.btnMostrar_Click);
            // 
            // btnSalvar
            // 
            this.btnSalvar.Location = new System.Drawing.Point(409, 242);
            this.btnSalvar.Name = "btnSalvar";
            this.btnSalvar.Size = new System.Drawing.Size(75, 37);
            this.btnSalvar.TabIndex = 2;
            this.btnSalvar.Text = "Salvar";
            this.btnSalvar.UseVisualStyleBackColor = true;
            this.btnSalvar.Click += new System.EventHandler(this.btnSalvar_Click);
            // 
            // btnParar
            // 
            this.btnParar.Location = new System.Drawing.Point(409, 55);
            this.btnParar.Name = "btnParar";
            this.btnParar.Size = new System.Drawing.Size(75, 36);
            this.btnParar.TabIndex = 3;
            this.btnParar.Text = "Parar";
            this.btnParar.UseVisualStyleBackColor = true;
            this.btnParar.Click += new System.EventHandler(this.btnParar_Click);
            // 
            // CamImageBox
            // 
            this.CamImageBox.BackColor = System.Drawing.Color.Transparent;
            this.CamImageBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.CamImageBox.Location = new System.Drawing.Point(13, 13);
            this.CamImageBox.Name = "CamImageBox";
            this.CamImageBox.Size = new System.Drawing.Size(390, 265);
            this.CamImageBox.TabIndex = 2;
            this.CamImageBox.TabStop = false;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(497, 290);
            this.Controls.Add(this.btnParar);
            this.Controls.Add(this.btnSalvar);
            this.Controls.Add(this.btnMostrar);
            this.Controls.Add(this.CamImageBox);
            this.Name = "Form1";
            this.Text = "Form1";
            ((System.ComponentModel.ISupportInitialize)(this.CamImageBox)).EndInit();
            this.ResumeLayout(false);
        }
        #endregion

        private Emgu.CV.UI.ImageBox CamImageBox;
        private System.Windows.Forms.Button btnMostrar;
        private System.Windows.Forms.Button btnSalvar;
        private System.Windows.Forms.Button btnParar;
    }
}
        
Sendo que o que alteramos foi nas linhas: 35, 69, 87 e 95.

Agora vá no designer do formulário, o componente responsável por mostrar a captura da webcam já irá aparecer, altere o tamanho dele para o tamanho que deseja:

Execute o projeto somente para ter certeza de que não houve nenhum erro ao inserir esse componente, se ao executar nenhum erro for mostrado então está tudo certo, obviamente não mostrará a imagem da webcam pois ainda não programamos.


Programando

Agora vamos dar comandos para o 3 botões, como são comandos pequenos, eu incluí todo o código do formulário abaixo:

namespace TesteAcessoCamera
{
    public partial class Form1 : Form
    {
        private Capture _capture = null;
        private bool _salvar = true;

        public Form1()
        {
            InitializeComponent();
        }

        private void ProcessFrame(object sender, EventArgs arg)
        {
            Mat frame = new Mat();
            _capture.Retrieve(frame, 0);
            CamImageBox.Image = frame;
            
            if (_salvar)
            {
                frame.Save(@"captura.jpg");
                _salvar = false;
            }
        }

        private void btnMostrar_Click(object sender, EventArgs e)
        {
            CvInvoke.UseOpenCL = false;
            try
            {
                _capture = new Capture();
                _capture.ImageGrabbed += ProcessFrame;
                Application.Idle += ProcessFrame;
            }
            catch (NullReferenceException excpt)
            {
                MessageBox.Show(excpt.Message);
            }
        }

        private void btnParar_Click(object sender, EventArgs e)
        {
            _capture.ImageGrabbed -= ProcessFrame;
            Application.Idle -= ProcessFrame;
            _capture = null;
            CamImageBox.Image = null;
        }

        private void btnSalvar_Click(object sender, EventArgs e)
        {
            _salvar = true;
        }
    }
}
        
A ação do botão btnMostrar inicia a captura utilizando a variável _capture; Reparem que ela utiliza a funçao ProcessFrame, esse procedimento é chamado a cada imagem capturada da webcam e é ele quem vai jogar a imagem na tela ou então salvá-la no computador.
O botão de parar vai desfazer as ações iniciadas no botão de mostrar e o botão de salvar vai simplesmente setar uma variável para true, essa variável será lida durante o mencionado ProcessFrame, que é quem vai processar a imagem.

Bem simples né?
Agora vamos rodar!

O básico já está feito, acesso a webcam e salvamento da imagem capturada, vamos seguir para um próximo nível agora.


Aplicando Efeitos à Imagem

Dentro do procedimento ProcessFrame nós podemos aplicar alguns efeitos, abaixo o código de um exemplo:

            private void ProcessFrame(object sender, EventArgs arg)
            {
                // Normal, sem efeitos
                Mat frame = new Mat();
                _capture.Retrieve(frame, 0);
                CamImageBox.Image = frame;

                // Somente as linhas
                Mat grayFrame = new Mat();
                CvInvoke.Canny(frame, grayFrame, 100, 60);
                CamImageBox.Image = grayFrame;
            
                if (_salvar)
                {
                    frame.Save(@"captura.jpg");
                    _salvar = false;
                }
            }
        


Além disso podemos virar a imagem verticalmente ou horizontalmente:

            private void btnMostrar_Click(object sender, EventArgs e)
            {
                CvInvoke.UseOpenCL = false;
                try
                {
                    _capture = new Capture();
                    
                    // Vira a captura verticalmente
                    _capture.FlipVertical = _capture.FlipHorizontal = !_capture.FlipHorizontal;
                    // Vira a captura horizontalmente
                    _capture.FlipVertical = _capture.FlipVertical = !_capture.FlipVertical;
                    
                    _capture.ImageGrabbed += ProcessFrame;
                    Application.Idle += ProcessFrame;
                }
                catch (NullReferenceException excpt)
                {
                    MessageBox.Show(excpt.Message);
                }
            }
        

É possível também misturar os efeitos, deixar a imagem somente com suas linhas e virá-la de cabeça para baixo por exemplo.

Espero que tenha gostado de mais esse artigo, você pode baixar o projeto completo através do meu GitHub no link abaixo:
https://github.com/FabricioLeite/AccessWebcamOpenCV

Estou trabalhando a algum tempo em um projeto de reconhecimento em tempo real de placas de veículos, espero em breve compartilhar outro artigo com vocês mostrando essa técnica.
Um abraço!




Comentários