【问题标题】:How to resize a Vector in Eigen3如何在 Eigen3 中调整向量的大小
【发布时间】:2013-03-07 02:59:08
【问题描述】:

我将两个 Eigen3 向量包装在一个模板化的 LineSegment<T,dim> 类中。你可以这样使用它:

typedef LineSegment<double,2> LineSegment2d;
typedef LineSegment<double,3> LineSegment3d;
typedef LineSegment<int,3> LineSegment3i;

它包含一个模板化的方法来改变组件的尺寸。这是修剪后的定义:

template<typename T,int dim>
struct LineSegment
{
public:
  template<int newDim>
  LineSegment<T,newDim> to() const
  {
    Eigen::Matrix<T,newDim,1> newp1;
    Eigen::Matrix<T,newDim,1> newp2;

    // TODO initialise newp1 and newp2 from d_p1 and d_p2

    return LineSegment<T,newDim>(newp1, newp2);
  }

  // ... other members ...

protected:
  Eigen::Matrix<T,dim,1> d_p1;
  Eigen::Matrix<T,dim,1> d_p2;
}

所以我的问题是,我该如何组合返回值,如上图所示?这应该支持增加和减少维度。

我尝试使用 Eigen3 resize(int) 方法,但在没有看到有关混合矩阵大小的警告的情况下无法使其工作。

最终,这应该可行:

LineSegment2d ls2d;
LineSegment3d ls3d = ls2d.to<3>(); // increase dim
ls2d = ls3d.to<2>();               // decrease dim

我对 C++ 模板比较陌生,如果这不仅仅是一个 API 问题并且与模板相关,我希望能得到一些解释。

【问题讨论】:

  • 维度变化的期望语义是什么?投影到第一个坐标并在新坐标中使用零值进行扩展?
  • @us2012,该模板通常用作机器人系统的一部分,该系统主要将摄像机图像的 2D 线段转换为周围环境地图的 3D 线段。这种转换是双向的。我可以使用子类而不是 typedef 并添加特定的 to3to2 方法,但想知道是否有办法做到这一点。我见过的唯一一个调整数组大小的例子是动态大小的向量,例如VectorXd
  • 在Eigen2中,我相信你可以使用.start&lt;3&gt;(),但我可能弄错了。

标签: c++ eigen eigen3


【解决方案1】:

首先,Eigen 的 resize 方法会在新元素数量与旧元素数量不同时重新分配内存,无论是在增长时还是在收缩时,所以在这种情况下你会丢失数据

下面的方法使用.head&lt;int&gt;(),这是Eigen3的.start&lt;int&gt;()的版本,加上一些模板编程,所以你不必检查你是收缩还是增长:

#include <Eigen/Core>

template <bool COND, int A, int B>
struct IF
{
  enum { val = A };
};

template <int A, int B>
struct IF<false, A, B>
{
  enum { val = B };
};

template <int A, int B>
struct MIN : IF<A < B, A, B>
{
};

template <typename T,int dim,int newDim>
Eigen::Matrix<T,newDim,1> to(Eigen::Matrix<T,dim,1> p)
{
  Eigen::Matrix<int,newDim,1> newp =
    Eigen::Matrix<T,newDim,1>::Zero();

  newp.template head< MIN<dim,newDim>::val >() =
    p.template head< MIN<dim,newDim>::val >();

  return newp;
}

使用这个,下面的程序:

#include <iostream>

int main()
{
  Eigen::Vector2i p_2i(1,2);
  Eigen::Vector3i p_3i(3,4,5);

  std::cout << to<int, 2, 3>(p_2i) << std::endl << std::endl;
  std::cout << to<int, 3, 2>(p_3i) << std::endl << std::endl;

}

作为输出:

1
2
0

3
4

【讨论】:

  • 我想我最终可能会学到一些关于模板的东西 :) 非常感谢。
【解决方案2】:

为了完整起见,这里是原位的解决方案,使用@sgvd's technique完美地完成了这项工作:

template<typename T,int dim>
struct LineSegment
{
public:
  template<int newDim>
  LineSegment<T,newDim> to() const
  {
    Eigen::Matrix<T,newDim,1> newp1;
    Eigen::Matrix<T,newDim,1> newp2;

    newp1.template head< MIN<dim,newDim>::val >() = d_p1.template head< MIN<dim,newDim>::val >();
    newp2.template head< MIN<dim,newDim>::val >() = d_p2.template head< MIN<dim,newDim>::val >();

    return LineSegment<T,newDim>(newp1, newp2);
  }

  // ... other members ...

protected:
  Eigen::Matrix<T,dim,1> d_p1;
  Eigen::Matrix<T,dim,1> d_p2;

private:
  template <bool COND, int A, int B>
  struct IF
  {
    enum { val = A };
  };

  template <int A, int B>
  struct IF<false, A, B>
  {
    enum { val = B };
  };

  template <int A, int B>
  struct MIN : IF<A < B, A, B>
  {};
}

还有一个通过的单元测试:

TEST (LineSegmentTests, to)
{
  EXPECT_EQ ( LineSegment3i(Vector3i(1,2,0), Vector3i(3,4,0)),
              LineSegment2i(Vector2i(1,2),   Vector2i(3,4)  ).to<3>() );

  EXPECT_EQ ( LineSegment2i(Vector2i(1,2),   Vector2i(4,5)),
              LineSegment3i(Vector3i(1,2,3), Vector3i(4,5,6)).to<2>() );

  EXPECT_EQ ( LineSegment3i(Vector3i(1,2,3), Vector3i(4,5,6)),
              LineSegment3i(Vector3i(1,2,3), Vector3i(4,5,6)).to<3>() );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 2018-05-02
    • 1970-01-01
    • 2017-05-11
    • 1970-01-01
    相关资源
    最近更新 更多