C# Tips之EmguCV(一)

本文介绍C#编程语言结合EmguCV库进行计算机视觉应用,包括矩阵操作、图像处理技巧及如何自定义矩阵扩展类实现基础矩阵运算。
部署运行你感兴趣的模型镜像

写在前面

C# Tips是博主开启的第一个项目,以C#为示例语言,旨在普及编程技巧、经典算法以及计算机视觉、图形学知识。

EmguCV

计算机视觉是研究计算机如何模拟人眼的学科,最常用、最稳定、最权威的库就是OpenCV,但是OpenCV主要是由C++开发的,编译起来相对麻烦,好在针对.NET平台的EmguCV被伟大的开源工程师们开发了出来,这个库实现了OpenCV的大部分功能,并且集成了图像显示控件ImageBox,随着其版本的不断更新,功能也会越来越接近OpenCV。值得一提的是,EmguCV的版本号与OpenCV基本一致,OpenCV2.x时可用的SIFT算法在EmguCV2.x中仍然可用,但是可能性能不太好【笑哭】。

矩阵创建

计算机视觉的基本单位是图像,图像就是一种特殊的矩阵(MxNx3),另外图像的处理需要其他矩阵的辅助,所以矩阵是计算机视觉库中必不可少的类,EmguCV和OpenCV中都用Mat类来表示,下面的例子都来自于EmguCV3.4.3,需要注意的是:一定要将下载的EmguCV的bin中的x86文件夹复制到与exe文件同目录下

构造方法

方法含义
Mat()创建一个空矩阵
Mat(Mat, Rectangle)/Mat(Mat, Range, Range)按ROI提取矩阵的一个部分
Mat(Size, DepthType, Int32) /Mat(Int32, Int32, DepthType, Int32)创建一个指定大小、类型、通道数的矩阵

特殊方法

方法含义
Mat Clone()复制矩阵
Mat Diag(int d = 0)提取对角阵
Mat Eye(int rows,int cols,DepthType type,int channels)创建单位矩阵
Mat Ones(int rows,int cols,DepthType type,int channels)创建全1矩阵
void SetTo(T[] data)从数组中复制数据到矩阵
Mat Zeros(int rows,int cols,DepthType type,int channels)创建零矩阵

矩阵运算

和OpenCV不同的是,EmguCV并未实现矩阵基础运算及取值赋值运算,但实现了像矩阵转置、矩阵求逆、向量点乘等更高级的运算,为了能兼顾二者,可以自建一个ME(Mat Extension)类继承Mat类,以下的ME类特指单通道矩阵。
首先得继承Mat的构造方法,根据自己的需要选择不同的方法。

public ME()
{
}

public ME(int rows, int cols, DepthType type): base(rows, cols, type, 1)
{
}

/// <summary>
/// Mat转化为ME
/// </summary>
/// <param name="mat">待转化的Mat</param>
public ME(Mat mat): base(mat, new System.Drawing.Rectangle(0, 0, mat.Width, mat.Height))
{
}

然后实现基本的取值和赋值运算,使得矩阵的取值赋值和二维数组一样方便。

/// <summary>
/// 获得或设置矩阵的值
/// </summary>
/// <param name="row">行号</param>
/// <param name="col">列号</param>
/// <returns>获取的值</returns>
public dynamic this[int row,int col=0]
{
    get 
    {
        var value1 = CreateElement();
        Marshal.Copy(this.DataPointer + (row * this.Cols + col) * this.ElementSize, value1, 0, 1);
        return value1[0];
    }
    set
    {
        var target = CreateElement();
        target[0] = value;
        Marshal.Copy(target, 0, this.DataPointer + (row * this.Cols + col) * this.ElementSize, 1);
    }
}

/// <summary>
/// 创建大小为1的基本类型数组
/// </summary>
/// <param name="depthType">Mat的深度类型</param>
/// <returns>数组结果</returns>
private dynamic CreateElement()
{
    DepthType depthType = this.Depth;
    if (depthType == DepthType.Cv8S)
    {
        return new sbyte[1];
    }
    else if (depthType == DepthType.Cv8U)
    {
        return new byte[1];
    }
    else if (depthType == DepthType.Cv16S)
    {
        return new short[1];
    }
    else if (depthType == DepthType.Cv16U)
    {
        return new ushort[1];
    }
    else if (depthType == DepthType.Cv32S)
    {
        return new int[1];
    }
    else if (depthType == DepthType.Cv64F)
    {
        return new double[1];
    }
    else
    {
        return new float[1];
    }
}

最后实现矩阵的加、减、乘和取负等基础运算,和一般类型一样,需要重载+、-、*运算符。

/// <summary>
/// 将矩阵转化为相应类型的数组
/// </summary>
/// <returns>数组结果</returns>
public dynamic ToArray()
{
    DepthType depthType = this.Depth;
    int length = this.Rows * this.Cols;
    dynamic arr;
    if (depthType == DepthType.Cv8S)
    {
        arr=new sbyte[length];
        this.CopyTo<sbyte>(arr);
    }
    else if (depthType == DepthType.Cv8U)
    {
        arr = new byte[length];
        this.CopyTo<byte>(arr);
    }
    else if (depthType == DepthType.Cv16S)
    {
        arr = new short[length];
        this.CopyTo<short>(arr);
    }
    else if (depthType == DepthType.Cv16U)
    {
        arr = new ushort[length];
        this.CopyTo<ushort>(arr);
    }
    else if (depthType == DepthType.Cv32S)
    {
        arr = new int[length];
        this.CopyTo<int>(arr);
    }
    else if (depthType == DepthType.Cv64F)
    {
        arr = new double[length];
        this.CopyTo<double>(arr);
    }
    else
    {
        arr = new float[length];
        this.CopyTo<float>(arr);
    }
    return arr;
}

/// <summary>
/// 矩阵加法
/// </summary>
/// <param name="lhs">左矩阵</param>
/// <param name="rhs">右矩阵</param>
/// <returns>结果</returns>
public static ME operator +(ME lhs, ME rhs)
{
    if (lhs.Rows != rhs.Rows || lhs.Cols != rhs.Cols)
        return null;
    dynamic data1 = lhs.ToArray();
    dynamic data2 = rhs.ToArray();
    double[] result = new double[lhs.Rows * lhs.Cols];
    for (int i = 0; i < data1.Length; i++)
        result[i] = data1[i] + data2[i];
    ME mat = new ME(lhs.Rows, lhs.Cols, DepthType.Cv64F);
    mat.SetTo<double>(result);
    return mat;
}

/// <summary>
/// 矩阵加法
/// </summary>
/// <param name="lhs">矩阵</param>
/// <param name="rhs">常数</param>
/// <returns>结果</returns>
public static ME operator +(ME lhs, double rhs)
{
    dynamic data1 = lhs.ToArray();
    double[] result = new double[lhs.Rows * lhs.Cols];
    for (int i = 0; i < data1.Length; i++)
        result[i] = data1[i] + rhs;
    ME mat = new ME(lhs.Rows, lhs.Cols, DepthType.Cv64F);
    mat.SetTo<double>(result);
    return mat;
}

/// <summary>
/// 矩阵减法
/// </summary>
/// <param name="lhs">左矩阵</param>
/// <param name="rhs">右矩阵</param>
/// <returns>结果</returns>
public static ME operator -(ME lhs, ME rhs)
{
    if (lhs.Rows != rhs.Rows || lhs.Cols != rhs.Cols)
        return null;
    dynamic data1 = lhs.ToArray();
    dynamic data2 = rhs.ToArray();
    double[] result = new double[lhs.Rows * lhs.Cols];
    for (int i = 0; i < data1.Length; i++)
        result[i] = data1[i]-data2[i];
    ME mat = new ME(lhs.Rows, lhs.Cols, DepthType.Cv64F);
    mat.SetTo<double>(result);
    return mat;
}

/// <summary>
/// 矩阵减法
/// </summary>
/// <param name="lhs">矩阵</param>
/// <param name="rhs">常数</param>
/// <returns>结果</returns>
public static ME operator -(ME lhs, double rhs)
{
    dynamic data1 = lhs.ToArray();
    double[] result = new double[lhs.Rows * lhs.Cols];
    for (int i = 0; i < data1.Length; i++)
        result[i] = data1[i]-rhs;
    ME mat = new ME(lhs.Rows, lhs.Cols, DepthType.Cv64F);
    mat.SetTo<double>(result);
    return mat;
}

/// <summary>
/// 矩阵取负
/// </summary>
/// <param name="lhs">矩阵</param>
/// <returns>结果</returns>
public static ME operator -(ME lhs)
{
    dynamic data1 = lhs.ToArray();
    double[] result = new double[lhs.Rows * lhs.Cols];
    for (int i = 0; i < data1.Length; i++)
        result[i] = -data1[i];
    ME mat = new ME(lhs.Rows, lhs.Cols, DepthType.Cv64F);
    mat.SetTo<double>(result);
    return mat;
}

/// <summary>
/// 矩阵乘法
/// </summary>
/// <param name="lhs">左矩阵</param>
/// <param name="rhs">右矩阵</param>
/// <returns>结果</returns>
public static ME operator *(ME lhs, ME rhs)
{
    if (lhs.Cols != rhs.Rows)
        return null;
    double[] result = new double[lhs.Rows * rhs.Cols];
    for (int i = 0; i < lhs.Rows * rhs.Cols; i++)
        result[i] = lhs.Row(i / rhs.Cols).Dot(rhs.Col(i % rhs.Cols).T());
    ME mat = new ME(lhs.Rows, rhs.Cols, DepthType.Cv64F);
    mat.SetTo<double>(result);
    return mat;
}

/// <summary>
/// 矩阵乘法
/// </summary>
/// <param name="lhs">常数</param>
/// <param name="rhs">矩阵</param>
/// <returns>结果</returns>
public static ME operator *(double rhs, ME lhs)
{
    dynamic data1 = lhs.ToArray();
    double[] result = new double[lhs.Rows * lhs.Cols];
    for (int i = 0; i < data1.Length; i++)
        result[i] = data1[i]*rhs;
    ME mat = new ME(lhs.Rows, lhs.Cols, DepthType.Cv64F);
    mat.SetTo<double>(result);
    return mat;
}

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值