(成功案例超详细保姆级)vs2019 opencv qt创建动态库被C#调用
Posted lixiaoweia
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(成功案例超详细保姆级)vs2019 opencv qt创建动态库被C#调用相关的知识,希望对你有一定的参考价值。
之前有个项目关于图像处理,既用到了opencv,还二次开发了相机提供的动态库。一开始我是用QT写的,然后发现人家只需要我提供一个库函数调用就可以了,但是他是用C#写的。没办法,到处找资料,但是没有找到贴切的。最后自己尝试一下,终于弄好的了。其实比较困难的是我的QT动态库里还要包含另外的一个相机的库、opencv的库,然后还要依赖qt。接下来主要介绍vs2019 opencv qt创建动态库被C#调用的过程,optris相机二次开发的就放在下一篇再讲。
目录
第一步:创建一个QT 的动态库
如下图新建一个QT动态库,选择Qt Class Library,再命名(不规范不要学)选择路径,接下来会跳出来一个QT的界面,选择好对应的版本,我直接默认即可,通常最后生成Release版本。一路next,finish。最后生成一个默认模板的qt动态库。
第二步:QT动态库中引入opencv
上面是创建动态库的示意,接下来以我之前成功的QT动态库imgdeal_qtdll为例进行接下来的讲解。
首先你应该需要下载好,编译好opencv,创建相应的环境变量,正常项目中能够调用opencv,这个CSDN上有非常多的博客,搜索opencv库即可。
回到这个项目,首先像其他一样,在项目属性管理器中添加好opencv的路径(环境变量中设置的)。点击上方的项目→属性。
然后选择VC++目录,包含目录、库目录中分别中添加好opencv路径,如下图。
接下来点开C/C++→常规→附加包含目录,添加好路径。
链接器→ 输入→附加依赖项,添加opencv,我打算生成Release版本所以只添加不带d的。
最后点击确定就完成了opencv库的引入,只要在项目文件中添加好对应头文件、命名空间,就能正常使用opencv的函数了。
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/utils/logger.hpp>
using namespace cv;
第三步:动态库中创建好被调用的函数
imgdQtdll_global.h文件不用动。
imgdeal_Qtdll.h中默认生成的东西不用动,然后添加好你会用到的头文件。重要的是最后两行,创建好这个动态库你想导出,能够被调用的函数,像我这里导出了两个函数。
imgdeal_Qtdll.cpp中默认的模板不用更改,创建你在h文件中定义的想被导出的函数,注意 我是在类外创建的函数,除了两个导出的函数,其他是回调的、被导出函数调用的。
因为会需要用到比较麻烦的回调,按理来说在类内创建函数也行。需要用到的变量我也是直接在cpp文件中进行声明。
第四步:生成动态库并找到这个动态库所有的依赖项
动态库中的函数写好没有问题后,右击解决方案,选择生成/重新生成。
再右击解决方案→在文件资源管理器中打开文件夹,在文件夹中打开x64→Release,可以看到对应环境生成的动态库,dll文件。
然后很多人就直接拿着这个动态库去让C++、或者C#调用,发现不行,C#提示“应用程序中发生了未经处理的异常”、“无法加载xxx:找不到指定的模块”。、
这其实是因为你创建的动态库:第一依赖与Qt的环境,用到了Qt的变量类型;第二是调用了opencv的函数,那么opencv的动态库也要一起放过去。
为了一劳永逸,使用vs自带的dumpbin工具查找你生成的动态库的依赖项。具体可以参考这篇文章
查看dll或exe文件的依赖项——使用vs自带的dumpbin工具
使用上面的工具找到生成动态库的依赖项,如下图所示,可以看到,除了一些公用的库之外,还依赖了QtCore.dll、opencv_world454.dll、ImagerIPC2x64.dll(这个是我相机的动态库),那么我们就需要找到这些dll文件,与生成的动态库一起移动,QtCore.dll就在你安装qt目录下,例如我的是在 D:\\app\\qt\\qt5.12.9\\5.12.9\\mingw73_64\\bin 下面,注意平台要匹配,我是x64下的所以是mingw73_64文件及下面。找到所有依赖的dll文件后,再进行下一步。
第五步:创建C#项目文件调用qt生成的动态库(最坑的地方)
打开vs新建项目,这里我直接新建一个控制台应用进行测试。
代码如下:
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;
using System.Threading;
namespace WindowsFormsApp1
public partial class Form1 : Form
[DllImport("imgdeal_Qtdll.dll", EntryPoint = "imgdeal", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern void imgdeal(double leftx, double lefty, double rightx, double righty, string Path);
[DllImport("imgdeal_Qtdll.dll", EntryPoint = "Pixsanp", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern int Pixsanp();
public Form1()
InitializeComponent();
private void button1_Click(object sender, EventArgs e)
HELLOW();
public void HELLOW()
Pixsanp();
Console.WriteLine("helloword");
double leftx, lefty, rightx, righty;
leftx = 13.625; lefty = 27.667;
rightx = 14.583; righty = 27.833;
string ImagePath = "D:\\\\Imager Data\\\\";
imgdeal( leftx, lefty, rightx, righty, ImagePath);
为啥要说最坑呢?因为C#和C++的数据类型虽然名称一样,但是是完全不同的类型!!比如一个函数imgdeal(),需要传入string类型的参数,但是C++和C#的string完全不是一个东西!!!!没有办法,把C++里面的string改成与C#string对应的wchar_t*格式,然后再如图所示在qt动态库里面转成Qstring。(不要纠结为啥我一定要C++的string!!!!!)
所以在写函数的时候注意数据类型,另外师兄说灵活运用C++中的指针可以更好解决这个问题。
C++:
void imgdeal(double leftx, double lefty, double rightx, double righty, wchar_t* Path);
C#:
void imgdeal(double leftx, double lefty, double rightx, double righty, string Path);
void imgdeal(double leftx, double lefty, double rightx, double righty, wchar_t* Path)
QString ImagePath = QString::fromWCharArray(Path);
dir.setPath(ImagePath);
首次运行一下,肯定运行失败,然后将生成的动态库与所依赖的dll文件,一起复制放在选择的运行环境的文件夹下,再重新运行,即可。
以上是关于(成功案例超详细保姆级)vs2019 opencv qt创建动态库被C#调用的主要内容,如果未能解决你的问题,请参考以下文章
Hadoop 3.1.3 分布式集群搭建,超详细,保姆级教程