|

楼主 |
发表于 2025-4-11 15:46:56
|
显示全部楼层
Ceres 拟合代码
struct SphereResidual {
SphereResidual(const Eigen::Vector3d& point) : point_(point) {}
template <typename T>
bool operator()(const T* const center, const T* const radius, T* residual) const {
Eigen::Matrix<T, 3, 1> c(center[0], center[1], center[2]);
T r = radius[0];
residual[0] = (point_.cast<T>() - c).norm() - r;
return true;
}
private:
const Eigen::Vector3d point_;
};
void fitSphereCeres(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud,
Eigen::Vector3d& center_out, double& radius_out) {
double center[3] = {0.0, 0.0, 0.0};
double radius = 1.0;
ceres::Problem problem;
for (const auto& pt : cloud->points) {
Eigen::Vector3d p(pt.x, pt.y, pt.z);
ceres::CostFunction* cost = new ceres::AutoDiffCostFunction<SphereResidual, 1, 3, 1>(
new SphereResidual(p));
problem.AddResidualBlock(cost, nullptr, center, &radius);
}
ceres::Solver::Options options;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
center_out = Eigen::Vector3d(center[0], center[1], center[2]);
radius_out = radius;
std::cout << "✅ Ceres 拟合完成:\n" << summary.BriefReport() << std::endl;
}
✅ 功能 2:用 PCL Viewer 可视化拟合球体、球心
📈 追加可视化模块
#include <pcl/visualization/pcl_visualizer.h>
#include <thread>
void visualizeSphere(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud,
const Eigen::Vector3d& center,
double radius) {
auto viewer = boost::make_shared<pcl::visualization::PCLVisualizer>("Sphere Fitting Viewer");
viewer->setBackgroundColor(0, 0, 0);
// 显示原始点云
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color(cloud, 255, 255, 255);
viewer->addPointCloud(cloud, color, "cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "cloud");
// 显示拟合球体(透明球)
pcl::ModelCoefficients sphere;
sphere.values.resize(4);
sphere.values[0] = center[0];
sphere.values[1] = center[1];
sphere.values[2] = center[2];
sphere.values[3] = radius;
viewer->addSphere(sphere, "fitted_sphere");
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, 0.3, "fitted_sphere");
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0.0, 1.0, 0.0, "fitted_sphere");
// 显示球心
pcl::PointXYZ c(center[0], center[1], center[2]);
viewer->addSphere(c, 0.1, 1.0, 0.0, 0.0, "center_point");
viewer->addText3D("Center", c, 0.2, 1.0, 0.0, 0.0);
// 交互式显示
viewer->addCoordinateSystem(1.0);
while (!viewer->wasStopped()) {
viewer->spinOnce(100);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
✅ 功能 3:输出残差误差报告(CSV)
🧾 导出 CSV 报告(偏差、球度)
#include <fstream>
void exportSphereResidualCSV(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud,
const Eigen::Vector3d& center,
double radius,
double tolerance = 0.05,
const std::string& filename = "sphere_fit_report.csv") {
std::ofstream file(filename);
file << "Index,X,Y,Z,Residual(mm),OutOfTolerance\n";
for (size_t i = 0; i < cloud->size(); ++i) {
const auto& pt = cloud->points;
Eigen::Vector3d p(pt.x, pt.y, pt.z);
double r_actual = (p - center).norm();
double residual = r_actual - radius;
bool out = std::abs(residual) > tolerance;
file << i << "," << pt.x << "," << pt.y << "," << pt.z << ","
<< residual << "," << (out ? "YES" : "NO") << "\n";
}
std::cout << "📄 拟合报告导出完成: " << filename << std::endl;
}
🔁 主函数整合调用示例
int main() {
// 1. 生成球点
auto cloud = generateSphereData(); // 你已有实现
// 2. 拟合(Ceres)
Eigen::Vector3d center;
double radius;
fitSphereCeres(cloud, center, radius);
// 3. 可视化
visualizeSphere(cloud, center, radius);
// 4. 报告
exportSphereResidualCSV(cloud, center, radius, 0.05, "sphere_fit_report.csv");
return 0;
}
✅ 运行效果
项目 效果说明
Ceres Solver 拟合 更准确,残差最小(非线性优化)
PCL Viewer 显示球面、球心、点云
CSV 报告 每点偏差 + 是否超差判断(供 QC 审核) |
|