2013年3月22日星期五

Visual C++编程实现摄像头视频捕捉

VS6.0年代,微软提供了VFW(Video For Window) 这样强大而方便的库来支持视频捕获和回放。但是无论是在。NET v1.0 还是在.NET v2.0框架中,都没有提供相应的类库来支持视频捕获和回放。解决这个问题有很多种方法,比如利用平台调用P/Invoke对VFW中的功能函数进行封 装,然后再C#中进行调用。这样效率很低并且太复杂。还可以利用第三方提供的ActiveX控件来实现这个功能,这有什么好处呢?简单!!!!这也就足够 了。并且往往第三方提供的控件功能更强大。但是世界上没有免费的午餐——这种控件往往是要收费的。在这里肯定有的朋友会想到:“不是还可以利用 DX(DirectX)来实现吗,微软也提供了Manager DX托管代码的SDK”。的确,利用DX来实现视频捕获和回放是一个很好的方法,无论从效率还是效果来说都是上上之选。不幸的是:微软虽然提供了D3D、 DirectDraw、DirectSound、DirectPlayer......但是唯独没有我们感兴趣的,可以实现视频捕获的 DirectShow的SDK。据我所知,国外有开源的代码对DirectShow进行了封装,我也用过,个人感觉还不错,有兴趣的朋友可以查找一下这方 面的资料,这里我就不多说了。
        言归正传,要利用ActiveX在C#中实现视频捕获,先要做好以下准备工作:
首先是要有VS2003或者VS2005的开发环境,这个我就不多说,相信地球人都知道。
其次是要安装好摄像头的驱动程序,也就是说你在QQ或者MSN视频聊天时能看到你自己摄像头的图像。
然 后是最重要的了:安装支持视频捕获的ActiveX控件!什么控件?Pegasus CapturePro。哪里下载?下载地址:http://www.cncode.com/downinfo/3504.html 这个地址应该是可以下载的,我刚刚又测试了一次。但是我不能保证它一直有效。这个控件是收费的,网上有它的评估版,相信大家也有办法,实在不行,那么给我 发Email吧,我来告诉你怎么办。安装时一直"Next"下去后就可以了。
        在VS2003中新建一个“Windows 应 用程序”工程,工程建立后,首先要向“工具箱”中添加ActiveX控件具体方法是在VS2003菜单的“工具”菜单中单击“添加/移除工具箱项”。在 弹出的对话框中选择“COM 组件”选项卡,在下面的列表框中,将“Pegasus Imaging CapturePRO Control v3.0”前面的复选框选中,然后单击“确定”返回编译器编辑界面就可以了。然后将刚刚添加的控件拖放到窗体上调整好大小和位置,在属性页中修改属性。修 改属性的方法和普通控件一样,至于各个属性的含义可以参考控件的帮助文档。控件所有的方法、属性和事件在帮助文档中都有详细的说明。这里建议修改其 “Name”属性,方便以后操作,比如将Name属性改为axCap(以后axCap都表示该控件)。将axCap的Size属性改为320,240。因 为很多摄像头的默认分辨率是320X240。窗体布局大概如下图:
        然后再窗体上放一个Button控件,在该控件的单击事件中添加以下代码:
view plaincopy to clipboardprint?
private void butConnect_Click(object sender, System.EventArgs e)  
...{  
    axCap.Connect (0);        // 连接到设备  
    axCap.Preview = true;        // 开始预览  

private void butConnect_Click(object sender, System.EventArgs e)
...{
    axCap.Connect (0);        // 连接到设备
    axCap.Preview = true;        // 开始预览
}
        然后编译工程,允许程序,单击按钮应该就可以看到视频图像了。
         到这里就表示我们的操作成功了,最基本的功能实现了,这里对上述两行代码进行简单的解释。第一行axCap.Connect(0)表示将控件连接到设备 0。在Windows中,可以同时支持多个视频设备,每个设备都有一个编号。第一个设备编号0,第二个设备编号1,依次类推。由于我的电脑上只连接了一个 视频摄像头,所以视频设备的编号是0。这里也就可以看出Connect()函数的参数实际上就是视频设备的参数,至于怎样来确定视频设备对于得编号,下面 会有详细的说明。第二行axCap.Preview = true;表示打开预览。Preview属性为真时表示在控件上显示视频图像,当然要是该属性为false,我们就看不到视频了。

        下面对一些常用的,比较重要的方法和属性进行说明:
         怎样确定视频设备的编号:首先利用属性axCap .NumDevices来获取Windows中可用视频设备的数目,然后利用方法axCap .ObtainDeviceName (i)来获取该设备的名称字符串。其中参数i同Connect()函数一样,表示视频设备编号。具体的方法和实现过程可以参考以下代码:
view plaincopy to clipboardprint?
//判断有没用可用的捕获设备  
if(axCap .NumDevices <0)  
 
{  
    //没有找到可用的视频设备则报错,并退出程序  
    MessageBox.Show ("没有发现可用的设备!","错误",MessageBoxButtons.OK ,MessageBoxIcon.Error );  
    cobDevice.Items .Add("未发现可用视频设备");  
    cobDevice.SelectedIndex =0;  
}  
else 
{  
    //找到则枚举所以设备,并初始化设备组合框  
    try 
    {  
        for(int i=0;i<axCap .NumDevices ;i++)  
        {  
            cobDevice.Items .Add (axCap .ObtainDeviceName (i));  
        }  
        cobDevice.SelectedIndex =0;    //设置默认设备  
    }  
    catch 
    {  
        MessageBox.Show ("初始化设备失败!","错误",MessageBoxButtons.OK ,MessageBoxIcon.Error );  
        cobDevice.Items .Add("未发现可用视频设备");  
        cobDevice.SelectedIndex =0;  
    }  

//判断有没用可用的捕获设备
if(axCap .NumDevices <0)
{
    //没有找到可用的视频设备则报错,并退出程序
    MessageBox.Show ("没有发现可用的设备!","错误",MessageBoxButtons.OK ,MessageBoxIcon.Error );
    cobDevice.Items .Add("未发现可用视频设备");
    cobDevice.SelectedIndex =0;
}
else
{
    //找到则枚举所以设备,并初始化设备组合框
    try
    {
        for(int i=0;i<axCap .NumDevices ;i++)
        {
            cobDevice.Items .Add (axCap .ObtainDeviceName (i));
        }
        cobDevice.SelectedIndex =0;    //设置默认设备
    }
    catch
    {
        MessageBox.Show ("初始化设备失败!","错误",MessageBoxButtons.OK ,MessageBoxIcon.Error );
        cobDevice.Items .Add("未发现可用视频设备");
        cobDevice.SelectedIndex =0;
    }
}
 
        怎样修改摄像头参数:每个摄像头都有很多参数,如亮度、对比度、灰度等。有的摄像还可能提供很多特效效果,比如像框,黑白等。这些参数和效果都可通过调用底层的视频设备属性对话框来修改,具体方法请参考以下代码:
view plaincopy to clipboardprint?
private void butSet_Click(object sender, System.EventArgs e)  
{  
    //调用DrawShow设置对话框  
    if (axCap .HasFilterPropertyPage (CAPTUREPRO3Lib.FILTERPROPTYPE .FILTERPROP_VIDEO_DEVICE ))  
    {  
        axCap .ShowFilterPropertyPage (CAPTUREPRO3Lib.FILTERPROPTYPE .FILTERPROP_VIDEO_DEVICE, "");  
    }  

private void butSet_Click(object sender, System.EventArgs e)
{
    //调用DrawShow设置对话框
    if (axCap .HasFilterPropertyPage (CAPTUREPRO3Lib.FILTERPROPTYPE .FILTERPROP_VIDEO_DEVICE ))
    {
        axCap .ShowFilterPropertyPage (CAPTUREPRO3Lib.FILTERPROPTYPE .FILTERPROP_VIDEO_DEVICE, "");
    }
}
 
        怎样录像:首先要设置录像文件,可以通过axCap.StreamFile属性来设置录像文件路径,该属性指的是录像文件的完整路径。然后可以设置 Preview = true属性来打开预览。然后调用方法axCap.StartCapture ()来开始录像。停止录像很简单只需要调用函数axCap.EndCapture ()就可以了。可以参考以下代码:
view plaincopy to clipboardprint?
private void butStartCap_Click(object sender, System.EventArgs e)  
...{  
    if(saveFile.FileName !="") //如果设置了路径则执行操作 否则报错  
    ...{  
        if(radCapFarme.Checked )  //执行帧捕获操作  
        ...{  
            if(!flagCapingFarmes)  //如果当前没有执行其它捕获  
            ...{  
                if(!axCap.Preview )   //打开自动预览  
                ...{  
                    axCap.Visible =true;  
                    axCap.Preview =true;  
                    txtBack.Visible =false;  
                    butCaptureImg.Enabled =true;  
                    butPreview.Text ="停止预览";  
                }  
                if(chkAutoSave.Checked )  
                ...{  
                    //如果自动保存为真则设置周期  
                    axCap.Interval =Convert.ToInt32 (txtTime.Text ,10); //先设置自动保存时间  
                }  
                axCap.AutoSave =chkAutoSave.Checked;   //处理自动保存  
                axCap.AutoIncrement =chkAutoRename.Checked; //处理自动改文件名  
                axCap.FrameFile =saveFile.FileName ;    //设置保存路径  
                butStartCap.Text ="停止捕获";           
                flagCapingFarmes=true;                   //设置工作进行标志 标志忙  
                axCap.CaptureFrame ();                   //开始捕获帧  
            }  
            else        //如果当前正在进行其它捕获工作  
            ...{   
                axCap.AutoSave =false;                 //关自动保存  
                axCap.Interval =0;                     //自动保存周期置0  
                butStartCap.Text ="开始捕获";  
                flagCapingFarmes=false;                //置工作空闲标志  
                DisConnect();                          //断开连接 关闭捕获   
            }  
        }  
        else   //执行流捕获  
        ...{  
            if(!flagCapingStream )  
            ...{  
                axCap.VideoCompressorIndex =cobVicomp.SelectedIndex ;  
                axCap.AudioDeviceIndex =comAudioDevice.SelectedIndex ;  
                axCap.AudioCompressorIndex =comAudioComp.SelectedIndex ;  
                axCap.StreamFile =saveFile.FileName ;  
                butStartCap.Text ="停止捕获";  
                flagCapingStream=true;  
                if(!axCap.Preview )   //打开自动预览  
                ...{  
                    axCap.Visible =true;  
                    axCap.Preview =true;  
                    txtBack.Visible =false;  
                    butCaptureImg.Enabled =true;  
                    butPreview.Text ="停止预览";  
                }  
                try 
                ...{  
                    axCap.StartCapture ();  
                }  
                catch 
                ...{  
                    MessageBox.Show ("视频编码器不可用,请重新连接设备");  
                    cobVicomp.Items.Clear ();  
                    butStartCap.Text ="开始捕获";  
                    flagCapingStream=false;  
                    axCap.Preview =false;  
                    mnuDisableLink.Enabled =false;  
                    mnuLink.Enabled =true;  
                    cobColor.Enabled =false;  
                    cobPix.Enabled =false;  
                    cobColor.Text =null;  
                    cobColor.Items.Clear ();  
                    cobPix.Text =null;  
                    cobPix.Items .Clear ();  
                    txtBack.Visible =true;  
                    chkAdvCap.Enabled =false;  
                    butPreview.Enabled =false;  
                    butSet.Enabled =false;  
                    butDeviceSet.Enabled =false;  
                    butVideoFormat.Enabled =false;  
                    butCaptureImg.Enabled =false;  
                    chkData.Enabled =false;  
                    chkTime.Enabled =false;  
                    txtLable.Enabled =false;  
                    butPreview.Text ="开始预览";  
                    butLink.Text ="连接设备";  
                    if(chkAdvCap.Checked )  
                    chkAdvCap.CheckState =CheckState.Unchecked ;  
                    visableControl(false,3);  
                }  
            }  
            else 
            ...{  
                if(axCap.Preview )  
                ...{  
                    axCap.Preview =false;  
                    axCap.Visible =false;  
                    txtBack.Visible =true;  
                    butCaptureImg.Enabled =false;  
                    butPreview.Text ="开始预览";  
                }  
                butStartCap.Text ="开始捕获";  
                flagCapingStream=false;  
                axCap.EndCapture ();  
            }  
        }  
    }  
    else 
    ...{  
        MessageBox.Show ("请先设置要存储的文件!","错误",MessageBoxButtons.OK ,MessageBoxIcon.Error );  
    }  
      

private void butStartCap_Click(object sender, System.EventArgs e)
...{
    if(saveFile.FileName !="") //如果设置了路径则执行操作 否则报错
    ...{
        if(radCapFarme.Checked )  //执行帧捕获操作
        ...{
            if(!flagCapingFarmes)  //如果当前没有执行其它捕获
            ...{
                if(!axCap.Preview )   //打开自动预览
                ...{
                    axCap.Visible =true;
                    axCap.Preview =true;
                    txtBack.Visible =false;
                    butCaptureImg.Enabled =true;
                    butPreview.Text ="停止预览";
                }
                if(chkAutoSave.Checked )
                ...{
                    //如果自动保存为真则设置周期
                    axCap.Interval =Convert.ToInt32 (txtTime.Text ,10); //先设置自动保存时间
                }
                axCap.AutoSave =chkAutoSave.Checked;   //处理自动保存
                axCap.AutoIncrement =chkAutoRename.Checked; //处理自动改文件名
                axCap.FrameFile =saveFile.FileName ;    //设置保存路径
                butStartCap.Text ="停止捕获";        
                flagCapingFarmes=true;                   //设置工作进行标志 标志忙
                axCap.CaptureFrame ();                   //开始捕获帧
            }
            else        //如果当前正在进行其它捕获工作
            ...{
                axCap.AutoSave =false;                 //关自动保存
                axCap.Interval =0;                     //自动保存周期置0
                butStartCap.Text ="开始捕获";
                flagCapingFarmes=false;                //置工作空闲标志
                DisConnect();                          //断开连接 关闭捕获
            }
        }
        else   //执行流捕获
        ...{
            if(!flagCapingStream )
            ...{
                axCap.VideoCompressorIndex =cobVicomp.SelectedIndex ;
                axCap.AudioDeviceIndex =comAudioDevice.SelectedIndex ;
                axCap.AudioCompressorIndex =comAudioComp.SelectedIndex ;
                axCap.StreamFile =saveFile.FileName ;
                butStartCap.Text ="停止捕获";
                flagCapingStream=true;
                if(!axCap.Preview )   //打开自动预览
                ...{
                    axCap.Visible =true;
                    axCap.Preview =true;
                    txtBack.Visible =false;
                    butCaptureImg.Enabled =true;
                    butPreview.Text ="停止预览";
                }
                try
                ...{
                    axCap.StartCapture ();
                }
                catch
                ...{
                    MessageBox.Show ("视频编码器不可用,请重新连接设备");
                    cobVicomp.Items.Clear ();
                    butStartCap.Text ="开始捕获";
                    flagCapingStream=false;
                    axCap.Preview =false;
                    mnuDisableLink.Enabled =false;
                    mnuLink.Enabled =true;
                    cobColor.Enabled =false;
                    cobPix.Enabled =false;
                    cobColor.Text =null;
                    cobColor.Items.Clear ();
                    cobPix.Text =null;
                    cobPix.Items .Clear ();
                    txtBack.Visible =true;
                    chkAdvCap.Enabled =false;
                    butPreview.Enabled =false;
                    butSet.Enabled =false;
                    butDeviceSet.Enabled =false;
                    butVideoFormat.Enabled =false;
                    butCaptureImg.Enabled =false;
                    chkData.Enabled =false;
                    chkTime.Enabled =false;
                    txtLable.Enabled =false;
                    butPreview.Text ="开始预览";
                    butLink.Text ="连接设备";
                    if(chkAdvCap.Checked )
                    chkAdvCap.CheckState =CheckState.Unchecked ;
                    visableControl(false,3);
                }
            }
            else
            ...{
                if(axCap.Preview )
                ...{
                    axCap.Preview =false;
                    axCap.Visible =false;
                    txtBack.Visible =true;
                    butCaptureImg.Enabled =false;
                    butPreview.Text ="开始预览";
                }
                butStartCap.Text ="开始捕获";
                flagCapingStream=false;
                axCap.EndCapture ();
            }
        }
    }
    else
    ...{
        MessageBox.Show ("请先设置要存储的文件!","错误",MessageBoxButtons.OK ,MessageBoxIcon.Error );
    }
   
}
 
    Pegasus CapturePRO 控件是一个功能非常强大的控件,由于篇幅和时间关系这里就不一一叙述了,该控件所有的属性、方法、事件在它的帮助文档中都有详细的说明,大家在使用的时候 可以仔细阅读。我写了一个

没有评论:

发表评论