参考文献:Malkin Z. A new method to subdivide a spherical surface into equal-area cells[J]. arXiv preprint arXiv:1612.03467, 2016.
一种根据面积均分球面的方法是根据经纬度来分,即将直角坐标
(
x
,
y
,
z
)
(x,y,z)
(x,y,z)转换成极坐标
(
θ
,
ϕ
,
r
)
(\theta, \phi, r)
(θ,ϕ,r),然后将
θ
\theta
θ和
ϕ
\phi
ϕ均分。均分
ϕ
\phi
ϕ(经度)确实能让分出来的小块面积相等,但
θ
\theta
θ(维度)分块后是不均匀的,如下图

网上找到一篇博客介绍了两种均分方法:正多面体(柏拉图体regular polyhedron)、Hierarchical Equal Area isoLatitude Pixelization(这个方法甚至专门有个c++库)


但是这两种方法感觉在原理和实现上都很复杂,于是经过一番搜寻找到了论文16年的一篇论文《A new method to subdivide a spherical surface into equal-area cells》
这篇论文的方法跟开头介绍的错误分法都是从经纬度( θ \theta θ和 ϕ \phi ϕ)下手,但它并不是均分。主要步骤分两步:
划分的方法论文中并没有给,只给了将球面均分成46、130、406块的划分方式


由于我手边工作的需要,这些划分数量太多了,我就自己手推了
x
=
4
x=4
x=4和
x
=
5
x=5
x=5的划分方式,而且我并没有要求“赤道附近的块接近正方形”

| Total Cell | Cells | Latitudinal | Longitudinal |
|---|---|---|---|
| 10 | 2 3 3 2 | 0-53.13° 53.13°-90° 90°-126.87° 126.87°-180° | 180° 120° 120° 180° |
| 14 | 3 4 4 3 | 0-55.15° 55.15°-90° 90°-124.85° 124.85°-180° | 120° 90° 90° 120° |
| 18 | 4 5 5 4 | 0-56.22° 56.22°-90° 90°-123.78° 123.78°-180° | 90° 72° 72° 90° |
| 20 | 3 7 7 3 | 0-45.573° / 0 - 0.7954 45.573°-90° / 0.7954 - 1.5708 90°-134.427° / 1.5708 - 2.3462 134.427°-180° / 2.3462 - 3.1416 | 120° / 2.0944 51.43° / 0.8976 51.43° / 0.8976 120° / 2.0944 |
| Total Cell | Cells | Latitudinal | Longitudinal |
|---|---|---|---|
| 19 | 3 4 5 4 3 | 0-46.826° 46.826°-74.743° 74.743°-105.257° 105.257°- 133.174° 133.174°-180° | 120° 90° 72° 90° 120° |
| 24 | 4 5 6 5 4 | 0-48.190° 48.190°-75.522° 75.522°-104.478° 104.478°- 131.810° 131.810°-180° | 90° 72° 60° 72° 90° |
这里以“统计球形点云落在每个块中的数量”为例,划分方式为 x = 4 , m = 3 , n = 7 x=4, m=3, n=7 x=4,m=3,n=7
/**
* 统计球形点云落在每个块中的数量
* @param[in] points n*3的矩阵,存储三维点云
* @param[out] nums 统计结果,存储顺序北极->南极 & 经度0°->360°
*/
void ClassifyCentroidVector(const Eigen::MatrixXf &points, vector<int> &nums) {
direct.resize(20);
Eigen::Vector4f block_theta(0., 0.7954, 1.5708, 2.3462);
Eigen::Vector4f block_phi(2.0944, 0.8976, 0.8976, 2.0944);
Eigen::Vector4i offset(0, 3, 10, 17);
for (int k = 0; k < points.rows(); k++) {
//笛卡尔坐标系转换为球坐标系
const float x = points(k, 0), y = points(k, 1), z = points(k, 2);
float r = sqrt(x * x + y * y + z * z);
float theta = acos(z / r);
float fai = atan2(y, x) + M_PI; // 取值范围0-2π
int coord_theta = -1;
for(int i = 0; i < block_theta.size(); i++)
if(theta > block_theta(i)){
coord_theta = i;
break;
}
assert(coord_theta != -1);
int coord_phi = int(fai/block_phi(coord_theta));
direct[offset(coord_theta)+coord_phi] += 1;
}
}