c#中调用CERES
因项目中需要使用Ceres进行求解计算,所以有了本文,主要思路就是用C++编写好Ceres求解的函数,然后封装成DLL,最后由C#执行调用从而得到计算结果。
Ceres编译
参考的文章:
Win10 + VS2017 + Ceres配置
Ceres-Solver库使用(一)–windows下安装配置
Ceres Solver 在Windows下安装配置笔记
参考以上几位大佬的文章,应该可以实现Ceres在windows下的配置,本人的环境为Win10 64bit,VS2017,在配置过程中也遇到了一些问题,踩坑记录如下:
在配置管理器中的预处理器中添加如下两项:
_CRT_NONSTDC_NO_DEPRECATE
_CRT_SECURE_NO_WARNINGS
在预处理器中添加
GOOGLE_GLOG_DLL_DECL=
以上两个错误是在C++编写dll库中会遇到的,在预处理器中添加
GLOG_NO_ABBREVIATED_SEVERITIES
NOMINMAX
按照参考文章中,在vs2017中新建了一个项目编译并运行成功。有些文章中说用CMake编译后,可以用命令行执行helloworld.exe,但本人按这种方法没有成功,没有找到原因。
C++编写调用Ceres的DLL
.h文件代码,主要是添加extern “C”定义导出函数
class CERESDLL_API CCeresDll {
public:
CCeresDll(void);
// TODO: 在此处添加方法。
};
extern "C" CERESDLL_API int nCeresDll;
extern "C" CERESDLL_API int fnCeresDll(void);
extern "C" CERESDLL_API double testCeresDll(void);
.cpp文件
#include "pch.h"
#include "framework.h"
#include "Ceres_Dll.h"
#include <ceres\ceres.h>
#include <glog\logging.h>
using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solver;
struct CostFunctor {
template <typename T>
bool operator()(const T* const x, T* residual) const {
residual[0] = T(10.0) - x[0];
return true;
}
};
// 这是导出变量的一个示例
CERESDLL_API int nCeresDll=0;
// 这是导出函数的一个示例。
CERESDLL_API int fnCeresDll(void)
{
return 0;
}
CERESDLL_API double testCeresDll(void)
{
google::InitGoogleLogging(new char(123));
// The variable to solve for with its initial value.
double initial_x = 5.0;
double x = initial_x;
// Build the problem.
Problem problem;
// Set up the only cost function (also known as residual). This uses
// auto-differentiation to obtain the derivative (jacobian).
CostFunction* cost_function =
new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, NULL, &x);
// Run the solver!
Solver::Options options;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
return x;
}
// 这是已导出类的构造函数。
CCeresDll::CCeresDll()
{
return;
}
C#调用DLL
新建一个控制台程序,要添加命名空间System.Runtime.InteropServices,然后定义DLL中的函数,代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace CeresDllTest_CSharp
{
class Program
{
[DllImport("CERESDLL.dll")]
private static extern int fnCeresDll();
[DllImport("CERESDLL.dll")]
private static extern double testCeresDll();
static void Main(string[] args)
{
int n = fnCeresDll();
double value = testCeresDll();
Console.WriteLine();
}
}
}
运行结果如下: