(4opencv)如何基于GOCW,创建一个实时视频程序

直接使用提供的代码框架进行修改,是最快得到效果的方法;但是这样的灵活性较差,而且真正的程序员从来都不会停滞在这一步:我们需要的是“将框架解析到最小化、理清楚每个构建之间的关系”,只有这样才能灵活运用。
一、准备工作
1、高拍仪已经接通,如果需要的话,还要安装驱动;
2、vs2012编程环境,能够编写Csharp和OpenCV程序(具体不清楚可以回过头来看配置);
3、 508489-20180831193303463-1986484462.png 是DirectShow.net(http://directshownet.sourceforge.net/docs.html)的可使用类
logo
它本身包含文档,有时间可以看一下。最新更新时间2010年。
4、 508489-20180831193304012-409114295.png 是由
508489-20180831193304209-491423623.png
生成的。这里可以先立足修改已经编辑成功的项目(具体原理将在下一课讲解)
二、配置程序
1、添加引用
508489-20180831193304426-1038011652.png
directshow.net的话,直接引用dll就可以了
508489-20180831193304654-749519769.png
2、拖动控件
使用Csharp编写界面,可以重复使用
508489-20180831193304915-29559585.png
的定位功能
508489-20180831193305076-1562961293.png
以及Dock的停靠功能
508489-20180831193305238-1584146256.png

图像显示的地方,肯定需要的是picturebox,不妨连同lena一起拷贝过来
508489-20180831193305938-1339436566.jpg

由于采集处理是一个实时过程,我们采用timer控件来控制(关于是使用timer还是开线程,那种比较好,我们在框架融合的时候专门比较,并选择)
508489-20180831193306367-1824525790.png
性Interval采用50即可,以为50*24>1000,一般来说还是有认为24帧以上比较连贯。


三、编写代码
1、添加头文件和引用,并添加capture.cs
508489-20180831193306540-1601494609.png
508489-20180831193306778-2024280620.jpg

其中,Capture是一个专门对Directshow的采集设备的封装,里面有丰富的功能;是官方提供的代码,可以较为方向应用。
注意修改命名空间
508489-20180831193307062-1473670933.jpg
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();  
        }

此时,已经可以预览,并且获得所有视频设备
508489-20180831193307818-1506314275.jpg
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的处理结果显示在右侧。
508489-20180831193309154-1598585275.jpg


508489-20180831193309662-829572476.jpg

到此为止,基于 GOCW,创建一个实时视频程序的基本流程已经明晰了,如果感兴趣,相关的原理请关注后续博客。
感谢阅读至此,
希望有所帮助。
P.S小技巧:在tab选择到预览窗口的时候,才打开timer,这样能够保证最好效率。

   private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tabControl.SelectedIndex == 1)//只有在预览的时候打开图像处理
                timer.Enabled = true;
            else
                timer.Enabled = false;
        }





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、主要内容:OpenCV能够实现强大丰富的图像处理,但是它缺少一个能够支持它运行的界面。Csharp经过多年的发展,得益于它的“所见及所得”能力,非常方便编写界面。这两者如果能够“双剑合璧”,将有效帮助实际工作产出。本课着重推荐GOCW采用“Csharp基于CLR直接调用Opencv编写的算法库”方法,能够将最新的OpenCV技术引入进来,同时保证生成程序的最小化。    为了进一步说明Csharp和OpenCV的结合使用,首先一个较为完整的基于winform实现答题卡识别的例子,相比较之前的实现,本次进一步贴近生产实际、内涵丰富,对算法也进行了进一步提炼。同时我们对WPF下对OpenCV函数的调用、OpenCV.js的调用进行相关教授。       二、课程结构1、 EmguCV、OpenCVSharp和GOCW之间进行比较(方便代码编写、能够融入最新的算法、速度有保障、方便调试找错、拒绝黑箱化);2、视频采集模块的构建,视频采集和图像处理之间的关系;3、视频采集专用的SDK和“陪练”系统的介绍;4、在视频增强类项目中和图像处理项目中,算法的选择;5、Csharp界面设计、图片的存储和其他构建设计;6、较为完整的答题卡识别例子,兼顾界面设计和算法分析;8、WPF基于GOCW也同样可以基于GOCW实现算法调用;webForm虽然也可以通过类似方法调用,但是OpenCV.JS的方法更现代高效。9、关于软件部署的相关要点和窍门。       三、知识要点:1、基本环境构建和程序框架;2、CLR基本原理和应用方法;3、接入、采集、模拟输入;4、图像处理,通过构建循环采集图片;5、增强和实时处理;6、基于投影等技术的答题卡识别算法;7、存储、转换;8、部署交付。        课程能够帮助你掌握Csharp调用Opencv的基本方法,获得相应框架代码和指导;从而进一步提升实现“基于图像处理”的解决方案能力。  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值