VS2013 opencv 3.1.0 开发程序后封装为dll文件并通过C#调用

opencv是一个开源的视觉处理平台,为我们的视觉处理提供了非常多的函数。本人在vs下配置opencv,在实际应用中需要将基于opencv开发的程序打包为dll文件,并通过C#调用。在网上借鉴了诸多大牛的博客,现总结如下:

主要参考博客有,在此表示感谢:https://blog.csdn.net/kuer1379/article/details/80843239  

本文直接跳过VS 配置opencv的教程,网上有很多很好的教程,在配置时需要注意的是修改属性管理器位置不同,配置后的结果有些不同。配置位置如下图所示:

进入debug里面右键属性进行配置
在Debug上直接右键属性进行配置

 两者配置的区别在于进入里面进行配置为永久有效(即新建工程后保留在opencv的配置信息),在外面配置的为只针对该工程有效,新建工程后配置信息消失,再次使用时需要重新进行配置。 

配置时需要注意的是:若只配置Debug,则realease会默认配置该信息(在附加依赖项处出错)。  若用realease直接进行运行会报错,需要修改为realease下的依赖文件。

步入封装正题:(需要C#调用,可直接跳过该步骤)

1、基于C++和opencv的程序封装为dll文件,仍通过C++调用

本人新建dll文件按如下步骤进行:

1)文件—》新建——》项目——》,按自己需要修改名称。

 2)点击确定,下一步 进入该界面

选择dll 和导出符号,新手建议勾选导出符号,可查看系统生成的示例代码

新建后主要生成6个文件如下图所示,

主要需要修改的是自己命名的头文件和CPP文件,即:dll.h和dll.cpp文件 ,这两个文件示意了变量,类,函数的声明和定义方法。下面以自己实际做的例子为例进行分析。

头文件编写如下:

 其中if 0 和#endif中间为将示例程序进行注释,编写的头文件声明如图所示。

cpp文件编写如下:

#if 0 #endif意义和h文件相同。训练结果部分为下面函数需要调用的变量。 

至此完成头文件和CPP文件的声明和定义,在生成dll文件时,只要正常生成解决方案即可,需要注意的是:debug和realease模式的不同,本人的结果是debug生成的 在调用时只能debug调用,realease生成的 在调用时只能realease调用(该出不太明白,有精通的欢迎进行交流)。生成的dll文件和lib文件在如图位置查看

 debug模式生成的在debug下,realease下生成的在release下查看。本人在debug下生成,故灭有realease文件。

1、C++对生成的dll文件进行调用

调用前准备,按照正常步骤生成控制台程序,将dll文件和lib文件,以及生成dll文件的函数声明文件拷贝到新建工程下:

 在使用该dll文件时仅需在源文件中进行包含对应lib库即可,具体参考下图

第一行为包含生成dll的头文件,第三行为包含lib库。其中Check()函数为dll库中文件。运行结果如下

至此,在C++中调用dll库结束。



 下面进入本文醉醉重要部分,由C#调用dll库  。(和C++调用略有不同)

不同1、生成dll文件时小细节不同(该部分参考上面博客编写),直接上代码

改代码为。h文件代码,和上面不同之处在于27~28行之间 。 此处加入了 extern "C"  。 cpp文件和上面格式完全一样。本人在Realease下生成dll文件。

不同2、调用方式不同。

创建C#项目参考上述引用博客。在复制dll文件时和C++调用不同的是不需要复制对应的lib文件和头文件。只需要dll一个即可,复制目录为C#工程下的bin目录,本人在x64下的realease,即

由于调用了opencv库,故需要将opencv的dll库拷进来。

 调用动态库

进入form.cs,添加命名空间,添加命名空间 

using System.Runtime.InteropServices;

引入dll库

[DllImport("txt.dll", EntryPoint = "showImg")]
public extern static int showImg(string str);

具体代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        [DllImport("txt.dll", EntryPoint = "showImg")]
        public extern static int showImg(string str);
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            showImg("C:\\Users\\hp\\Desktop\\cat.jpg");
        }
    }
}

引用dll库时,EntryPoint=“”showImg“”可不写,只写dll名称亦可。

public 关键字亦可没有。但extern static 必须保留。 

题外话:为什么C#引用dll时在生成dll库时必须声明extern "C"。具体可百度,本人理解为,加与不加的区别主要在于:

通过工具查看时,extern c 方式导出的函数, 在 DLL 中函数名就是我们定义的名字

在C++中, 不使用exern c 方式导出, 在 DLL 中函数名字已经不是我们定义时的名字了。 添加了一些特殊符号

可通过VS自带工具查看生成的dll文件,

 进入界面

输入 dumpbin -exports+dll文件的目录

回车显示 用extern "C"生成的dll文件

红色部分为dll库中包含的函数名

 回车显示 没有用extern "C"生成的dll文件

红色部分为dll文件的函数名,可以看出在生成之后 对函数名做了一些转化,进而造成C#无法调用dll文件。

猜你喜欢

转载自blog.csdn.net/xiaolifeidaoer/article/details/81232666
今日推荐