为了将你的代码封装成一个名为 `BlockWeightedRegistration` 的类,我们将代码拆分为 `.h` 和 `.cpp` 文件,分别用于声明类接口和实现类功能。
---
### ✅ 类功能说明
该类封装了以下主要功能:
- **扇形分区(sectorPartition)**
- **ICP配准(ICP)**
- **ESF特征提取(ESFEstimation)**
- **分区加权配准(blockICP)**
- **配准误差计算(calFinalRegistrationRMSE 和 calCrossRegistrationDeviation)**
---
### 📁 文件结构
```
BlockWeightedRegistration.h
BlockWeightedRegistration.cpp
```
---
### 📄 BlockWeightedRegistration.h
```cpp
#ifndef BLOCK_WEIGHTED_REGISTRATION_H
#define BLOCK_WEIGHTED_REGISTRATION_H
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/features/esf.h>
#include <pcl/registration/icp.h>
#include <pcl/common/centroid.h>
#include <pcl/common/angles.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/registration/correspondence_rejection_one_to_one.h>
#include <pcl/registration/correspondence_estimation.h>
#include <Eigen/Geometry>
#include <vector>
#include <map>
#include <cmath>
class BlockWeightedRegistration
{
public:
using PointType = pcl::PointXYZI;
using PointCloudPtr = pcl::PointCloud<PointType>::Ptr;
BlockWeightedRegistration();
~BlockWeightedRegistration();
// 主要接口函数
pcl::PointCloud<pcl::PointXYZI>::Ptr blockICP(
pcl::PointCloud<pcl::PointXYZI>::Ptr& source,
pcl::PointCloud<pcl::PointXYZI>::Ptr& target,
float maxCorrespondenceDistance,
int sectorNum,
double& frmse);
private:
// 扇形分区
std::pair<std::vector<pcl::PointCloud<pcl::PointXYZI>>,
std::vector<pcl::PointCloud<pcl::PointXYZI>>>
sectorPartition(pcl::PointCloud<pcl::PointXYZI>::Ptr& source,
pcl::PointCloud<pcl::PointXYZI>::Ptr& target,
int sectorNum = 12);
// ICP配准
void ICP(pcl::PointCloud<pcl::PointXYZI>::Ptr& oldSection,
pcl::PointCloud<pcl::PointXYZI>::Ptr& baseSection,
pcl::PointCloud<pcl::PointXYZI>::Ptr& newSection,
int maximumIterateTime,
float maxCorrespondenceDistance,
float registrationAccuracy,
Eigen::Matrix4f& transform,
double& SD);
// 计算最终配准误差
void calFinalRegistrationRMSE(pcl::PointCloud<pcl::PointXYZI>::Ptr& baseCloud,
pcl::PointCloud<pcl::PointXYZI>::Ptr& computedCloud,
double& RMSE);
// 计算断面扇形分区配准偏差
void calCrossRegistrationDeviation(pcl::PointCloud<pcl::PointXYZI>::Ptr& baseCloud,
pcl::PointCloud<pcl::PointXYZI>::Ptr& computedCloud,
double& SD);
// 计算ESF特征
pcl::PointCloud<pcl::ESFSignature640>::Ptr ESFEstimation(pcl::PointCloud<pcl::PointXYZI>::Ptr& object);
};
#endif // BLOCK_WEIGHTED_REGISTRATION_H
```
---
### 📄 BlockWeightedRegistration.cpp
```cpp
#include "BlockWeightedRegistration.h"
#include <pcl/console/time.h>
BlockWeightedRegistration::BlockWeightedRegistration() {}
BlockWeightedRegistration::~BlockWeightedRegistration() {}
// 扇形分区
std::pair<std::vector<pcl::PointCloud<pcl::PointXYZI>>,
std::vector<pcl::PointCloud<pcl::PointXYZI>>>
BlockWeightedRegistration::sectorPartition(pcl::PointCloud<pcl::PointXYZI>::Ptr& source,
pcl::PointCloud<pcl::PointXYZI>::Ptr& target,
int sectorNum)
{
Eigen::Vector4f centroid;
pcl::compute3DCentroid(*source, centroid);
float Xo = centroid[0];
float Zo = centroid[2];
std::vector<float> sourceDeg(source->size(), -1.0);
for (size_t i = 0; i < source->size(); ++i)
{
float Xi = source->points[i].x;
float Zi = source->points[i].z;
float rad = std::atan2(Xi - Xo, Zi - Zo);
sourceDeg[i] = (rad < 0) ? pcl::rad2deg(rad) + 360 : pcl::rad2deg(rad);
}
std::vector<float> targetDeg(target->size(), -1.0);
for (size_t i = 0; i < target->size(); ++i)
{
float Xi = target->points[i].x;
float Zi = target->points[i].z;
float rad = std::atan2(Xi - Xo, Zi - Zo);
targetDeg[i] = (rad < 0) ? pcl::rad2deg(rad) + 360 : pcl::rad2deg(rad);
}
float sectorSize = 360.0 / sectorNum;
std::vector<pcl::PointCloud<PointType>> sourceInSector(sectorNum);
std::vector<pcl::PointCloud<PointType>> targetInSector(sectorNum);
for (size_t i = 0; i < source->size(); ++i)
{
int sectorID = static_cast<int>(std::floor(sourceDeg[i] / sectorSize));
if (sectorID >= 0 && sectorID < sectorNum)
sourceInSector[sectorID].push_back(source->points[i]);
}
for (size_t i = 0; i < target->size(); ++i)
{
int sectorID = static_cast<int>(std::floor(targetDeg[i] / sectorSize));
if (sectorID >= 0 && sectorID < sectorNum)
targetInSector[sectorID].push_back(target->points[i]);
}
return {sourceInSector, targetInSector};
}
// ICP配准
void BlockWeightedRegistration::ICP(pcl::PointCloud<PointType>::Ptr& oldSection,
pcl::PointCloud<PointType>::Ptr& baseSection,
pcl::PointCloud<PointType>::Ptr& newSection,
int maximumIterateTime,
float maxCorrespondenceDistance,
float registrationAccuracy,
Eigen::Matrix4f& transform,
double& SD)
{
pcl::IterativeClosestPoint<PointType, PointType> icp;
icp.setTransformationEpsilon(1e-10);
icp.setMaxCorrespondenceDistance(maxCorrespondenceDistance);
icp.setMaximumIterations(maximumIterateTime);
icp.setEuclideanFitnessEpsilon(registrationAccuracy);
icp.setUseReciprocalCorrespondences(true);
icp.setInputSource(oldSection);
icp.setInputTarget(baseSection);
pcl::PointCloud<PointType>::Ptr ICPcloud(new pcl::PointCloud<PointType>);
icp.align(*ICPcloud);
transform = icp.getFinalTransformation();
pcl::transformPointCloud(*oldSection, *newSection, transform);
calCrossRegistrationDeviation(newSection, baseSection, SD);
}
// 计算最终配准误差
void BlockWeightedRegistration::calFinalRegistrationRMSE(pcl::PointCloud<PointType>::Ptr& baseCloud,
pcl::PointCloud<PointType>::Ptr& computedCloud,
double& RMSE)
{
pcl::registration::CorrespondenceEstimation<PointType, PointType> core;
core.setInputSource(baseCloud);
core.setInputTarget(computedCloud);
pcl::Correspondences corres;
core.determineCorrespondences(corres, 0.012);
pcl::CorrespondencesPtr corresPtr(new pcl::Correspondences(corres));
pcl::registration::CorrespondenceRejectorOneToOne corrRej;
corrRej.getRemainingCorrespondences(*corresPtr, corres);
float sum = 0.0;
for (const auto& c : corres) sum += c.distance;
RMSE = (corres.empty()) ? -1.0 : sqrt(sum / corres.size());
}
// 计算断面扇形分区配准偏差
void BlockWeightedRegistration::calCrossRegistrationDeviation(pcl::PointCloud<PointType>::Ptr& baseCloud,
pcl::PointCloud<PointType>::Ptr& computedCloud,
double& SD)
{
pcl::KdTreeFLANN<PointType> kdtree;
kdtree.setInputCloud(baseCloud);
std::vector<double> deviation;
for (size_t i = 0; i < computedCloud->size(); ++i)
{
std::vector<int> idx(1);
std::vector<float> dist(1);
kdtree.nearestKSearch(computedCloud->points[i], 1, idx, dist);
if (dist[0] < 0.01)
deviation.push_back(dist[0]);
}
if (deviation.empty()) {
SD = -1;
return;
}
double sum = 0;
for (double d : deviation) sum += d;
double mean = sum / deviation.size();
double var = 0;
for (double d : deviation) var += (d - mean) * (d - mean);
SD = std::sqrt(var / (deviation.size() - 1));
}
// 计算ESF特征
pcl::PointCloud<pcl::ESFSignature640>::Ptr BlockWeightedRegistration::ESFEstimation(pcl::PointCloud<PointType>::Ptr& object)
{
pcl::PointCloud<pcl::ESFSignature640>::Ptr descriptor(new pcl::PointCloud<pcl::ESFSignature640>);
pcl::ESFEstimation<PointType, pcl::ESFSignature640> esf;
esf.setInputCloud(object);
esf.compute(*descriptor);
return descriptor;
}
// 分区加权ICP配准
pcl::PointCloud<pcl::PointXYZI>::Ptr BlockWeightedRegistration::blockICP(
pcl::PointCloud<pcl::PointXYZI>::Ptr& source,
pcl::PointCloud<pcl::PointXYZI>::Ptr& target,
float maxCorrespondenceDistance,
int sectorNum,
double& frmse)
{
auto sectorResults = sectorPartition(source, target, sectorNum);
std::vector<Eigen::Matrix4f> RotaionGroup;
std::map<int, pcl::PointCloud<PointType>::Ptr> newSectionICP;
std::vector<double> weight;
for (int i = 0; i < sectorNum; ++i)
{
if (sectorResults.first[i].empty() || sectorResults.second[i].empty())
continue;
auto sourceFeature = ESFEstimation(sectorResults.first[i].makeShared());
auto targetFeature = ESFEstimation(sectorResults.second[i].makeShared());
float sumAB = 0, sumAA = 0, sumBB = 0;
for (int k = 0; k < 640; ++k)
{
float Vik = sourceFeature->points[0].histogram[k];
float Vjk = targetFeature->points[0].histogram[k];
sumAB += Vik * Vjk;
sumAA += Vik * Vik;
sumBB += Vjk * Vjk;
}
float sim = sumAB / (std::sqrt(sumAA) * std::sqrt(sumBB));
if (sim < 0.9) continue;
Eigen::Matrix4f Rotation;
double SD = 0.0;
ICP(sectorResults.first[i].makeShared(), sectorResults.second[i].makeShared(),
newSectionICP[i], 100, maxCorrespondenceDistance, 0.001, Rotation, SD);
if (SD <= 0) continue;
RotaionGroup.push_back(Rotation);
weight.push_back(1.0 / SD);
}
Eigen::Matrix4f bestRotaion = Eigen::Matrix4f::Zero();
double weightSum = 0;
for (double w : weight) weightSum += w;
for (size_t i = 0; i < weight.size(); ++i)
bestRotaion += (weight[i] / weightSum) * RotaionGroup[i];
pcl::PointCloud<PointType>::Ptr registResult(new pcl::PointCloud<PointType>);
pcl::transformPointCloud(*source, *registResult, bestRotaion);
calFinalRegistrationRMSE(registResult, target, frmse);
return registResult;
}
```
---
### ✅ 使用示例(main.cpp)
```cpp
#include "BlockWeightedRegistration.h"
#include <pcl/io/pcd_io.h>
#include <pcl/console/time.h>
int main()
{
pcl::console::TicToc time;
time.tic();
pcl::PointCloud<pcl::PointXYZI>::Ptr source(new pcl::PointCloud<pcl::PointXYZI>);
pcl::io::loadPCDFile<pcl::PointXYZI>("WW//228//source_slice_228.pcd", *source);
pcl::PointCloud<pcl::PointXYZI>::Ptr target(new pcl::PointCloud<pcl::PointXYZI>);
pcl::io::loadPCDFile<pcl::PointXYZI>("WW//228//target_slice_228.pcd", *target);
BlockWeightedRegistration bwr;
double frmse = 0.0;
int bestSegNum = 1;
pcl::PointCloud<pcl::PointXYZI>::Ptr result = bwr.blockICP(source, target, 0.8, 1, frmse);
std::cout << "算法耗时: " << time.toc() << " ms" << std::endl;
std::cout << "最佳分块配准误差为: " << frmse << std::endl;
pcl::io::savePCDFileBinary("WW//result//source_slice_1427reg.pcd", *result);
return 0;
}
```
---
###