C#调用OpenCV(C++原版)思路和实现方法(小白教程)

前言:

原本想着用OpenCV的话,只需考虑在编程语言环境下调用对应的库(包)就行了,因为之前也是做了一个利用python(OpenCV-python接口)下编写了一个停车场空位识别项目,但是没接触过实际的我,天真地认为这些语言封装库接口已经可以实现原本OpenCV的所有功能,但是看了面试题目和网上查询相关资料,发现语言封装库其实或多或少是原版OpenCV的各种阉割版,毕竟也可以理解:在为各种语言封装时肯定会牺牲本身的一些接口和API功能!
因此,原版的OpenCV非常强大,继承了C的快速和C++优秀的图形处理性能,由于C++和C语法糖和应用项目化其实没有.net C#好,实际的生成环境更是一种特殊的情况:用C#编写脚本(项目)调用原版的OpenCV(C++)!
为了展示和记录特意写了这一博文,希望大家能多多勘误!

一,下载和安装OpenCV到本地

为什么要本地安装呢?因为既然调用那么必须是要获得相应OpenCV接口的调头文件或者C++文件!

下载可到官网去下载,主要看看是什么对应的系统环境(windows,Linux,Mac OX)!
由于你的VS版本要与OpenCV的SDK文件对应(比如我的VS2019是要VC15或16),这里是VS-VC对应版本表
下载文件安装程序其实可以发现,该版本是269MB,实际安装到文件目录后是2点多个G!(可见里面的功能和文件是多么丰富的!随着版本的更新,这只会越庞大,所以要留足内存哦!)
实际配置方法可参考我写的这个:VS2019如何永久配置本地OpenCV4.5.5使用
配置必须完成,不然后面的步骤根本没办法做!

二,主要原理

c#和C++虽然两者衍生自C语言爸爸,两者更是有多个类似的地方,但是终究语言环境的差异,这两者并不能互通,但是做好接口和生成和调用.dll(动态链接库)就可以无缝连接,这也是目前C#做视觉应用的一个常用点!

  • C#调用OpenCV(c++的.dll主要有两种常见的方式:托管和非托管两种形式!
  • 非托管的形式即是采用[DllImport]的形式,这种形式只能调用的C++的函数,适合用于简单的图形处理调用,这也是非常便捷的方法,由于只是演示C#调用OpenCV(c++的.dll),本文主要采用该方法!
  • 托管的形式用的是ref,可以调用C++类中的方法,适用于处理比较复杂的图形处理,特别是封装成类和方法,使得C#调用时处理复杂情景更好!

开发环境:与上文配置vs与opencv一样!

  • windows10专业版
  • opencv4.5.5
  • VS2019
  • C# .NET Framework4.5控制台应用程序

三,C++生成供C#调用OpenCV的.dll

既然要用到第一种方法那么就要建立一个C++空项目来生成.dll文件!

  • 在vs2019下,新建空项目:
    在这里插入图片描述
    在这里插入图片描述

1.添加头文件

点击头文件夹,右键点击添加->添加新建项(或者点击头文件后,快捷键Ctrl+Shift+A)
在这里插入图片描述
在这里插入图片描述
接着添加demo.h内容:

#pragma once
extern "C" __declspec(dllexport) void toCV();

上面得说明下的是,toCV();是我们后面在demo.cpp文件添加的返回为空的调用函数名,可根据自己实际添加!

2.添加cpp文件

在这里插入图片描述

  • 在demo.cpp文件下添加以下代码:
#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs/legacy/constants_c.h"
#include <opencv2/opencv.hpp>
#include <time.h>
#include"demo.h"  //这里对应你新建的那个头文件

using namespace std;
using namespace cv;

void toCV()
{
    //从文件中读入图像
    Mat img = imread("1.jpg", 1);
    Mat dst;

    //如果读入图像失败
    if (img.empty()) {
        printf("打开图片失败!\n");
    }
    namedWindow("RGB", WINDOW_AUTOSIZE);
    imshow("RGB", img);
    cvtColor(img, dst, COLOR_BGR2GRAY);
    namedWindow("GRAY", WINDOW_AUTOSIZE);
    imshow("GRAY", dst);
    printf("测试成功!成功把rgb图转成灰度图!");
    //此函数等待按键,按键盘任意键就返回
    waitKey(0);
}

以上代码主要是将一个RGB原图转化为灰度图,并打印输出成功提示和两张图的窗口的函数toCV(),与前面的demo.h那个名称对应!

3.添加模块定义文件

点击源文件夹,右键点击添加->添加新建项(或者点击头文件后,快捷键Ctrl+Shift+A)
在这里插入图片描述
在Source.def下添加下面代码:

LIBRARY demo
  EXPORTS toCV

这里说明下:

  • LIBRARY 后跟着你的项目名(比如demo);
  • EXPORTS 后跟着你的调用函数名(比如toCV);

接着,先保存所有文件,看看有误语法错误等提示,如果没有,再按下面指示操作!
在这里插入图片描述
点击vs最顶的菜单->项目->对应的项目名属性
在这里插入图片描述

在这里插入图片描述

完成上面配置方可点击重新生成解决方案,不然会报错,常见是上面配置类型没有选择.dll而是选择了.exe!
在这里插入图片描述
在这里插入图片描述

四,建立C#调用.dll的控制台程序

  • 你可以选择其他应用项目,只要能利用C++.dll中的tocv函数都行,为了简单演示,只是新建.net 控制台程序!
    在这里插入图片描述
    在这里插入图片描述

完成配置后,点击启动程序(此时程序代码是默认给出的,可先不用管),让项目生成x64的debug文件先!接着把所需图片和C++生成的.dll放到该目录下,如下所示:
在这里插入图片描述

  • 接着添加Program.cs的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
using System.Runtime.InteropServices;//由于使用非托管,一定得添加这个

namespace App
{
    class Program
    {
        [DllImport("demo.dll")]    
        private extern static void toCV();  
        static void Main(string[] args)
        {
            toCV();
            ReadKey();
        }
    }
}

再点击启动程序,即可出现以下画面!
在这里插入图片描述
接着想说的是,由于OpenCV版本太新,里面应用的函数名参数配置,头文件引用等,都会发生很大的变化,当你用的是新版本,vs中使用一般的图形处理函数可能函数构造和引用都发生很大变化,vs会提示引用文件不存在或函数构造无标识,所以不要怀疑,得查看官方源码或文档,及时替换,另一种解决方式是,使用旧版本的OpenCV,这样变化不多,而且资料很多!

五,参考资料推荐

最后文中若有不足,敬请批评指正!

要在C#调用C++编写的OpenCV dll,可以使用Platform Invoke(P/Invoke)技术。下面是一个简单的示例,演示如何在C#调用C++编写的OpenCV dll: 1. 创建一个新的C#控制台应用程序。 2. 在项目文件夹中创建一个名为“opencv”的子文件夹。 3. 将OpenCV dll文件复制到该子文件夹中。 4. 在Visual Studio中打开项目,并添加以下代码: ```C# using System; using System.Runtime.InteropServices; class Program { [DllImport("opencv\\opencv_core320.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr cvCreateImage( [MarshalAs(UnmanagedType.Struct)] CvSize size, int depth, int channels); static void Main(string[] args) { // 创建一个256x256的8位单通道图像 var size = new CvSize(256, 256); var image = cvCreateImage(size, 8, 1); // 在控制台中输出图像信息 Console.WriteLine("Image created: {0}x{1}, depth={2}, channels={3}", size.Width, size.Height, 8, 1); Console.ReadKey(); } } [StructLayout(LayoutKind.Sequential)] public struct CvSize { public int Width; public int Height; public CvSize(int width, int height) { Width = width; Height = height; } } ``` 上面的代码创建了一个256x256的8位单通道图像,并在控制台中输出了图像信息。 在上面的代码中,我们使用DllImport属性来指定要导入的OpenCV dll的名称和调用约定。在本例中,我们使用Cdecl调用约定。 我们还定义了一个结构体CvSize,用于传递图像大小参数。在C++中,CvSize结构体定义在opencv_core.hpp头文件中。我们在C#中重新定义了这个结构体,以便我们可以在C#中使用它来传递参数。 需要注意的是,由于C++C#使用不同的内存管理机制,因此您需要确保在C#中正确处理从C++返回的指针。在本例中,我们使用IntPtr类型来表示从C++返回的指针,并使用Marshal类中的相关方法来管理它们。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值