Open3D是一个非常棒的点云处理库,包含一系列常用的点云处理函数,而且代码非常干净易读。在此文中我们一起读一下Open3D的源码,借此学习一下C++在比较大型的库中的写作规范。
在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
#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
#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
论文:https://jsturm.de/publications/data/steinbruecker_sturm_cremers_iccv11.pdf