在项目程序中经常看到动态链接库,非常好奇,想自己实现一下,于是乎尝试一波。就因为这种好奇,每天都被bug所困扰。。。

1. 训练caffemodel

在windows环境下搭建caffe无果,转投Ubuntu。。。

用的caffe--example--mnist中的文件,新建文件夹的话注意改路径,下面为train.sh

#!/usr/bin/env sh
set -e /home/fish/caffe/build/tools/caffe train --solver=/home/fish/STUDY/lenet_solver.prototxt

训练好后把lenet_train_test.prototxt和训练好的模型lenet_iter_10000.caffemodel拿出来。

2. 使用cv::dnn里的API加载model,输入图片,进行测试(可跳过)

根据文章https://blog.csdn.net/sushiqian/article/details/78555891,修改模型文件。若图片为白底黑字,bitwise_not一下。

#include
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp> using namespace std;
using namespace cv;
using namespace cv::dnn; /* Find best class for the blob (i. e. class with maximal probability) */
static void getMaxClass(const Mat& probBlob, int* classId, double* classProb)
{
Mat probMat = probBlob.reshape(1, 1);
Point classNumber;
minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
*classId = classNumber.x;
} int main(int argc, char* argv[])
{
string modelTxt = "C:\\Users\\ATWER\\Desktop\\lenet_train_test.prototxt";
string modelBin = "C:\\Users\\ATWER\\Desktop\\lenet_iter_10000.caffemodel";
string imgFileName = "C:\\Users\\ATWER\\Desktop\\9.png";
//read image
Mat imgSrc = imread(imgFileName);
if (imgSrc.empty()) {
cout << "Failed to read image " << imgFileName << endl;
exit(-1);
}
Mat img;
cvtColor(imgSrc, img, COLOR_BGR2GRAY);
//LeNet accepts 28*28 gray image
resize(img, img, Size(28, 28));
bitwise_not(img, img);
img /= 255; //transfer image(1*28*28) to blob data with 4 dimensions(1*1*28*28)
Mat inputBlob = dnn::blobFromImage(img);
dnn::Net net;
try {
net = dnn::readNetFromCaffe(modelTxt, modelBin);
}
catch (cv::Exception& ee) {
cerr << "Exception: " << ee.what() << endl;
if (net.empty()) {
cout << "Can't load the network by using the flowing files:" << endl;
cout << "modelTxt: " << modelTxt << endl;
cout << "modelBin: " << modelBin << endl; exit(-1);
}
}
Mat pred;
net.setInput(inputBlob, "data");//set the network input, "data" is the name of the input layer
pred = net.forward("prob");//compute output, "prob" is the name of the output layer
cout << pred << endl; int classId; double classProb; getMaxClass(pred, &classId, &classProb);
cout << "Best Class: " << classId << endl;
cout << "Probability: " << classProb * 100 << "%" << endl;
}

3. 创建动态链接库

参考https://blog.csdn.net/qq_30139555/article/details/103621955

class.h

#include
#include <opencv2/opencv.hpp>
#include <opencv2/dnn/dnn.hpp> using namespace std;
using namespace cv;
using namespace cv::dnn; extern "C" _declspec(dllexport) void Classfication(char* imgpath, char* result);

在此处卡的最久,原本我写的是Classfication(string imgpath, string result),生成dll时没问题,调用时总是System.AccessViolationException: 尝试读取或写入受保护的内存。后来发现要写成指针的形式。

class.cpp

#include
#include <opencv2/opencv.hpp>
#include <opencv2/dnn/dnn.hpp>
#include "class.h"
using namespace std;
using namespace cv;
using namespace cv::dnn; /* Find best class for the blob (i. e. class with maximal probability) */
static void getMaxClass(const Mat& probBlob, int* classId, double* classProb)
{
Mat probMat = probBlob.reshape(1, 1);
Point classNumber;
minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
*classId = classNumber.x;
} void Classfication(char* imgpath, char* result)
{
string res = "";
string modelTxt = "C:\\Users\\ATWER\\Desktop\\lenet_train_test.prototxt";
string modelBin = "C:\\Users\\ATWER\\Desktop\\lenet_iter_10000.caffemodel";
//string imgFileName = "C:\\Users\\ATWER\\Desktop\\9.png";
string imgFileName = imgpath;
//read image
Mat imgSrc = imread(imgFileName);
if (imgSrc.empty()) {
cout << "Failed to read image " << imgFileName << endl;
exit(-1);
}
Mat img;
cvtColor(imgSrc, img, COLOR_BGR2GRAY);
//LeNet accepts 28*28 gray image
resize(img, img, Size(28, 28));
bitwise_not(img, img);
img /= 255; //transfer image(1*28*28) to blob data with 4 dimensions(1*1*28*28)
Mat inputBlob = dnn::blobFromImage(img);
dnn::Net net;
try {
net = dnn::readNetFromCaffe(modelTxt, modelBin);
}
catch (cv::Exception& ee) {
cerr << "Exception: " << ee.what() << endl;
if (net.empty()) {
cout << "Can't load the network by using the flowing files:" << endl;
cout << "modelTxt: " << modelTxt << endl;
cout << "modelBin: " << modelBin << endl; exit(-1);
}
}
Mat pred;
net.setInput(inputBlob, "data");//set the network input, "data" is the name of the input layer
pred = net.forward("prob");//compute output, "prob" is the name of the output layer
int classId;
   double classProb;
   getMaxClass(pred, &classId, &classProb);
res += to_string(classId);
res += '|';
res += to_string(classProb);
strcpy_s(result, 15, res.c_str());
}

4. 调用动态链接库

根据数据的长度申请非托管空间参考:https://blog.csdn.net/xiaoyong_net/article/details/50178021

文中说:“一定要加1,否则后面是乱码,原因未找到 ”,应该是打印字符串时会打印到“\n”为止,没有遇到\n会一直打印下去。.Length方法没有计算"\n",+1的空间用于存放“\n”。

using System;
using System.Runtime.InteropServices; namespace Test
{
class Program
{
[DllImport("E:/c++project/caffedll/x64/Debug/caffedll.dll", EntryPoint = "Classfication")] unsafe private static extern void Classfication(IntPtr imgpath, IntPtr result);
private static IntPtr mallocIntptr(string strData)
{
//先将字符串转化成字节方式
Byte[] btData = System.Text.Encoding.Default.GetBytes(strData);
//申请非拖管空间
IntPtr m_ptr = Marshal.AllocHGlobal(btData.Length);
//给非拖管空间清0
Byte[] btZero = new Byte[btData.Length + 1]; //一定要加1,否则后面是乱码,原因未找到
Marshal.Copy(btZero, 0, m_ptr, btZero.Length);
//给指针指向的空间赋值
Marshal.Copy(btData, 0, m_ptr, btData.Length);
return m_ptr;
}
private static IntPtr mallocIntptr(int length)
{
//申请非拖管空间
IntPtr m_ptr = Marshal.AllocHGlobal(length);
//给非拖管空间清0
Byte[] btZero = new Byte[length];
Marshal.Copy(btZero, 0, m_ptr, btZero.Length);
//给指针指向的空间赋值
Marshal.Copy(btZero, 0, m_ptr, length);
return m_ptr;
}
static void Main(string[] args)
{
string s = "C:\\Users\\ATWER\\Desktop\\9.png";
IntPtr ptrFileName;
IntPtr res;
//根据数据的长度申请非托管空间
ptrFileName = mallocIntptr(s);
res = mallocIntptr(50);
Classfication(ptrFileName, res);
string result = Marshal.PtrToStringAnsi(res);
string[] a = result.Split('|');
Console.WriteLine("class:"+a[0]+"\n"+"score:"+a[1]);
Marshal.FreeHGlobal(res);
}
}
}

将mnist训练的caffemodel生成动态链接库DLL的更多相关文章

  1. MinGW gcc 生成动态链接库 dll 的一些问题汇总 (补充)

    我以前写过一个小短文,介绍MinGW gcc 生成动态链接库 dll 的一些问题.当时写的并不全面.近期又遇到写新的问题.这里记录一下,做个补充. 通常情况下,dll 中的函数假设採用 _stdcal ...

  2. dll = MinGW gcc 生成动态链接库 dll 的一些问题汇总

    MinGW gcc 生成动态链接库 dll 的一些问题汇总 https://blog.csdn.net/liyuanbhu/article/details/42612365 网络上关于用 MinGW  ...

  3. 使用python创建生成动态链接库dll

    如今,随着深度学习的发展,python已经成为了深度学习研究中第一语言.绝大部分的深度学习工具包都有python的版本,很多重要算法都有python版本的实现.为了将这些算法应用到具体工程中,这些工具 ...

  4. MinGW gcc 生成动态链接库 dll 的一些问题汇总(由浅入深,很详细)

    网络上关于用 MinGW gcc 生成动态链接库的文章很多.介绍的方法也都略有不同.这次我在一个项目上刚好需要用到,所以就花了点时间将网上介绍的各种方法都实验了一遍.另外,还根据自己的理解试验了些网上 ...

  5. 从一到二:利用mnist训练集生成的caffemodel对mnist测试集与自己手写的数字进行测试

    通过从零到一的教程,我们已经得到了通过mnist训练集生成的caffemodel,主要包含下面四个文件: 接下来就可以利用模型进行测试了.关于测试方法按照上篇教程还是选择bat文件,当然python. ...

  6. 利用mnist训练集生成的caffemodel对mnist测试集与自己手写的数字进行测试

    从一到二:利用mnist训练集生成的caffemodel对mnist测试集与自己手写的数字进行测试 通过从零到一的教程,我们已经得到了通过mnist训练集生成的caffemodel,主要包含下面四个文 ...

  7. 动态链接库DLL的创建生成及调用

    一.背景 最近在做CANTOUSB底层驱动的调用,是调用别人已经封装好的库,看不到别人写的源程序.程序中调用的是隐式调用即 x.h+x.lib+x.dll,其中DLL即是动态链接库(Dynamic L ...

  8. C#调用C++生成的动态链接库DLL

    一.背景 由于要使用C#写app,所以要把C++生成的DLL在C#中调用,所以就涉及怎样去调用外部的dll问题. 二.C#调用外部DLL 首先先看下C#调用外部DLL的代码 using System. ...

  9. 编译可供C#调用的C/C++动态链接库dll文件

    编译可供C#调用的C/C++动态链接库dll文件,C语言控制台应用程序,探索生成dll过程 由于项目需求,需要公司另一个团队提供相关算法支持,是用C语言编译好的dll库提供给我们进行调用. 但是拿到d ...

  10. VC++动态链接库(DLL)编程深入浅出(zz)

    VC++动态链接库(DLL)编程深入浅出(zz) 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用 ...

随机推荐

  1. docker 应用篇————nginx 例子[六]

    前言 简单整理一下nginx 例子. 正文 拉取nginx 镜像. docker pull nginx 那么会拉取nginx:latest 这个. 如果需要其他的,可以去官网查询一下. 2.docke ...

  2. WPF/C#:让绘制的图形可以被选中并将信息显示在ListBox中

    实现的效果 如果你对此感兴趣,可以接着往下阅读. 实现过程 绘制矩形 比如说我想绘制一个3行4列的表格: private void Button_Click_DrawRect(object sende ...

  3. 深度解读《深度探索C++对象模型》之数据成员的存取效率分析(一)

    接下来我将持续更新"深度解读<深度探索C++对象模型>"系列,敬请期待,欢迎关注!也可以关注公众号:iShare爱分享,自动获得推文和全部的文章列表. 在<深度解 ...

  4. 安装Visual Studio 2010 教程

    1.下载软件 方法一:关注[ 火耳软件安装 ]公众号获取软件,里面还有很多类型的其他软件 或者: 方法二:我的分享链接:https://pan.baidu.com/s/1_Ow2YR-kbnbSc6o ...

  5. 通过 MSE 实现基于Apache APISIX的全链路灰度

    简介: 无论是微服务网关还是微服务本身都需要识别流量,根据治理规则做出动态决策.当服务版本发生变化时,这个调用链路的转发也会实时改变.相比于利用机器搭建的灰度环境,这种方案不仅可以节省大量的机器成本和 ...

  6. 云上技术 | 混合云管理平台多Region架构

    简介: 随着现代化进程加速,企业业务规模和迭代速度也今非昔比,在已具备一定规模的中大型电力系统中,会面临着数字化升级的压力,包括复杂组织架构管理.计算资源弹性扩展.IT运维提效等需求.基于电力行业属性 ...

  7. EDA 事件驱动架构与 EventBridge 二三事

    ​简介: 事件驱动型架构 (EDA) 方兴未艾,作为一种 Serverless 化的应用概念对云原生架构具有着深远影响.当我们讨论到一个具体架构时,首当其冲的是它的发展是否具有技术先进性.这里从我们熟 ...

  8. [K8s] Kubernetes核心基础概念 Node, Pod, ReplicaSet, Deployment, Service, Ingress, ConfigMap

    Node 即 Kubernetes 集群中的一台工作机器,物理机或者虚拟机. https://kubernetes.io/zh/docs/concepts/architecture/nodes/ 通常 ...

  9. 尝试 IIncrementalGenerator 进行增量 Source Generator 生成代码

    在加上热重载时,源代码生成 Source Generator 的默认行为会让 Visual Studio 有些为难,其原因是热重载会变更代码,变更代码触发代码生成器更新代码,代码生成器更新的代码说不定 ...

  10. 使用 Silk.NET 创建 OpenGL 空窗口项目例子

    本文告诉大家如何使用 Silk.NET 创建 OpenGL 空窗口项目.在 dotnet 基金会下,开源维护 Silk.NET 仓库,此仓库提供了渲染相关的封装逻辑,包括 DX 和 OpenGL 等等 ...