我已经使用ceres-solver很长一段时间了,这是一个了不起的工具。到目前为止,我的用法并非基于可重用代码,我正在努力改进这一点。 Ceres使用具有特定模板化方法的特定结构作为其automatic differentiation的接口。在我试图解决的问题中,继承是有道理的,因为我需要具有的不同成本函数彼此非常相似。我创建了一个类似的例子(但没有意义,抱歉)。想象一下,我们希望能够找到具有给定区域的多边形。在我的例子中,多边形可以是三角形或矩形。考虑到这一点,有一个实现所有内容的基类和在这种情况下实现每个特定多边形的区域计算的特定类是有意义的:
ShapeCostFunction
class shapeAreaCostFunction
{
public:
shapeAreaCostFunction(double desired_area): desired_area_(desired_area){}
template<typename T>
bool operator()(const T* shape, T* residual) const{
residual[0] = T(desired_area_) - area(shape);
return true;
}
template<typename T>
virtual T area(const T* shape) const = 0;
protected:
double desired_area_;
};
RectangleCostFunction
#include "shapeAreaCostFunction.h"
#include "areaLibrary.h"
class rectangleAreaCostFunction : public shapeAreaCostFunction
{
public:
rectangleAreaCostFunction(double desired_area): shapeAreaCostFunction(desired_area){}
template<typename T>
T area(const T* triangle) const
{
return rectangleArea(triangle);
}
};
TriangleCostFunction
#include "shapeAreaCostFunction.h"
#include "areaLibrary.h"
class triangleAreaCostFunction : public shapeAreaCostFunction
{
public:
triangleAreaCostFunction(double desired_area): shapeAreaCostFunction(desired_area){}
template<typename T>
T area(const T* triangle) const
{
return triangleArea(triangle);
}
};
AreaLibrary
template<typename T>
T rectangleArea(const T* rectangle)
{
return rectangle[0]*rectangle[1];
}
template<typename T>
T triangleArea(const T* triangle)
{
return rectangleArea(triangle)/T(2);
}
主要
#include <ceres/ceres.h>
#include <iostream>
#include "rectangleAreaCostFunction.h"
#include "triangleAreaCostFunction.h"
#include "areaLibrary.h"
int main(int argc, char** argv){
// Initialize glogging
//google::InitGoogleLogging(argv[0]);
// Get values
/// Get total area
double total_area;
std::cout<<"Enter the desired area: ";
std::cin>>total_area;
/// Get initial rectangle
double rect[2];
std::cout<<"Enter initial rectangle base: ";
std::cin>>rect[0];
std::cout<<"Enter initial rectangle height: ";
std::cin>>rect[1];
/// Get initial triagnle
double tri[2];
std::cout<<"Enter initial triangle base: ";
std::cin>>tri[0];
std::cout<<"Enter initial triangle height: ";
std::cin>>tri[1];
// Copy initial values
double rect_ini[] = {rect[0],rect[1]};
double tri_ini[] = {tri[0],tri[1]};
// Create problem
ceres::Problem problem;
ceres::CostFunction* cost_function_rectangle = new ceres::AutoDiffCostFunction<rectangleAreaCostFunction, 1, 2>(
new rectangleAreaCostFunction(total_area));
ceres::CostFunction* cost_function_triangle = new ceres::AutoDiffCostFunction<triangleAreaCostFunction, 1, 2>(
new triangleAreaCostFunction(total_area));
problem.AddResidualBlock(cost_function_rectangle, NULL, rect);
problem.AddResidualBlock(cost_function_triangle, NULL, tri);
// Solve
ceres::Solver::Options options;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
options.max_num_iterations = 10;
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
// Compute final areas
double rect_area = rectangleArea(rect);
double tri_area = triangleArea(tri);
// Display results
std::cout << summary.FullReport() << std::endl;
std::cout<<"Rectangle: ("<<rect_ini[0]<<","<<rect_ini[1]<<") -> ("<<rect[0]<<","<<rect[1]<<") total area: "<<rect_area<<"("<< rect_area - total_area<<")"<<std::endl;
std::cout<<"Triangle: ("<<tri_ini[0]<<","<<tri_ini[1]<<") -> ("<<tri[0]<<","<<tri[1]<<") total area: "<<tri_area<<"("<< tri_area - total_area<<")"<<std::endl;
// Exit
return 0;
}
这个问题是模板化函数不能像stackoverflow(here和here)中多次解释的那样是虚拟的。但是,似乎有一些workarounds使用boost::any
。我试图在我的例子中使用它,但没有成功。我也尝试将模板从类方法移动到类,类似于here,但是ceres不接受它作为成本函数。
我的问题是(请记住,我被限制使用方法template<typename T> bool operator()(...)const
,否则我无法与ceres互动):
template<typename T> bool operator()(...)const
类方法中调用正确的函数? 提前谢谢。
答案 0 :(得分:2)
我可以想到两种方法。
首先,撰写lambdas。其次,使用CRTP。
最好使用c++14。
template<class Area>
auto cost_function(Area area, double desired){
return [=](auto const* shape, auto* residual){
using T=std::decay_t<decltype(*shape)>;
residual[0] = T(desired_area_) - area(shape);
return true;
};
}
auto triangle = [](auto* shape){return triangleArea(shape);};
创建三角形区域成本函数:
auto tri_cost = cost_function(triangle, 3.14159);
并获取类型decltype(tri_cost)
。
所以:
auto tri_cost = cost_function(triangle, 3.14159);
ceres::CostFunction* cost_function_triangle = new ceres::AutoDiffCostFunction<decltype(tri_cost), 1, 2>(
new decltype(tri_cost)(tri_cost));
你可以做一个没有lambdas的类似组合技术,但它更乏味。你也可以将其中一些裸体新手包装在辅助函数中。
template<class D>
class shapeAreaCostFunction {
public:
shapeAreaCostFunction(double desired_area): desired_area_(desired_area){}
template<typename T>
bool operator()(const T* shape, T* residual) const{
residual[0] = T(desired_area_) - static_cast<D const*>(this)->area(shape);
return true;
}
protected:
double desired_area_;
};
修改这样的派生类型:
class triangleAreaCostFunction :
public shapeAreaCostFunction<triangleAreaCostFunction>
{
using base=shapeAreaCostFunction<triangleAreaCostFunction>;
public:
triangleAreaCostFunction(double desired_area): base(desired_area){}
template<typename T>
T area(const T* triangle) const
{
return triangleArea(triangle);
}
};
这被称为使用CRTP实现静态多态。