Dotnet使用OpenCV库有两种方式:
一是使用opencvsharp,目前已经支持到OpenCV4.5.3。
二是使用C++编译源码,生成托管或者非托管的dll,给Dotnet使用。
推荐方式一的OpenCVSharp,可以直接使用,但是他发布的版本默认设置BUILD_opencv_wechat_qrcode=OFF,关闭了微信解码库,因此感兴趣的同学需要自己编译了。笔者因为之前需要,已经编译了C++版本的OpenCV4.5.2,所以再次封装dll更加便捷。
笔者的编译环境跟下面文章一致,所以直接参考下面大神的文章吧,很详细。
win10 下编译用于 Visual Studio 2019 的 OpenCV4.5.2(含 opencv_contrib 扩展模块)附编译好的OpenCV(图文)
首先解释一下,托管DLL和非托管DLL的区别:
1,狭义解释讲,托管DLL就在Dotnet环境生成的DLL文件。非托管DLL不是在Dotnet环境生成的DLL文件。
2,托管DLL文件,可以在Dotnet环境通过 “添加引用” 的方式,直接把托管DLL文件添加到项目中。然后通过 Using DLL命名空间,来调用相应的DLL对象 。非托管DLL文件,在Dotnet环境应用时,通过 DllImport 调用。
3,非托管需要对调用方法一个个声明引用,托管则不需要
参考文章:托管DLL和非托管DLL的区别
笔者是在C++环境编译好的OpenCV,再次封装一个接口给C#调用,所以选非托管。
代码如下(示例):
ZrdDecoder.h
#pragma once
#include
#include
#include
//extern "C" _declspec(dllexport) int Init();
extern "C" _declspec(dllexport) const char* Decoder(const char*);
//存放解码结果
char decoder_result[256] = { 0 };
//微信解码器构造
cv::Ptr<cv::wechat_qrcode::WeChatQRCode> detector = nullptr;
class ZrdDecoder
{
};
ZrdDecoder.cpp
#include "ZrdDecoder.h"
int Init()
{
try {
detector = cv::makePtr<cv::wechat_qrcode::WeChatQRCode>(
"models\\detect.prototxt",
"models\\detect.caffemodel",
"models\\sr.prototxt",
"models\\sr.caffemodel");
return 0;
}
catch (const std::exception& e) {
std::cout <<
"\n---------------------------------------------------------------\n"
"Failed to initialize WeChatQRCode.\n"
"Please, download 'detector.*' and 'sr.*' from\n"
"https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n"
"and put them into the current directory.\n"
"---------------------------------------------------------------\n";
std::cout << e.what() << std::endl;
return -1;
}
}
const char* Decoder(const char* imgpath)
{
if (!imgpath)
{
return "";
}
cv::Mat img = cv::imread(imgpath);
if (!img.data)
{
return "";
}
if (!detector)
{
if (Init() < 0)
{
return "";
}
}
std::vector<cv::Mat> points;
auto res = detector->detectAndDecode(img, points);
if (res.size() > 0)
{
memset(decoder_result, 0, 256);
memcpy(decoder_result, res[0].c_str(), res[0].length());
return decoder_result;
}
else
{
return "";
}
}
示例代码只封装了一个接口Decoder,且只返回第一个二维码的识别结果,如果需要其他接口或者返回值如二维码区域等可以自己封装。
1,项目–属性—配置属性–VC++目录—包含目录,填入已经编译好的OpenCV头文件位置
D:\opencv-4.5.2-contrib\opencv\newbuild\install_src\include
D:\opencv-4.5.2-contrib\opencv\newbuild\install_src\include\opencv2
2,项目–属性—配置属性–VC++目录—库目录,填入已经编译好的opencv_world452d.lib文件位置
D:\opencv-4.5.2-contrib\opencv\newbuild\install_src\x64\vc16\lib
4,拷贝模型文件
模型文件是CNN神经网络对二维码定位用的,拷贝到代码能找到的位置即可。
1,项目–属性—配置属性–常规—配置类型—动态库(.dll)
,2,项目–属性–配置属性–C/C++–高级—编译为—编译为C++代码(/TP)
3,生成
1,创建C#控制台应用程序:
using System;
using System.Runtime.InteropServices;
namespace ZrdDecoderDemo
{
class Program
{
[DllImport("ZrdDecoder.dll", CallingConvention = CallingConvention.Cdecl)]
extern static IntPtr Decoder(IntPtr path);
static void Main(string[] args)
{
try
{
IntPtr imgpath = Marshal.StringToHGlobalAnsi("images\\2021-12-18-19-02-37-cap.jpg");
IntPtr result = Decoder(imgpath);
string strResult = Marshal.PtrToStringAnsi(result);
Console.WriteLine("二维码识别结果:" + strResult);
}
catch (Exception ex)
{
Console.WriteLine($"ex:{ex}");
}
Console.ReadLine();
}
}
}
2,拷贝需要的库和模型
images:待测试的二维码图片,可以任意位置,代码能找到就行
models:上述四个模型文件,需要ZrdDecoder.dll能找到
opencv_wrold452d.dll:opencv和opencv_contrib的debug库
ZrdDecoder.dll:C++生成的库
文章配置均为debug环境,示例代码简洁为主
参考文章:https://blog.csdn.net/yumkk/article/details/106746882