Open3D源码笔记

Open3D是一个非常棒的点云处理库,包含一系列常用的点云处理函数,而且代码非常干净易读。在此文中我们一起读一下Open3D的源码,借此学习一下C++在比较大型的库中的写作规范。

文章目录

    • geometry
      • Geometry.h
      • Geometry3D.h
      • Geometry3D.cpp
    • RGBD里程计

geometry

Geometry.h

Geometry.h中定义了基类Geometry,Open3D中提到的其他几何类型均继承此基类。

#pragma once

#include 

namespace open3d {
namespace geometry {

/// \class Geometry
///
/// \brief The base geometry class.
class Geometry {
public:
    /// \enum GeometryType
    ///
    /// \brief Specifies possible geometry types.
    /// \这里定义了基类Geometry中的GeometryType,是个枚举类,不同的几何类型用不同的整数表示。
    /// \枚举类限定了Geometry的类型必须是以下中的
    enum class GeometryType {
        /// Unspecified geometry type.
        /// Unspecified就是未指定,在private中定义成员变量的默认几何数据类型。
        Unspecified = 0,
        /// PointCloud
        PointCloud = 1,
        /// VoxelGrid
        VoxelGrid = 2,
        /// Octree
        Octree = 3,
        /// LineSet
        LineSet = 4,
        /// MeshBase
        MeshBase = 5,
        /// TriangleMesh
        TriangleMesh = 6,
        /// HalfEdgeTriangleMesh
        HalfEdgeTriangleMesh = 7,
        /// Image
        Image = 8,
        /// RGBDImage
        RGBDImage = 9,
        /// TetraMesh
        TetraMesh = 10,
        /// OrientedBoundingBox
        OrientedBoundingBox = 11,
        /// AxisAlignedBoundingBox
        AxisAlignedBoundingBox = 12,
    };

public:
    /// \这里定义了基类Geometry的析构函数,这里的析构函数是虚析构,因为是基类,基类的析构函数必须是虚析构!
    virtual ~Geometry() {}

protected:
    /// \brief Parameterized Constructor.
    ///
    /// \param type Specifies the type of geometry of the object constructed.
    /// \param dimension Specifies whether the dimension is 2D or 3D.
    /// 不介绍参数意义了,这里把基类的构造函数写在protected中了
    /// 解读:仅允许派生类构造此基类,一般是通过派生类的构造函数隐含构造的,用人话再解释一下就是Geometry这个类不能被实例化出来,只能通过子类继承来使用,即这个基类就是其他类型的伴侣,不能单独用。
    /// protected构造函数/private构造函数详细介绍参考此:https://blog.csdn.net/qq_29344757/article/details/74757441
    Geometry(GeometryType type, int dimension)
        : geometry_type_(type), dimension_(dimension) {}

public:
    /// Clear all elements in the geometry.
    /// 这个是基类的纯虚函数,基类中的纯虚函数前面加个virtual后面加个=0,意思是基类中不用实现这个函数,但是继承这个基类的类必须要实现这个函数。
    virtual Geometry& Clear() = 0;
    /// Returns `true` iff the geometry is empty.
    virtual bool IsEmpty() const = 0;
    /// Returns one of registered geometry types.
    /// 定义函数GetGeometryType,作用是返回几何体的类型,其中被返回的成员变量geometry_type_是在构造函数中被定义的,在Open3D中成员变量的命名方式是小写的单词用下划线连接,最后再加个下划线,用来区别类内和类外的变量。
    GeometryType GetGeometryType() const { return geometry_type_; }
    /// Returns whether the geometry is 2D or 3D.
    int Dimension() const { return dimension_; }

    std::string GetName() const { return name_; }
    void SetName(const std::string& name) { name_ = name; }

private:
    /// 在private中定义成员变量,然后在实例化时在构造函数或者其他函数中给这些变量赋值。成员变量后面都加一个下划线。
    /// Type of geometry from GeometryType.
    GeometryType geometry_type_ = GeometryType::Unspecified;
    /// Number of dimensions of the geometry.
    int dimension_ = 3;
    std::string name_;
};

}  // namespace geometry
}  // namespace open3d

Geometry3D.h

#pragma once

#include 
#include 

#include "open3d/geometry/Geometry.h"
#include "open3d/utility/Eigen.h"

namespace open3d {
namespace geometry {

class AxisAlignedBoundingBox;
class OrientedBoundingBox;

/// \class Geometry3D
///
/// \brief The base geometry class for 3D geometries.
///
/// Main class for 3D geometries, Derives all data from Geometry Base class.
/// 这里定义了一个叫Geometry3D的类,继承了基类Geometry,这个类也是个基类。
class Geometry3D : public Geometry {
public:
    /// 参考资料:https://blog.csdn.net/qq_43808700/article/details/103539401
    /// 这里析构函数的override写不写都行,写不写都行的时候就写上
    /// (基类析构函数为虚函数时,派生类的析构函数写不写override都行,因为写不写编译器都会帮你override一下)
    /// ??存疑??override是否为必须??
    ~Geometry3D() override {}

protected:
    /// \brief Parameterized Constructor.
    ///
    /// \param type type of object based on GeometryType.
    /// 构造函数,继承基类Geometry,这里要求实例化Geometry3D时要给定GeometryType,变量叫type,同时继承自Geometry是要指定dim为3,因为我们定义这个基类是3D的类。
    Geometry3D(GeometryType type) : Geometry(type, 3) {}

public:
    /// Clear函数必须要有,因为基类Geometry中定义了纯虚函数
    /// 参考资料:https://blog.csdn.net/hou09tian/article/details/108862875
    /// 当成员函数返回的为*this时,就写Geometry3D&,表示返回值是调用该成员函数的变量的引用
    Geometry3D& Clear() override = 0;
    bool IsEmpty() const override = 0;
    /// 参考资料:https://blog.csdn.net/weixin_44001521/article/details/104394353
    /// 下面的虚函数是给3D几何类型定义的,要求不同的几何类型在其内部实现。const的含义是说返回值是一个const不可修改,=0的含义是说基类的虚函数未做实现的时候要加=0,并不是const=0,这两个要分开理解。
    /// Returns min bounds for geometry coordinates.
    virtual Eigen::Vector3d GetMinBound() const = 0;
    /// Returns max bounds for geometry coordinates.
    virtual Eigen::Vector3d GetMaxBound() const = 0;
    /// Returns the center of the geometry coordinates.
    virtual Eigen::Vector3d GetCenter() const = 0;
    /// Returns an axis-aligned bounding box of the geometry.
    virtual AxisAlignedBoundingBox GetAxisAlignedBoundingBox() const = 0;
    /// Returns an oriented bounding box of the geometry.
    virtual OrientedBoundingBox GetOrientedBoundingBox() const = 0;
    /// \brief Apply transformation (4x4 matrix) to the geometry coordinates.
    /// 传入矩阵的引用,避免浪费内存,加const防止被错误修改
    /// Geometry3D&表示return的是*this
    virtual Geometry3D& Transform(const Eigen::Matrix4d& transformation) = 0;

    /// \brief Apply translation to the geometry coordinates.
    ///
    /// \param translation A 3D vector to transform the geometry.
    /// \param relative If `true`, the \p translation is directly applied to the
    /// geometry. Otherwise, the geometry center is moved to the \p translation.
    virtual Geometry3D& Translate(const Eigen::Vector3d& translation,
                                  bool relative = true) = 0;
    /// \brief Apply scaling to the geometry coordinates.
    /// Given a scaling factor \f$s\f$, and center \f$c\f$, a given point
    /// \f$p\f$ is transformed according to \f$s (p - c) + c\f$.
    ///
    /// \param scale The scale parameter that is multiplied to the
    /// points/vertices of the geometry.
    /// \param center Scale center that is used to resize the geometry.
    virtual Geometry3D& Scale(const double scale,
                              const Eigen::Vector3d& center) = 0;

    /// \brief Apply rotation to the geometry coordinates and normals.
    /// Given a rotation matrix \f$R\f$, and center \f$c\f$, a given point
    /// \f$p\f$ is transformed according to \f$R (p - c) + c\f$.
    ///
    /// \param R A 3x3 rotation matrix
    /// \param center Rotation center that is used for the rotation.
    /// 这个有两个Rotate函数,输入不同,即函数重载,第一个=0即纯虚函数,在源文件中未做实现。
    /// 第二个做了实现(其实是在第二个Rotate中调用第一个Rotate,具体见cpp源文件)
    virtual Geometry3D& Rotate(const Eigen::Matrix3d& R,
                               const Eigen::Vector3d& center) = 0;

    virtual Geometry3D& Rotate(const Eigen::Matrix3d& R);

    /// Get Rotation Matrix from XYZ RotationType.
    static Eigen::Matrix3d GetRotationMatrixFromXYZ(
            const Eigen::Vector3d& rotation);
    /// Get Rotation Matrix from YZX RotationType.
    static Eigen::Matrix3d GetRotationMatrixFromYZX(
            const Eigen::Vector3d& rotation);
    /// Get Rotation Matrix from ZXY RotationType.
    static Eigen::Matrix3d GetRotationMatrixFromZXY(
            const Eigen::Vector3d& rotation);
    /// Get Rotation Matrix from XZY RotationType.
    static Eigen::Matrix3d GetRotationMatrixFromXZY(
            const Eigen::Vector3d& rotation);
    /// Get Rotation Matrix from ZYX RotationType.
    static Eigen::Matrix3d GetRotationMatrixFromZYX(
            const Eigen::Vector3d& rotation);
    /// Get Rotation Matrix from YXZ RotationType.
    static Eigen::Matrix3d GetRotationMatrixFromYXZ(
            const Eigen::Vector3d& rotation);
    /// Get Rotation Matrix from AxisAngle RotationType.
    static Eigen::Matrix3d GetRotationMatrixFromAxisAngle(
            const Eigen::Vector3d& rotation);
    /// Get Rotation Matrix from Quaternion.
    static Eigen::Matrix3d GetRotationMatrixFromQuaternion(
            const Eigen::Vector4d& rotation);
/// 下面的函数都没什么好说的
protected:
    /// Compute min bound of a list points.
    Eigen::Vector3d ComputeMinBound(
            const std::vector<Eigen::Vector3d>& points) const;
    /// Compute max bound of a list points.
    Eigen::Vector3d ComputeMaxBound(
            const std::vector<Eigen::Vector3d>& points) const;
    /// Computer center of a list of points.
    Eigen::Vector3d ComputeCenter(
            const std::vector<Eigen::Vector3d>& points) const;

    /// \brief Resizes the colors vector and paints a uniform color.
    ///
    /// \param colors An array of eigen vectors specifies colors in RGB.
    /// \param size The resultant size of the colors array.
    /// \param color The final color in which the colors will be painted.
    void ResizeAndPaintUniformColor(std::vector<Eigen::Vector3d>& colors,
                                    const size_t size,
                                    const Eigen::Vector3d& color) const;

    /// \brief Transforms all points with the transformation matrix.
    ///
    /// \param transformation 4x4 matrix for transformation.
    /// \param points A list of points to be transformed.
    void TransformPoints(const Eigen::Matrix4d& transformation,
                         std::vector<Eigen::Vector3d>& points) const;

    /// \brief Transforms the normals with the transformation matrix.
    ///
    /// \param transformation 4x4 matrix for transformation.
    /// \param normals A list of normals to be transformed.
    void TransformNormals(const Eigen::Matrix4d& transformation,
                          std::vector<Eigen::Vector3d>& normals) const;
    /// \brief Apply translation to the geometry coordinates.
    ///
    /// \param translation A 3D vector to transform the geometry.
    /// \param points A list of points to be transformed.
    /// \param relative If `true`, the \p translation is directly applied to the
    /// \p points. Otherwise, the center of the \p points is moved to the \p
    /// translation.
    void TranslatePoints(const Eigen::Vector3d& translation,
                         std::vector<Eigen::Vector3d>& points,
                         bool relative) const;

    /// \brief Scale the coordinates of all points by the scaling factor \p
    /// scale.
    ///
    /// \param scale The scale factor that is used to resize the geometry
    /// \param points A list of points to be transformed
    /// \param center Scale center that is used to resize the geometry..
    void ScalePoints(const double scale,
                     std::vector<Eigen::Vector3d>& points,
                     const Eigen::Vector3d& center) const;

    /// \brief Rotate all points with the rotation matrix \p R.
    ///
    /// \param R A 3x3 rotation matrix
    /// defines the axis of rotation and the norm the angle around this axis.
    /// \param points A list of points to be transformed.
    /// \param center Rotation center that is used for the rotation.
    void RotatePoints(const Eigen::Matrix3d& R,
                      std::vector<Eigen::Vector3d>& points,
                      const Eigen::Vector3d& center) const;

    /// \brief Rotate all normals with the rotation matrix \p R.
    ///
    /// \param R A 3x3 rotation matrix
    /// \param normals A list of normals to be transformed.
    void RotateNormals(const Eigen::Matrix3d& R,
                       std::vector<Eigen::Vector3d>& normals) const;
};

}  // namespace geometry
}  // namespace open3d

Geometry3D.cpp

#include "open3d/geometry/Geometry3D.h"

#include 
#include 

#include "open3d/utility/Logging.h"

namespace open3d {
namespace geometry {
/// 这里套娃了,用一个Rotate函数调用了另一个重载的Rotate函数;GetCenter是在Geometry3D的头文件中声明的。
Geometry3D& Geometry3D::Rotate(const Eigen::Matrix3d& R) {
    return Rotate(R, GetCenter());
}
// 得到最小的边界,即minx miny minz
Eigen::Vector3d Geometry3D::ComputeMinBound(
        const std::vector<Eigen::Vector3d>& points) const {
    // 如果points为空,就输出0,0,0
    if (points.empty()) {
        return Eigen::Vector3d(0.0, 0.0, 0.0);
    }
    // 参考资料:https://blog.csdn.net/qq_40803710/article/details/80273811
    // std::accumulate 用来做自定义数据类型的求和
    // 注意看上面网页里accumulate的模板实现,四个输入是:第一个iterator First,最后一个iterator Last,当前值val,自定义函数func
    // 这个函数会在迭代器中对当前值和迭代值取小值。学一下这里的std::accumulate的用法,很实用。
    return std::accumulate(
            points.begin(), points.end(), points[0],
            [](const Eigen::Vector3d& a, const Eigen::Vector3d& b) {
                return a.array().min(b.array()).matrix();
            });
}
// 实现方法同上
Eigen::Vector3d Geometry3D::ComputeMaxBound(
        const std::vector<Eigen::Vector3d>& points) const {
    if (points.empty()) {
        return Eigen::Vector3d(0.0, 0.0, 0.0);
    }
    return std::accumulate(
            points.begin(), points.end(), points[0],
            [](const Eigen::Vector3d& a, const Eigen::Vector3d& b) {
                return a.array().max(b.array()).matrix();
            });
}
Eigen::Vector3d Geometry3D::ComputeCenter(
        const std::vector<Eigen::Vector3d>& points) const {
    // 先定义center为0,0,0
    Eigen::Vector3d center(0, 0, 0);
    // 如果点集合为空就返回0,0,0
    if (points.empty()) {
        return center;
    }
    // 这里的std::accumulate是求和,在points迭代器中求和然后给到center中
    center = std::accumulate(points.begin(), points.end(), center);
    // 然后除以点的数量得到点集的center
    center /= double(points.size());
    return center;
}

void Geometry3D::ResizeAndPaintUniformColor(
        std::vector<Eigen::Vector3d>& colors,
        const size_t size,
        const Eigen::Vector3d& color) const {
    // 先对传入的引用colors
    colors.resize(size);
    Eigen::Vector3d clipped_color = color;
    if (color.minCoeff() < 0 || color.maxCoeff() > 1) {
        utility::LogWarning(
                "invalid color in PaintUniformColor, clipping to [0, 1]");
        clipped_color = clipped_color.array()
                                .max(Eigen::Vector3d(0, 0, 0).array())
                                .matrix();
        clipped_color = clipped_color.array()
                                .min(Eigen::Vector3d(1, 1, 1).array())
                                .matrix();
    }
    for (size_t i = 0; i < size; i++) {
        colors[i] = clipped_color;
    }
}

void Geometry3D::TransformPoints(const Eigen::Matrix4d& transformation,
                                 std::vector<Eigen::Vector3d>& points) const {
    // points是一个vector,auto& point是Vector3d类型点的引用,在for循环中处理每个点的旋转操作 
    // auto关键字处理引用类型时为 auto&                 
    for (auto& point : points) {
        Eigen::Vector4d new_point =
                transformation *
                Eigen::Vector4d(point(0), point(1), point(2), 1.0);
        // 用法参考:https://blog.csdn.net/u012541187/article/details/53420432
        // x.head<3>()的用法说明:即x(1:n)用于数组提取前n个[vector]
        // 关于为什么要除以new_point(3):为了做矩阵乘法先将new_point齐次化,new_point(3)是scale这里为1.        
        point = new_point.head<3>() / new_point(3); // 取前三个值
    }
}

void Geometry3D::TransformNormals(const Eigen::Matrix4d& transformation,
                                  std::vector<Eigen::Vector3d>& normals) const {
    for (auto& normal : normals) {
        Eigen::Vector4d new_normal =
                transformation *
                Eigen::Vector4d(normal(0), normal(1), normal(2), 0.0);
        normal = new_normal.head<3>();
    }
}

void Geometry3D::TranslatePoints(const Eigen::Vector3d& translation,
                                 std::vector<Eigen::Vector3d>& points,
                                 bool relative) const {
    Eigen::Vector3d transform = translation;
    // !relative:物体的中心点移动到transform的位置;否则即整体移动transform
    if (!relative) {
        transform -= ComputeCenter(points);
    }
    // 
    for (auto& point : points) {
        point += transform;
    }
}

void Geometry3D::ScalePoints(const double scale,
                             std::vector<Eigen::Vector3d>& points,
                             const Eigen::Vector3d& center) const {
    for (auto& point : points) {
        // 先去中心化,scale后再平移到原中心,即以center为中心进行scale
        point = (point - center) * scale + center;
    }
}

void Geometry3D::RotatePoints(const Eigen::Matrix3d& R,
                              std::vector<Eigen::Vector3d>& points,
                              const Eigen::Vector3d& center) const {
    for (auto& point : points) {
    	// 先去中心化,旋转后再平移回去,即让物体绕着自身坐标系旋转,而不是绕着世界坐标系旋转
        point = R * (point - center) + center;
    }
}

void Geometry3D::RotateNormals(const Eigen::Matrix3d& R,
                               std::vector<Eigen::Vector3d>& normals) const {
    for (auto& normal : normals) {
        normal = R * normal;
    }
}

Eigen::Matrix3d Geometry3D::GetRotationMatrixFromXYZ(
        const Eigen::Vector3d& rotation) {
    return open3d::utility::RotationMatrixX(rotation(0)) *
           open3d::utility::RotationMatrixY(rotation(1)) *
           open3d::utility::RotationMatrixZ(rotation(2));
}

Eigen::Matrix3d Geometry3D::GetRotationMatrixFromYZX(
        const Eigen::Vector3d& rotation) {
    return open3d::utility::RotationMatrixY(rotation(0)) *
           open3d::utility::RotationMatrixZ(rotation(1)) *
           open3d::utility::RotationMatrixX(rotation(2));
}

Eigen::Matrix3d Geometry3D::GetRotationMatrixFromZXY(
        const Eigen::Vector3d& rotation) {
    return open3d::utility::RotationMatrixZ(rotation(0)) *
           open3d::utility::RotationMatrixX(rotation(1)) *
           open3d::utility::RotationMatrixY(rotation(2));
}

Eigen::Matrix3d Geometry3D::GetRotationMatrixFromXZY(
        const Eigen::Vector3d& rotation) {
    return open3d::utility::RotationMatrixX(rotation(0)) *
           open3d::utility::RotationMatrixZ(rotation(1)) *
           open3d::utility::RotationMatrixY(rotation(2));
}

Eigen::Matrix3d Geometry3D::GetRotationMatrixFromZYX(
        const Eigen::Vector3d& rotation) {
    return open3d::utility::RotationMatrixZ(rotation(0)) *
           open3d::utility::RotationMatrixY(rotation(1)) *
           open3d::utility::RotationMatrixX(rotation(2));
}

Eigen::Matrix3d Geometry3D::GetRotationMatrixFromYXZ(
        const Eigen::Vector3d& rotation) {
    return open3d::utility::RotationMatrixY(rotation(0)) *
           open3d::utility::RotationMatrixX(rotation(1)) *
           open3d::utility::RotationMatrixZ(rotation(2));
}

Eigen::Matrix3d Geometry3D::GetRotationMatrixFromAxisAngle(
        const Eigen::Vector3d& rotation) {
    const double phi = rotation.norm();
    return Eigen::AngleAxisd(phi, rotation / phi).toRotationMatrix();
}

Eigen::Matrix3d Geometry3D::GetRotationMatrixFromQuaternion(
        const Eigen::Vector4d& rotation) {
    return Eigen::Quaterniond(rotation(0), rotation(1), rotation(2),
                              rotation(3))
            .normalized()
            .toRotationMatrix();
}

}  // namespace geometry
}  // namespace open3d

RGBD里程计

论文:https://jsturm.de/publications/data/steinbruecker_sturm_cremers_iccv11.pdf

你可能感兴趣的:(笔记,c++)