C ++共享库API中使用的数据类型

时间:2017-05-06 20:33:56

标签: c++ api opencv data-structures eigen3

我正在编写一个C ++共享库(.so),其主要功能是处理OpenCV处理的图像中的特征。但是,此共享库中的算法并非专门用于视觉 - 它可以从RADAR,LiDAR等接收测量结果。

当我构建库时,我试图保持OpenCV依赖性,而不是使用更通用的Eigen3矩阵库。

我的问题是关于应用程序代码和我的库之间的接口。我有一个公共方法,它将接受应用程序中每个特征的位置和速度测量列表:

void add_measurements(std::vector< std::tuple<double, double> > pos, 
                      std::vector< std::tuple<double, double> > vel);

最好是将API接口上的数据结构保留为原始数据,如上所述?或者我应该强制应用程序代码为测量提供std::vector<Eigen::Vector2d>吗?

此外,我应该从应用程序代码中允许std::vector<cv::Point2f>,然后只是转换为Eigen3或其他内部?这个似乎是最不实用的,因为该库仍然依赖于OpenCV。

2 个答案:

答案 0 :(得分:2)

您可以使用泛型来桥接不同的数据约定,而不会牺牲性能。

缺点是界面可能有更高的学习曲线。

首先,您可以接受 iterators ,而不是接受向量,它允许用户在其他容器中提供数据,例如 arrays 列表

template<typename AccessType, typename PosIter, typename VelIter>
void add_measurements(PosIter p1, PosIter p2, VelIter v1, VelIter v2)
{
    // instantiate type to access coordinates
    AccessType access;

    // process elements

    // Internal representation
    std::vector<std::pair<double, double>> positions;

    for(; p1 != p2; ++p1)
        positions.emplace_back(access.x(*p1), access.y(*p1));

    std::vector<std::pair<double, double>> velocities;

    for(; v1 != v2; ++v1)
        positions.emplace_back(access.x(*v1), access.y(*v1));

    // do stuff with the data
}

然后,如果他们有一个奇怪的数据类型,他们想要这样使用:

struct WeirdPositionType
{
    double ra;
    double dec;
};

他们可以创建一个类型来访问其内部点坐标:

// class that knows how to access the
// internal "x/y" style data
struct WeirdPositionTypeAccessor
{
    double x(WeirdPositionType const& ct) const { return ct.ra; }
    double y(WeirdPositionType const& ct) const { return ct.dec; }
};

然后“插入”通用函数:

int main()
{
    // User's weird and wonderful data format
    std::vector<WeirdPositionType> ps = {{1.0, 2.2}, {3.2, 4.7}};
    std::vector<WeirdPositionType> vs = {{0.2, 0.2}, {9.1, 3.2}};

    // Plugin the correct Access type to pull the data out of your weirt type
    add_measurements<WeirdPositionTypeAccessor>(ps.begin(), ps.end(), vs.begin(), vs.end());

    // ... etc
}

当然,您可以为公共点库提供现成的 Access类型,例如OpenCv

struct OpenCvPointAccess
{
    double x(cv::Point2d const& p) const { return p.x; }
    double y(cv::Point2d const& p) const { return p.y; }
};

然后使用可以简单地使用:

add_measurements<OpenCvPointAccess>(ps.begin(), ps.end(), vs.begin(), vs.end());

答案 1 :(得分:1)

请记住,您可以重载功能以支持多种容器。如果您认为两者都有用,则无需在它们之间进行选择。

因此,主要考虑因素是每种方式的开销,以及是否要在Eigen上添加依赖项。如果库的未来版本具有不同的实现,则不希望使用漏洞抽象。

另一个有用的技巧是在名称空间中添加类型别名:

using point2d = std::tuple<double, double>;

您可以稍后更改为:

using point2d = Eigen::vector2d;

或者:

using point2d = cv::Point2f;

通过将它们包装在结构中,可以使它们更加不透明。如果这样做,将来的更改将破坏与先前ABI的兼容性,但不会破坏API。