【 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

智能推荐

将本地网站发布到服务器上_网页发布-程序员宅基地

文章浏览阅读1.5k次,点赞2次,收藏4次。将静态的网页部署到服务器上,首先需要下载一个xftp,帮助我们上传文件;以及它的服务端xshell帮助我们重启服务器1,首先与服务器建立连接2,要想把我们的静态网页发布到服务器上,前提是我们的服务器安装了nignx,完成这些以后把我们本地的网页文件夹上传到/usr/local/nginx/html的路径下3,文件上传成功后,还需要我们修改nignx的配置文件,打开/usr/local/ng..._网页发布

java.net.ConnectException: no available server-程序员宅基地

文章浏览阅读2.1w次,点赞8次,收藏10次。我出现这个错误是因为没有加载我的配置文件在这里插入图片描述可以看到我上图打印的是连接我本地的nacos,并且连接超时但实际我的配置文件并不是配置的本地,看下图这就是典型的没有加载解决办法:完成这些就能加载到配置文件了..._no available server

请求大佬帮忙看看VScode Tensorflow model.fit 报错_model.fit报错use_multiprocessing=use_multiprocessing-程序员宅基地

文章浏览阅读1k次。import numpy as npimport tensorflow_core as tffrom tensorflow.keras.layers import Dense, SimpleRNNimport matplotlib.pyplot as pltimport osinput_word = "abcde"w_to_id = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4} # 单词映射到数值id的词典id_to_onehot = {0: [1.,._model.fit报错use_multiprocessing=use_multiprocessing

chapter04-程序员宅基地

文章浏览阅读152次。1、创建/guanli 目录,在/guanli下创建zonghe 和 jishu 两个目录(一条命令)[root@localhost ~]mkdir -p /guanli/{zonghe,jishu}2、添加组帐号zonghe、caiwu、jishu,GID号分别设置为2001、2002、2003[root@localhost ~]# groupadd -g 2001 zon..._在chapter04的包cn.itcast.chapter04.prsponse

字符串_空串是什么都没有字符串吗-程序员宅基地

文章浏览阅读362次。串的定义串是字符串的简称。在数据结构中,串是一种在数据元素的组成上具有一定约束条件的线性表,即要求组成线性表的所有数据元素都是字符,所以说串是一个有穷的字符序列。串是由零个或多个字符组成的有限序列,记作s=”s0s1…sn-1”(n≥0),其中s是串名,字符个数n称作串的长度,双撇号括起来的字符序列”s0s1…sn-1”是串的值字符串(String)是由数字、字母、任何其它的符号组成的一串字符。零个字符的串(即:"")称为空串,空串不包含任何字符。值得注意的是:(1)长度为1的空格串" “不等同于_空串是什么都没有字符串吗

mathtype软件产品密钥最新7.4_mathtyoe产品密钥-程序员宅基地

文章浏览阅读1.5k次,点赞15次,收藏18次。总之,MathType 7.4是一款功能全面、易于使用的数学公式编辑器,无论是教育、科研还是出版领域,它都能为用户提供强大的支持和便利。当然,作为软件技术支持专家,我很乐意为用户提供关于MathType 7.4的详细信息和支持。_mathtyoe产品密钥

随便推点

【SQL注入漏洞-04】布尔盲注靶场实战_oracle布尔盲注-程序员宅基地

文章浏览阅读6.5k次,点赞4次,收藏3次。当我们改变前端页面传输给后台sql参数时,页面没有显示相应内容也没有显示报错信息时,不能使用联合查询注入和报错注入,这时我们可以考虑是否为基于布尔的盲注。利用页面返回的布尔类型状态,正常或者不正常;我们输入的语句让页面呈现出两种状态,相当于true和false,根据这两种状态可以判断我们输入的语句是否查询成功。布尔盲注就是根据这两种状态,来反推我们输入的条件是真还是假。以sqli-labs-masterless-8关为例_oracle布尔盲注

ROS学习(11)使用ROS创建地图_ros建图-程序员宅基地

文章浏览阅读1w次,点赞10次,收藏72次。创建地图是一件比较复杂的工作,ROS利用map_server地图服务器,借助激光雷达和机器人的里程信息来完成这项工作。本篇我们还是利用柳树车库作为默认的地图环境。主要介绍了地图的创建、保存、加载,下一篇尝试配置导航功能包集,并在gazebo仿真环境下完成自定义机器人的自主导航。httpshttpshttpshttps。..._ros建图

自定义Magento页标题与Meta描述_magento seo suite 自定义 meta description-程序员宅基地

文章浏览阅读3.2k次。在Magento中,CMS页、产品页、分类页均可以设置Meta keywords与Meta Description。但在其它页面上如何设置呢?例如今天SEO团队发来文档,要求修改Checkout页、MyAccount页、Login页、Contact页等等的页标题与Meta描述部分。于是第一反应就是用XML来配置.另:在System-Configration-Design-Html-_magento seo suite 自定义 meta description

【PTA-python】第4章-15 换硬币 (20 分)_pta换硬币python-程序员宅基地

文章浏览阅读1.3k次。第4章-15 换硬币分析题目解法分析为了实现各个硬币数目>=1,range()函数设定倒序范围,先求五分硬币数目,再求二分硬币数目,最后求一分硬币数目,注意在往下递推求解的过程中,各个硬币数目的条件是>=1,这影响到range(five,0,-1)和if one>=1:题目将一笔零钱换成5分、2分和1分的硬币,要求每种硬币至少有一枚,有几种不同的换法?输入格式:输入在一行中给出待换的零钱数额x∈(8,100)。输出格式:要求按5分、2分和1分硬币的数量依次从大到小的顺序_pta换硬币python

firewall限制或开放IP及端口命令_firewall-cmd --zone=public --list-ports-程序员宅基地

文章浏览阅读1w次,点赞6次,收藏23次。一、查看防火墙状态1、首先查看防火墙是否开启,如未开启,需要先开启防火墙并作开机自启systemctl status firewalld开启防火墙并设置开机自启systemctl start firewalldsystemctl enable firewalld一般需要重启一下机器,不然后面做的设置可能不会生效二、开放或限制端口1、开放端口(1)如我们需要开启XShell连接时需要使用的22端口firewall-cmd --zone=public --add-port=22/tcp _firewall-cmd --zone=public --list-ports

北京交通大学-图像处理与机器学习_北京交通大学图像处理与机器视觉实验代码-程序员宅基地

文章浏览阅读6.7k次,点赞10次,收藏73次。日期项目2022/03/04更新实验环境配置视频P6,第八章后所有内容已同步更新!名称项目课程主页图像处理与机器学习B站主页啥都会一点的研究生课程B站视频【北交】图像处理与机器学习人工智能技术探讨群178174903人工智能技术探讨群2571218304人工智能技术探讨群3584723646课程目录及资料(UP已打包整理支持直链下载)章节内容资料第一章 绪论1-1 基本._北京交通大学图像处理与机器视觉实验代码

推荐文章

热门文章

相关标签