【 Emgu CV教程】1.1、Emgu CV 简介及使用_emgucv-程序员宅基地

技术标签: c#  Emgu CV  Emgu CV使用教程  计算机视觉  图像处理  

作者在工作中偶然接触到了Emgu CV这个视觉处理封装包,并对它的具体功能做了比较全面的试验,为了方便广大C#程序员也能愉快的体验到视觉处理的乐趣,我决定通过一系列的文章和代码演示,来一步步的实现Emgu CV,或者说是OpenCV的基础功能。

由于作者代码水平有限,以及是一个视觉处理方便的业余爱好者,因此只能从门外汉的角度进行编程和文字描述,不足之处希望大家不要介意。另外介绍的代码、功能描述、章节划分,甚至是理论的介绍都有可能出现错误之处,请大家多多指正。

本系列文章适用于C#程序员,对计算机视觉有一定爱好,并且理论基础比较薄弱。提供的代码也仅限于相互交流和技术验证,请勿用于商业目的。

1、OpenCV

在计算机视觉处理领域,OpenCV可是说是大名鼎鼎。其用C++语言编写,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS,OpenCV主要倾向于实时视觉应用,并在可用时利用MMX和SSE指令, 如今也提供对于C#、Ch、Ruby,GO的支持(来自百度百科)。

对于 .NET 程序员来说,直接使用OpenCV很不方便。如果程序员想用WinForm或者WPF开发一些视觉应用的程序,此时就有两个选择,分别是OpenCvSharpEmgu CV

2、OpenCvSharp

好像是一位日本程序员开发并维护的OpenCV封装包,具体的使用方法不在本系列课程的介绍范围内,据说是使用方式上更接近原始的OpenCV,有兴趣的朋友可以单独了解一下。其项目网址如下:

Github网址OpenCV wrapper for .NET. Contribute to shimat/opencvsharp development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/shimat/opencvsharp

​3、Emgu CV

其官方介绍如下:Emgu CV is a cross platform .Net wrapper to the OpenCV image processing library. Allowing OpenCV functions to be called from .NET compatible languages. The wrapper can be compiled by Visual Studio and Unity, it can run on Windows, Linux, Mac OS, iOS and Android.

Emgu CV: OpenCV in .NET (C#, VB, C++ and more)icon-default.png?t=N7T8https://emgu.com/其在版本的更新上,紧随OpenCV,截止到2023年12月11日,其最新版本为Emgu CV-4.8.0

从具体功能上来说,它实现了OpenCV应有的以下功能:

  1. 图像处理,比如滤波、形态学处理、二值化、色彩空间转换、图像增强等。
  2. 计算机视觉:支持各种计算机视觉算法,如特征提取、目标检测、跟踪、人脸识别等。
  3. 模式识别:提供了模式识别算法,如支持向量机(SVM)、随机森林等。
  4. 深度学习:支持深度学习算法,如卷积神经网络(CNN)、循环神经网络(RNN)等。
  5. OCR:可以结合Tesseract OCR引擎实现光学字符识别(OCR)功能,将图像中的文字转换为可编辑和可搜索的文本。
  6. 视频处理:提供了视频处理功能,如视频帧提取、视频编解码等。
  7. 几何变换:支持各种几何变换算法,如平移、旋转、缩放等。
  8. 图像分割:提供了各种图像分割算法,如基于阈值的分割、基于区域的分割等。

​​        上面这个功能介绍也是我抄的,据说是有这些功能,但是我也还没有全部实现呢。

4、WPF项目引用Emgu CV

本系列课程都以WPF项目为例,来进行Emgu CV的演示,WinForm的使用方法应该差不多,读者可以自行试验。

首先创建WPF应用,基于.NET Framework 4.7.2

然后在NuGet中引用以下四个包:

    Emgu.CV

    Emgu.CV.runtime.windows

    Emgu.CV.Bitmap

    Emgu.CV.UI

引用并安装好NuGet包,WPF应用如下图所示:

5、简单应用

Emgu CV用于图像分析,最简单的应用当然是读取出一副原始图片并显示。在实际过程中分为四种情况:

1、读取.jpg、.bmp、png类的图片文件;

2、读取本地.mp4类的视频文件并显示每一帧图像;

3、读取计算机的摄像头并显示;

4、读取网络上的视频文件并显示。

补充资料:视频其实就是在一秒内连续播放n幅图片,然后下一秒再不停的播放,直到结束为止。

5.1、显示图片文件

在MainWindow.xmal中建立一个Image控件,代码如下:

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Image Name="Image1" Grid.Row="0"  Grid.Column="0" Grid.ColumnSpan="1" HorizontalAlignment="Left" Margin="10,10,10,10" VerticalAlignment="Top"/>
    </Grid>

窗体的Load事件中执行如下代码:

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Image<Bgr, Byte> image = new Image<Bgr, byte>("lena.jpg"); // 创建Image类的变量image,并从文件加载图片
            Image1.Source = image.ToBitmapSource(); // Image控件显示加载到的图片
        }

其实就定义一个Emgu CV内的Image类,加载本地 lena.jpg 文件,然后让WPF的Image1控件显示。运行项目,结果如下: 

5.2、显示本地mp4文件

窗体的Load事件中要先建立一个VideoCapture类(Emgu CV中用于操作视频的类),用于打开本地 J20.mp4 文件,打开成功后,通过       

ComponentDispatcher.ThreadIdle += new EventHandler(ProcessFrame)

去执行ProcessFrame函数内的代码。而ProcessFrame函数就是在Image1控件中显示出 J20.mp4 文件的每一帧,全部代码如下:

        /// <summary>
        /// Window窗体加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            videoCapture?.Dispose(); // 先释放现有的VideoCapture类
            videoCapture = new VideoCapture("J20.mp4");

            // 进行异常判断
            if (!videoCapture.IsOpened)
            {
                System.Windows.MessageBox.Show("流媒体视频加载出错!", "提示", (MessageBoxButton)MessageBoxButtons.OK);
                return;
            }

            // 开始捕捉并显示每一帧
            ComponentDispatcher.ThreadIdle += new EventHandler(ProcessFrame);
        }

        /// <summary>
        /// 显示每一帧.
        /// </summary>
        /// <param name="sender">触发事件的控件对象,就是当前的对象.</param>
        /// <param name="e">触发事件的控件对象,记录事件传递过来的额外信息.</param>
        private void ProcessFrame(object sender, EventArgs e)
        {
            try
            {
                // 进行异常判断,如果打不开流媒体,则终止视频分析
                if (videoCapture == null || videoCapture.Ptr == IntPtr.Zero || !videoCapture.IsOpened)
                {
                    return;
                }

                frame = videoCapture.QueryFrame();
                if (frame == null)
                {
                    return;
                }

                if (frame.IsEmpty)
                {
                    return;
                }
                Image1.Source = frame.ToBitmapSource();
            }
            catch (Exception)
            {
            }
        }

程序运行效果如下图所示,视频在播放时速度比利用VLC等软件播放的要快。原因是VLC会调整播放速度,比如一秒钟显示24帧,每一帧中间会有短暂的间隔;而上面的代码则是显示完一帧马上就显示下一帧,中间没有间隔。

5.3、显示本地计算机的摄像头

显示本地文件的代码是

       

videoCapture = new VideoCapture("J20.mp4");

只需要改成

       

videoCapture = new VideoCapture(0);

就可以打开本地计算机的摄像头。可以简单的理解为:new VideoCapture(0) 的意思就是打开本地计算机的第0个摄像头。如果您的计算机上有多个外接摄像机,可以用

videoCapture = new VideoCapture(1);
videoCapture = new VideoCapture(2);

分别打开不同的外接摄像头。

5.3、读取网络上的视频文件并显示

5.2章节已经可以利用VideoCapture显示出本地文件,是这样写的

videoCapture = new VideoCapture(0);

此时,只需要把数字 0 ,换成网络视频的地址,就可以播放出对应的视频,代码及效果如下:

            videoCapture?.Dispose(); // 先释放现有的VideoCapture类
            videoCapture = new VideoCapture("http://gcalic.v.myalicdn.com/gc/sgns01_1/index.m3u8");

提示

1、WPF的Image1控件显示时,或是 image.ToBitmapSource(),或是 Image1.Source = frame.ToBitmapSource()。这个.ToBitmapSource()方法来自于Emgu CV的一个官方文件,可以通过这个路径下载:

emgucv/Emgu.CV.NativeImage/BitmapSourceExtension.cs at master · emgucv/emgucv · GitHub

2、当Emgu CV要操作视频时,需要用到VideoCapture进行初始化。

  • 如果是本地文件,就在括号内写文件路径。
  • 如果是计算机连接的外接摄像头,就在括号内写摄像头的数字编号(编号顺序和规则是什么,作者不知道,您可以试一试)。
  • 如果是网络视频,就在括号内写视频地址,RTSP、RTMP、HLS各种格式的都可以播放。

这篇文章全部代码如下,MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="540" Width="800" Loaded="Window_Loaded">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Image Name="Image1" Grid.Row="0"  Grid.Column="0" Grid.ColumnSpan="1" HorizontalAlignment="Left" Margin="10,10,10,10" VerticalAlignment="Top"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using Emgu.CV;
using System;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;

namespace WpfApp1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private static VideoCapture videoCapture = null;
        private Mat frame; // 视频播放的n帧

        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Windowc窗体加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // 1.显示图片文件
            // Image<Bgr, Byte> image = new Image<Bgr, byte>("lena.jpg"); // 创建Image类的变量image,并从文件加载图片
            // Image1.Source = image.ToBitmapSource(); // Image控件显示加载到的图片

            // 2.显示本地mp4文件
            // videoCapture?.Dispose(); // 先释放现有的VideoCapture类
            // videoCapture = new VideoCapture("J20.mp4");

            // 3.显示本地计算机的摄像头
            // videoCapture?.Dispose(); // 先释放现有的VideoCapture类
            // videoCapture = new VideoCapture(0);

            // 3.显示本地计算机的摄像头
            videoCapture?.Dispose(); // 先释放现有的VideoCapture类
            videoCapture = new VideoCapture("http://gcalic.v.myalicdn.com/gc/sgns01_1/index.m3u8");

            // 进行异常判断
            if (!videoCapture.IsOpened)
            {
                System.Windows.MessageBox.Show("流媒体视频加载出错!", "提示", (MessageBoxButton)MessageBoxButtons.OK);
                return;
            }

            // 开始捕捉并显示每一帧
            ComponentDispatcher.ThreadIdle += new EventHandler(ProcessFrame);
        }

        /// <summary>
        /// 显示每一帧.
        /// </summary>
        /// <param name="sender">触发事件的控件对象,就是当前的对象.</param>
        /// <param name="e">触发事件的控件对象,记录事件传递过来的额外信息.</param>
        private void ProcessFrame(object sender, EventArgs e)
        {
            try
            {
                // 进行异常判断,如果打不开流媒体,则终止视频分析
                if (videoCapture == null || videoCapture.Ptr == IntPtr.Zero || !videoCapture.IsOpened)
                {
                    return;
                }

                frame = videoCapture.QueryFrame();
                if (frame == null)
                {
                    return;
                }

                if (frame.IsEmpty)
                {
                    return;
                }
                Image1.Source = frame.ToBitmapSource();
            }
            catch (Exception)
            {
            }
        }
    }
}

总结

Emgu CV总体上使用起来比较简单,而且所有的函数都和OpenCV原始函数相差不多,接下来的文章会把几十个主要的函数,或者图像/视频处理方式介绍给大家。

原创不易,请勿抄袭。共同进步,相互学习。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sswss12345/article/details/134921699

智能推荐

国产免费数据库建模工具EZDML3.24发布 支持生成和预览vue文件_vue 数据模型软件-程序员宅基地

文章浏览阅读2.3k次。国产免费数据建模和代码生成工具,新版增加了生成vue的JS脚本模板,默认采用ElementUI作为template界面_vue 数据模型软件

1005 继续(3n+1)猜想(python)_phython 3n+1问题-程序员宅基地

文章浏览阅读122次。卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对n=3进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对n=5、8、4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。我们称一个数列中的某个数n为“关键数”,如果n不能被数列中的其他数字所覆..._phython 3n+1问题

jupyter下的python基本使用和信号处理编程_jupyterlab fft-程序员宅基地

文章浏览阅读1.5k次。jupyter下的python基本使用和信号处理编程简介:jupyter notebook是一种 Web 应用,能让用户将说明文本、数学方程、代码和可视化内容全部组合到一个易于共享的文档中。它可以直接在代码旁写出叙述性文档,而不是另外编写单独的文档。也就是它可以能将代码、文档等这一切集中到一处,让用户一目了然。实验环境:腾讯云服务器centos7一、安装jupyter notebook..._jupyterlab fft

Notepad++ 安装XML Tools插件格式化XML文件-程序员宅基地

文章浏览阅读7.8k次,点赞3次,收藏5次。Notepad++ 安装XML Tools插件格式化XML文件Ritchie_Li2022.02.06 20:37:12字数 183阅读 0编辑文章1. 打开Notepad++ 软件2. 选择插件,选择“插件管理”3. 搜索 XML Tools,找到该插件后,勾选该文件,点击“安装”在Notepad++ 中安装,如果没有成功,可以在多尝试2次,我是第3次成功的,具体原因不知,但有的电脑一次就能安装成功的。4. 安装的进入如下:5.成功之后,插件栏显示6. 格式化XML文件, 单击 "_xml tools

Linux驱动开发———imx6ull的pinctrl子系统源码分析_0x4001b8b0-程序员宅基地

文章浏览阅读1.2k次,点赞3次,收藏21次。目录前言前言 最近在配置pinctrl时,配置了引脚复用寄存器的SION位,配置如下图中的所示,0x4001b8b0中的第30位表示SION位 按照个人理解,imx6ull在设备树中配置的pinctrl节点,后面所带的值应该为配置寄存器的值,而SION位是复用寄存器的第三十位..._0x4001b8b0

TCP三次握手四次挥手及各状态解释_计算机网络中seq是什么意思-程序员宅基地

文章浏览阅读2.1k次,点赞2次,收藏5次。常说的三次握手和四次挥手的意思就是TCP建立连接和断开连接的过程下图为TCP三次握手和四次挥手的过程图状态或符号解释seq(sequence number),序列号,用来标记数据段的顺序,TCP把连接中发送的数据字节都编上一个序号,第一个字节的编号由本地随机产生ack(acknowlege number),确认号,指的是期望接收到下一个字节的编号,因此当前报文段最后一个字节的编号+1即为确认号ACK(acknowledgement),确认,当ACK=1确认号字段才有效,ACK=0确认号无效S_计算机网络中seq是什么意思

随便推点

(转)基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出...-程序员宅基地

文章浏览阅读166次。http://www.cnblogs.com/wuhuacong/p/3873498.html数据的导入导出,在很多系统里面都比较常见,这个导入导出的操作,在Winform里面比较容易实现,我曾经在之前的一篇文章《Winform开发框架之通用数据导入导出操作》介绍了在Winform里面的通用导入导出模块的设计和开发过程,但在Web上我们应该如何实现呢?本文主要介绍利用MVC4+Eas...

14.JS语句和注释,变量和数据类型-程序员宅基地

文章浏览阅读112次。1.JavaScript 语句(1)语句的作用(2)语句标识符2.代码和代码块儿(1)代码(2)代码块3.分号、空格和拆行(1)分号(2)空格(3)拆行4.单行注释和多行注释5.JS变量6.创建变量7.JS 数据类型(1)值类型(基本类型):(2)引用数据类型(对象类型):(3)动态类型8.字符串、数字、布尔、数组和对象等(1)字符串(2)数字(3)布尔(4)数组(5)对象...

C语言ASCLL码_c语言 \ ascll-程序员宅基地

文章浏览阅读2.1k次。C语言ASCLL码表介绍_c语言 \ ascll

Linux那些事儿之我是U盘(37)彼岸花的传说(五)_unsigned soft : 1;-程序员宅基地

文章浏览阅读4.1k次。 燕子去了,有再来的时候;杨柳枯了,有再青的时候;桃花谢了,有再开的时候;老婆离了,有再找的时候,孩子跑了,有回来的时候;煮熟的鸭子飞了,有飞回来的时候.一个函数没讲完就跳走了,有再回来的时候.其实,那些人,那些事,终究不曾远离.于是,她再一次进入我们的视野. 她就是usb_stor_control_thread().唤醒她的是来自queuecommand的up(&(us->sema)_unsigned soft : 1;

usb-serial controller d感叹号_usb serial converter驱动感叹号-程序员宅基地

文章浏览阅读4k次,点赞6次,收藏12次。2. 安装正确的驱动程序:USB-Serial设备通常需要安装驱动程序才能正常工作。这些驱动程序通常可从设备制造商的官方网站下载。请确保下载并安装与您的操作系统兼容的最新驱动程序。解决:1. 确认设备已正确连接:检查USB-Serial设备是否正确插入计算机的USB接口,并确保插头没有松动或损坏。感叹号可能是对于USB-Serial设备发生的问题或错误的表达。这可能是指设备无法被识别、驱动安装问题、通信错误等。_usb serial converter驱动感叹号

Laravel定时任务_laravel 停止schedule:run-程序员宅基地

文章浏览阅读576次。Laravel 定时任务首先:Laravel 制定定时任务很简单的!在app/console 文件夹下面,执行 php artisan make:console TestSchedule,他会生成TestSchedule.php这个文件TestSchedule.php,这个文件写你要定时执行的代码逻辑;class TestSchedule extends Command { //..._laravel 停止schedule:run