• 如何基于GOCW,创建一个实时视频程序


    直接使用提供的代码框架进行修改,是最快得到效果的方法;但是这样的灵活性较差,而且真正的程序员从来都不会停滞在这一步:我们需要的是“将框架解析到最小化、理清楚每个构建之间的关系”,只有这样才能灵活运用。

    一、准备工作

    1、高拍仪已经接通,如果需要的话,还要安装驱动;
    2、vs2012编程环境,能够编写Csharp和OpenCV程序(具体不清楚可以回过头来看配置);
    3、是DirectShow.net(http://directshownet.sourceforge.net/docs.html)的可使用类
    logo
    它本身包含文档,有时间可以看一下。最新更新时间2010年。
    4、是由
    生成的。这里可以先立足修改已经编辑成功的项目(具体原理将在下一课讲解)
    二、配置程序
    1、添加引用
    directshow.net的话,直接引用dll就可以了
    2、拖动控件
    使用Csharp编写界面,可以重复使用
    的定位功能
    以及Dock的停靠功能
     
    图像显示的地方,肯定需要的是picturebox,不妨连同lena一起拷贝过来
     
    由于采集处理是一个实时过程,我们采用timer控件来控制(关于是使用timer还是开线程,那种比较好,我们在框架融合的时候专门比较,并选择)
    性Interval采用50即可,以为50*24>1000,一般来说还是有认为24帧以上比较连贯。
     
     
    三、编写代码
    1、添加头文件和引用,并添加capture.cs
     
    其中,Capture是一个专门对Directshow的采集设备的封装,里面有丰富的功能;是官方提供的代码,可以较为方向应用。
    注意修改命名空间
    2、编写选择视频准备函数(注意这里默认设备为640*480),并且我在选择的时候默认选择了第2个(序号为1)的设备,因为我用的是笔记本,有内置摄像头
     
    相关函数的操作,注意参考相关注释
     
      //选择视频设备
            public void InitVideoDevice()
            {
                try
                {
                    if (cam != null)
                        cam.Dispose();
                    //读取参数
                    int VIDEODEVICE = 1; // zero based index of video capture device to use
                    const int VIDEOWIDTH = 640;// 是用默认(最大)分辨率
                    const int VIDEOHEIGHT = 480// Depends on video device caps
                    const int VIDEOBITSPERPIXEL = 24// BitsPerPixel values determined by device
                    cam = new Capture(VIDEODEVICE, VIDEOWIDTH, VIDEOHEIGHT, VIDEOBITSPERPIXEL, picPreview  );
                }
                catch
                {
                    MessageBox.Show("摄像头打开错误,请首先确保摄像头连接并至少支持1024*768分辨率!");
                }
            }
    并且在form的init中进行调用,确保不能够出错
      public FormMain()
            {
                InitializeComponent();
               
                //构造摄像头数据
                foreach (DsDevice ds in DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice))
                {
                    cbCam.Items.Add(ds.Name);
                }
                //初始化摄像头
                InitVideoDevice();  
            }
     
    此时,已经可以预览,并且获得所有视频设备
    4、编写timer事件
    为了将OpenCV的函数融入进去,必须自己编写timer事件。在这个timer事件中,最重要的操作就是
    读取directshow.net产生的结果
    调用OpenCV的函数进行处理
    将处理的结果反馈到directshow.net中去显示出来
     
     private void timer_Tick(object sender, EventArgs e)
            {
                // Release any previous buffer
                if (m_ip != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(m_ip);
                    m_ip = IntPtr.Zero;
                }
                // capture image
                try
                {
                    m_ip = cam.Click();
                }
                catch
                {
                    //do nothing,允许丢帧 TODO:是否改成继承上一帧更好
                }
                Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
                // If the image is upsidedown
                b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                srcImage = b;
                if (picPreview.Image != null)
                    picPreview.Image.Dispose();
                //调用clr+opencv图像处理模块
                MemoryStream ms = new MemoryStream();
                b.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                byte[] bytes = ms.GetBuffer();
                Bitmap bitmap = client.testMethod(bytes);
                //显示结果
                picPreview.Image = bitmap;
            }
     
    这段代码比较关键
     // Release any previous buffer
                if (m_ip != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(m_ip);
                    m_ip = IntPtr.Zero;
                }
    首先判断指针是否为空
     
      // capture image
                try
                {
                    m_ip = cam.Click();
                }
                catch
                {
                    //do nothing,允许丢帧 TODO:是否改成继承上一帧更好
                }
       Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
                // If the image is upsidedown
                b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                srcImage = b;
    而后通过调用Click()获得当前视频数据,并且将其转换为BitMap格式
     
       if (picPreview.Image != null)
                    picPreview.Image.Dispose();
                //调用clr+opencv图像处理模块
                MemoryStream ms = new MemoryStream();
                b.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                byte[] bytes = ms.GetBuffer();
                Bitmap bitmap = client.testMethod(bytes);
    最为关键的调用client.testMethod方法来进行图像处理,并将结果直接转换为bitmap,最后这个结果显示在另外一个picturebox上面。
     
    如果你去看这个testMethod,是一个非常典型的“三明治”结构:包括将<byte>结构转换为Mat,调用OpenCV函数对Mat进行处理,将Mat结果返回出来。
    Bitmap^  GOClrClass::testMethod(cli::array<unsigned char>^ pCBuf1)
    {
        ////////////////////////////////将输入cli::array<unsigned char>转换为cv::Mat/////////////////////////
        pin_ptr<System::Byte> p1 = &pCBuf1[0];
        unsigned char* pby1 = p1;
        cv::Mat img_data1(pCBuf1->Length,1,CV_8U,pby1);
        cv::Mat img_object = cv::imdecode(img_data1,IMREAD_UNCHANGED);
        if (!img_object.data)
            return nullptr;
        ////////////////////////////////////////////OpenCV的算法处理过程////////////////////////////////////
        cvtColor(img_object,img_object,COLOR_BGR2GRAY);
        cvtColor(img_object,img_object,COLOR_GRAY2BGR);
        Mat drawing = img_object.clone();
        
        /////////////////////////将cv::Mat转换为Bitmap(只能传输cv_8u3格式数据)///////////////////////////////
        if (!drawing.data)
            return nullptr;
        Bitmap^ bitmap = MatToBitmap(drawing);
        return bitmap;
    }
    而主要算法,只是一个灰度处理。(我首先将彩色图像转换为灰度,然后再将灰度转换为彩色,是为了保持3通道)
     
    四、测试结果
     
    为了显示结果,我添加了一个picResult的picturebox,则调用OpenCV的处理结果显示在右侧。
     
     
     
    到此为止,基于GOCW,创建一个实时视频程序的基本流程已经明晰了,如果感兴趣,相关的原理请关注后续博客。
    感谢阅读至此,
    希望有所帮助。
    P.S小技巧:在tab选择到预览窗口的时候,才打开timer,这样能够保证最好效率。
     
       private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
            {
                if (tabControl.SelectedIndex == 1)//只有在预览的时候打开图像处理
                    timer.Enabled = true;
                else
                    timer.Enabled = false;
            }





  • 相关阅读:
    asp.net 一次性提交大量数据,服务器会报错,要在 web.config 中设置一下
    同一服务器上多个版本的 sqlserver ,如何连接,改变某一实例的端口号
    安装SQl 2008为SQL Server代理服务提供的凭据无效
    winserver2008 R2 64位 企业版 , IIS 配置运行 asp+access 网站
    获取屏幕分辩率及客户端信息
    如何使用 aspnetpager
    SQL函数:判断库、表、存储过程等是否存在
    NPOI封装类
    Python基础Day1
    HTML5_增强可访问性和解决IE兼容性问题
  • 原文地址:https://www.cnblogs.com/jsxyhelu/p/9567597.html
Copyright © 2020-2023  润新知