C#调用C++图像处理算法(opencv)

C#调用C++图像处理算法(OpenCV)

因为需要做一个图像处理的程序,后来决定采用C#写界面,C++写算法调用opencv的函数。关于opencv的使用之前已经学习过了,需要实现的是在C#中如何使用C++语言编写的DLL。

参考:
CSDN支持语法高亮的常用语言

本开发环境为win10+vs2010

C++编程笔记:dll的生成与使用

参考:C++编程笔记:dll的生成与使用

这个博客讲了dll是什么以及静态动态dll的区别还有dll的创建和使用,特别是隐式和显式链接方式加载dll。函数的名字自动改编导致错误的解决方案。

新建一个C++的dll(非托管类)

参考:C++创建dll文件及使用方法

新建解决方案 =>【添加】【新建项目】=>【Visual C++】>【Win32 项目】> 输入名称:DllTest)> 完成 => 向导【下一步】>【DLL】> 【完成】

头文件夹中新建头文件 dllTest.h


// dllTest.h
#ifndef DllTest_H_  
#define DllTest_H_  
#ifdef MYLIBDLL  
#define MYLIBDLL extern "C" _declspec(dllimport)   
#else  
#define MYLIBDLL extern "C" _declspec(dllexport)   
#endif  
MYLIBDLL int Add(int plus1, int plus2);  
//You can also write like this:  
//extern "C" {  
//_declspec(dllexport) int Add(int plus1, int plus2);  
//};  
//also like this:
//extern "C" _declspec(dllexport) int Add(int plus1, int plus2);
#endif  
// extern "C"外部声明,表示函数和变量是按照C语言的方式编译和链接的。
// _decspec(dllexport)的目的是为了将对应的函数放入到DLL动态库中。
// extern "C" _declspec(dllexport)的目的是为了使用DllImport调用非托管C++的DLL文件。
// 因为使用DllImport只能调用由C语言函数做的DLL。

源文件夹中新建cpp文件 dllTest.cpp


// DllTest.cpp : 定义 DLL 应用程序的导出函数。

#include "stdafx.h"  
#include "dllTest.h"  
#include <iostream>  
using namespace std;  
int Add(int plus1, int plus2)  
{  
    int add_result = plus1 + plus2;  
    return add_result;  
}  

在资源文件夹中新建模板定义文件 dllTest.def


LIBRARY "DllTest"  // 这个名字最好和项目名称相同 在我测试时不同会产生一个错误
EXPORTS  
Add @1   // 这里是否改为 Add  不知道

在本项目中只写了一个Add函数,点击【启动调式】(Debug模式),将会在【解决方案】文件夹中的【Debug】文件夹中产生 DllTest.lib,和 DllTest.dll,在使用DLL时会需要这两个文件加 dllTest.h。

使用DLL时:【属性管理器】>【Microdoft.Cpp.Win32.user】>右键>【属性】>【链接器】>【输入】>【附加依赖项】要添加 DllTest.lib,【VC++目录】的【可执行文件项】添加 DllTest.dll 所在目录,【包含目录】添加 dllTest.h 所在目录即可。

在另一个c++项目中使用它

参考:C++创建dll文件及使用方法

新建c++空项目Test,在源文件夹中新建 main.cpp


//== 依赖添加
//#include <opencv2/opencv.hpp>
//#include <opencv2/core/core.hpp>   
//#include <opencv2/imgproc/imgproc.hpp>  //opencv图像处理头文件
//#include <opencv2/highgui/highgui.hpp>   //opencv  highgui模块头文件
#include <iostream>

#include "dllTest.h"

//== 命名空间
//using namespace cv;
using namespace std;

//== 函数声明


//== 程序入口
int main(int argc, char* args)
{
    int a,b;  
    while(1)  
    {  
        cin>>a>>b;  
        cout<<Add(a,b)<<endl;  
    }

    // waitKey(0);  // 好像是cv的函数
    // system("pause")
    return 0;
}

生成时出了一个错误,无法打开dllTest.def文件

1>------ 已启动生成: 项目: Test, 配置: Debug Win32 ------
1>生成启动时间为 2018/3/21 21:51:341>InitializeBuildStatus:
1>  正在对“Debug\Test.unsuccessfulbuild”执行 Touch 任务。
1>ClCompile:
1>  所有输出均为最新。
1>LINK : fatal error LNK1104: 无法打开文件“dllTest.def1>
1>生成失败。
1>
1>已用时间 00:00:00.25
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

原因是【属性管理器】中【链接器】【输入】【模块定义文件】中添加了文件 dllTest.def,删除后生成正确且没有任何警告报错等。
输入 12 35 得到结果 47 。

在C#中使用非托管类C++的dll

参考 C#调用C++ dll 总结 内含(opencv)

c++的(非托管类)dll(Release模式下) 生成后会在项目所在文件夹的Realease里面找到所生成的dll.

新建一个C#控制台应用程序,将上文所生成的DLL拷贝到C#应用程序的bin里面然后应用如下方式进行调用:

[DllImport(“ COM DLL path/file ”)]
extern static int FunctionName(byte param1, ushort param2)

具体调用的时候在参数传递的过程中会遇到问题,具体解决方式见这篇博客C#时常需要调用C++DLL

在C#与C++之间常用的参数传递

将string转为IntPtr:IntPtr System.Runtime.InteropServices.Marshal.StringToCoTaskMemAuto(string)
将IntPtr转为string:string System.Runtime.InteropServices.MarshalPtrToStringAuto(IntPtr)
c++ <----------> c#
BSTR ---------  StringBuilder
LPCTSTR --------- StringBuilder
LPCWSTR ---------  IntPtr
handle---------IntPtr
hwnd-----------IntPtr
char *----------string
int * -----------ref int
int &-----------ref int
void *----------IntPtr
unsigned char *-----ref byte
Struct需要在C#里重新定义一个Struct
CallBack回调函数需要封装在一个委托里,delegate static extern int FunCallBack(string str);
注意在每个函数的前面加上public static extern +返回的数据类型,如果不加public ,函数默认为私有函数,调用就会出错。

C#中的代码 Test.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Project1
{
    class Test
    {
        [DllImport(@"D:\AppCache\Visual Studio 2010\Projects\DllLibs\DllTest.dll", EntryPoint = "Add")]
        // 如果将DLL放进bin目录下就可以改为 [DllImport("DllTest.dll", EntryPoint = "Add")]
        extern static int Add(int a, int b);

        static void Main(String[] args)
        {
            //Console.WriteLine("Hello World");
            int c = Add(1, 2);
            Console.WriteLine(c);

            Console.ReadKey();
        }
    }
}

很遗憾产生了一个错误,选择继续后会显示正确的结果。
产生了一个错误

新建托管类c++的dll

参考:C#C++混合编程

非托管类会存在一些问题,而这些问题的解决方式可能有点麻烦,就可以选择 C++函数=>托管类封装=>C#调用的形式进行。

我的GitHub

所有参考:
CSDN支持语法高亮的常用语言在Markdown模式下在开头的三个反引号后加语言关键字
如何在写CSDN博客时插入代码
C++创建dll文件及使用方法
C#调用C++ dll 总结 内含(opencv)
C#时常需要调用C++DLL
C#C++混合编程
opencv的安装与环境配置
C#调用openCV函数及其移植
【开发日记】C#调用C++图像处理算法(opencv)
C#调用C++动态库(dll)
C#与C++ DLL的交互
在VS2015中用C++编写可被其它语言调用的动态库DLL
在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
利用C++制作dll并调用dll
C#调用 opencv cv::Mat 图像, 采用折中方法

猜你喜欢

转载自blog.csdn.net/wagsn8/article/details/79646979