ceres库安装(Mac)
由于笔者使用的是macOS系统,因此只介绍macOS系统下的操作,其他平台上的安装已经有很多教程。
macOS下的安装参考官方网站:Installation — Ceres Solver (ceres-solver.org)
安装包下载:http://ceres-solver.org/ceres-solver-2.2.0.tar.gz,可以下载在任意路径下,确定自己能找到即可。
首先安装ceres库的依赖项目,用homebrew一键搞定,在终端下输入:
brew install ceres-solver
这条命令应该回自动安装其他第三方库(eigen、glog、suite-solver),如果不确定,可以输入以下命令确定:
# CMake
brew install cmake
# google-glog and gflags
brew install glog gflags
# Eigen3
brew install eigen
# SuiteSparse
brew install suite-sparse
安装完成后,通过以下命令查看是否正确安装(出现图上的命令说明ceres库及依赖项安装成功):
brew info ceres-solver
然后,终端中定位到刚刚的安装包下载路径,输入一下命令:
tar zxf ceres-solver-2.2.0.tar.gz
mkdir ceres-bin
cd ceres-bin
cmake ../ceres-solver-2.2.0
make -j3
make test
sudo make install
这样就安装好了!在安装包的路径下查看,会有图中两个文件夹。(测试文件夹是我自己创建的)
七参数原解算理
笔者以如下问题为例,用ceres库求解七参数:
已知4个点分别在ITRF和CGCS2000坐标系下的坐标,如下所示。请用上述4个已知点的ITRF和CGCS2000坐标,通过布尔莎模型求解七个转换参数。
空间中两个不同的参考椭球之间的转换需要 3 个旋转参数、3 个平移参数和 1 个缩放参数,即布尔沙七参数。
通常至少需要三个公共已知点,在两个不同空间直角坐标系中的六对 XYZ 坐标值,才能推算出这七个未知参数。计算出了这七个参数,就可以通过七参数方程组,将一个空间直角坐标系下一个点的 XYZ 坐标值转换为另一个空间直角坐标系下的 XYZ 坐标值。
首先,从一个坐标系到另一个坐标系的转换公式为:
[
X
B
Y
B
Z
B
]
=
[
Δ
X
Δ
Y
Δ
Z
]
+
(
1
+
k
)
R
(
ε
z
)
R
(
ε
y
)
R
(
ε
x
)
[
X
A
Y
A
Z
A
]
\left[\begin{array}{c} X_{B} \\ Y_{B} \\ Z_{B} \end{array}\right]=\left[\begin{array}{c} \Delta X \\ \Delta Y \\ \Delta Z \end{array}\right]+(1+k) R\left(\varepsilon_{z}\right) R\left(\varepsilon_{y}\right) R\left(\varepsilon_{x}\right)\left[\begin{array}{c} X_{A} \\ Y_{A} \\ Z_{A} \end{array}\right]
XBYBZB
=
ΔXΔYΔZ
+(1+k)R(εz)R(εy)R(εx)
XAYAZA
其中,
[
Δ
X
Δ
Y
Δ
Z
]
\begin{bmatrix}\Delta X\\ \Delta Y \\ \Delta Z \end{bmatrix}
ΔXΔYΔZ
为平移参数,
k
k
k为尺度变化参数,
ε
x
,
ε
y
,
ε
z
\varepsilon_{x},\varepsilon_{y},\varepsilon_{z}
εx,εy,εz为旋转参数。
R
(
ε
x
)
,
R
(
ε
y
)
,
R
(
ε
z
)
R(\varepsilon_{x}),R(\varepsilon_{y}),R(\varepsilon_{z})
R(εx),R(εy),R(εz)为旋转参数矩阵,即:
R
(
ε
x
)
=
[
1
0
0
0
cos
ε
x
sin
ε
x
0
−
sin
ε
x
cos
ε
x
]
R(\varepsilon_{x})=\begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos \varepsilon_{x} & \sin \varepsilon_{x} \\ 0 & -\sin \varepsilon_{x} & \cos \varepsilon_{x} \end{bmatrix}
R(εx)=
1000cosεx−sinεx0sinεxcosεx
R ( ε y ) = [ cos ε y 0 − sin ε y 0 1 0 sin ε y 0 cos ε y ] R(\varepsilon_{y})=\begin{bmatrix} \cos \varepsilon_{y} & 0 & -\sin \varepsilon_{y} \\ 0 & 1 & 0 \\ \sin \varepsilon_{y} & 0& \cos \varepsilon_{y} \end{bmatrix} R(εy)= cosεy0sinεy010−sinεy0cosεy
R ( ε z ) = [ cos ε z sin ε z 0 − sin ε z cos ε z 0 0 0 1 ] R(\varepsilon_{z})=\begin{bmatrix} \cos \varepsilon_{z} & \sin \varepsilon_{z} & 0 \\ -\sin \varepsilon_{z} & \cos \varepsilon_{z} & 0\\ 0 & 0& 1 \end{bmatrix} R(εz)= cosεz−sinεz0sinεzcosεz0001
为了简化计算,当
k
,
ε
x
,
ε
y
,
ε
z
k,\varepsilon_{x},\varepsilon_{y},\varepsilon_{z}
k,εx,εy,εz为微小量时,忽略期间的互乘项,且
c
o
s
ε
≈
1
,
s
i
n
ε
≈
1
cos \varepsilon \approx 1,sin \varepsilon \approx 1
cosε≈1,sinε≈1,则转换公式可变为:
[
X
B
Y
B
Z
B
]
=
[
Δ
X
Δ
Y
Δ
Z
]
+
(
1
+
k
)
[
X
A
Y
A
Z
A
]
+
[
0
ε
z
−
ε
y
−
ε
z
0
ε
x
ε
y
−
ε
x
0
]
[
X
A
Y
A
Z
A
]
\left[\begin{array}{c} X_{B} \\ Y_{B} \\ Z_{B} \end{array}\right]=\left[\begin{array}{c} \Delta X \\ \Delta Y \\ \Delta Z \end{array}\right]+(1+k)\left[\begin{array}{c} X_{A} \\ Y_{A} \\ Z_{A} \end{array}\right]+\left[\begin{array}{ccc} 0 & \varepsilon_{z} & -\varepsilon_{y} \\ -\varepsilon_{z} & 0 & \varepsilon_{x} \\ \varepsilon_{y} & -\varepsilon_{x} & 0 \end{array}\right]\left[\begin{array}{c} X_{A} \\ Y_{A} \\ Z_{A} \end{array}\right]
XBYBZB
=
ΔXΔYΔZ
+(1+k)
XAYAZA
+
0−εzεyεz0−εx−εyεx0
XAYAZA
[ X B Y B Z B ] = [ X A Y A Z A ] + [ 1 0 0 0 − Z A Y A X A 0 1 0 Z A 0 − X A Y A 0 0 1 − Y A X A 0 Z A ] [ Δ X Δ Y Δ Z ε 1 ε 2 ε 3 k ] \begin{bmatrix} X_{B} \\ Y_{B} \\ Z_{B} \end{bmatrix}=\left[\begin{array}{c} X_{A} \\ Y_{A} \\ Z_{A} \end{array}\right]+\left[\begin{array}{ccccccc} 1 & 0 & 0 & 0 & -Z_{A} & Y_{A} & X_{A} \\ 0 & 1 & 0 & Z_{A} & 0 & -X_{A} & Y_{A} \\ 0 & 0 & 1 & -Y_{A} & X_{A} & 0 & Z_{A} \end{array}\right] \begin{bmatrix}\Delta X \\ \Delta Y \\ \Delta Z \\ \varepsilon_{1} \\ \varepsilon_{2} \\ \varepsilon_{3} \\ k \end{bmatrix} XBYBZB = XAYAZA + 1000100010ZA−YA−ZA0XAYA−XA0XAYAZA ΔXΔYΔZε1ε2ε3k
A
=
[
1
0
0
0
−
Z
A
Y
A
X
A
0
1
0
Z
A
0
−
X
A
Y
A
0
0
1
−
Y
A
X
A
0
Z
A
]
,
L
=
[
X
B
Y
B
Z
B
]
−
[
X
A
Y
A
Z
A
]
A=\left[\begin{array}{ccccccc} 1 & 0 & 0 & 0 & -Z_{A} & Y_{A} & X_{A} \\ 0 & 1 & 0 & Z_{A} & 0 & -X_{A} & Y_{A} \\ 0 & 0 & 1 & -Y_{A} & X_{A} & 0 & Z_{A} \end{array}\right], L=\left[\begin{array}{c} X_{B} \\ Y_{B} \\ Z_{B} \end{array}\right]-\left[\begin{array}{c} X_{A} \\ Y_{A} \\ Z_{A} \end{array}\right]
A=
1000100010ZA−YA−ZA0XAYA−XA0XAYAZA
,L=
XBYBZB
−
XAYAZA
X = [ Δ X , Δ Y , Δ Z , ε 1 , ε 2 , ε 3 , k ] T X=\left[\Delta X, \Delta Y, \Delta Z, \varepsilon_{1}, \varepsilon_{2}, \varepsilon_{3}, k\right]^{T} \\ X=[ΔX,ΔY,ΔZ,ε1,ε2,ε3,k]T
为了求解7个转换参数,至少需要3个公共点,当多于3个公共点时,可按照最小二乘法求得7个参数的最或然值。符合间接平差,依照最小二乘法求解:
V
=
A
∗
X
−
L
V=A*X-L
V=A∗X−L
X = ( A T A ) − 1 A T L X=(A^{T}A)^{-1}A^{T}L X=(ATA)−1ATL
ceres库求解七参数
终端进入ceres-bin文件夹,新建两个文件。
第一个是ceres_example.cpp文件(名字任意),将下面代码复制粘贴即可。
#include <ceres/ceres.h>
#include <iomanip>
struct BursaWolfModel {
BursaWolfModel(double X_s, double Y_s, double Z_s,
double X_t, double Y_t, double Z_t)
: X_s(X_s), Y_s(Y_s), Z_s(Z_s), X_t(X_t), Y_t(Y_t), Z_t(Z_t) {}
template <typename T>
bool operator()(const T* const params, T* residuals) const {
// 假设params包含七个参数:三个平移参数(dx, dy, dz),三个旋转参数(rx, ry, rz)和一个尺度因子(m)
T dx = params[0];
T dy = params[1];
T dz = params[2];
T rx = params[3];
T ry = params[4];
T rz = params[5];
T m = params[6];
// 计算转换后的坐标
T X_c = X_s + dx - Z_s * ry + Y_s * rz + X_s * m;
T Y_c = Y_s + dy + Z_s * rx - X_s * rz + Y_s * m;
T Z_c = Z_s + dz - Y_s * rx + X_s * ry + Z_s * m;
// 计算残差
residuals[0] = -X_t + X_c;
residuals[1] = -Y_t + Y_c;
residuals[2] = -Z_t + Z_c;
return true;
}
private:
const double X_s, Y_s, Z_s, X_t, Y_t, Z_t;
};
int main(int argc, char const* argv[])
{
double source_coordinates[4][3] = { {-2358683.2015, 5153007.9355, 2916777.1882}, {-2476191.1223, 5220545.6468, 2692588.9666},
{-2366980.0034, 5241954.8314, 2748152.9313}, {-2479709.4985, 5074389.1912, 2953715.9067} };
double target_coordinates[4][3] = { {-2358682.9205, 5153007.9970, 2916777.2489}, {-2476190.8413, 5220545.7090, 2692589.0279},
{-2366979.7223, 5241954.8932, 2748152.9923}, {-2479709.2174, 5074389.2528, 2953715.9674} };
double params[7] = { 0, 0, 0, 0, 0, 0, 0 };
ceres::Problem problem;
// 我们有4组源坐标和目标坐标
for (int i = 0; i < 4; ++i) {
problem.AddResidualBlock(
new ceres::AutoDiffCostFunction<BursaWolfModel, 3, 7>(
new BursaWolfModel(source_coordinates[i][0], source_coordinates[i][1], source_coordinates[i][2],
target_coordinates[i][0], target_coordinates[i][1], target_coordinates[i][2])),
nullptr, // 没有核函数
params); // 七个参数(dx, dy, dz, rx, ry, rz, m)
}
ceres::Solver::Options options;
// 设置求解器选项
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
// 输出求解结果
std::cout << std::fixed << std::setprecision(20);
std::cout << summary.FullReport() << "\n";
std::cout << "dx = " << params[0] << "\n";
std::cout << "dy = " << params[1] << "\n";
std::cout << "dz = " << params[2] << "\n";
std::cout << "rx = " << params[3] << "\n";
std::cout << "ry = " << params[4] << "\n";
std::cout << "rz = " << params[5] << "\n";
std::cout << "m = " << params[6] << "\n";
return 0;
}
第二个是CMakeLists.txt,复制一下内容(记得将add_executable后改为自己创建的cpp名字):
cmake_minimum_required(VERSION 3.8.0)
project(ceres_example)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Ceres REQUIRED)
include_directories(
${CERES_INCLUDE_DIRS}
)
add_executable(ceres_example
ceres_example.cpp)
target_link_libraries(ceres_example
${CERES_LIBRARIES}
)
输入以下命令:
mkdir build
cd build
cmake ..
make
文件夹中的内容应该如下图所示:
最后输入
./ceres_example
终端界面上出现以下内容,最下面即为求出的七参数:
解算成功!