成功案例超详细-vs2019 opencv qt创建动态库被C#调用

之前有个项目关于图像处理,既用到了opencv,还二次开发了相机提供的动态库。一开始我是用QT写的,然后发现人家只需要我提供一个库函数调用就可以了,但是他是用C#写的。没办法,到处找资料,但是没有找到贴切的。最后自己尝试一下,终于弄好的了。其实比较困难的是我的QT动态库里还要包含另外的一个相机的库、opencv的库,然后还要依赖qt。接下来主要介绍vs2019 opencv qt创建动态库被C#调用的过程,optris相机二次开发的就放在下一篇再讲。

目录

第一步:创建一个QT 的动态库

 第二步:QT动态库中引入opencv

 第三步:动态库中创建好被调用的函数

 第四步:生成动态库并找到这个动态库所有的依赖项

 第五步:创建C#项目文件调用qt生成的动态库(最坑的地方)

第一步:创建一个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文件,一起复制放在选择的运行环境的文件夹下,再重新运行,即可。

猜你喜欢

转载自blog.csdn.net/u011555996/article/details/129072987
今日推荐