参考https://blog.csdn.net/Fan_z_0802/article/details/80960790
原理很简单,先计算出目标的中心,将目标绕中心旋转一定角度alpha。求出点云的最值Xmax,Xmin,Ymax,Ymin。这四个值两两组合就能组成外接矩形的四个顶点。记录矩形面积最小时的最值和角度。
以上步骤得到的矩形的边分别平行于X轴和Y轴,通过对矩形的四个点逆旋转alpha。就能得到任意角度的外接矩形。
我们选择旋转目标,而不是外接矩形,这样会更容易理解。
根据建筑物点云的特点:大部分建筑物是矩形边界,所以把最小面积换成点云再X,Y轴上的投影的长度和最短来确定点云的主方向。如果想要计算最小面积,可以直接使用pcl库的getOBB方法,或者修改compute()方法来计算面积。
头文件
#ifndef MinimumBoundingRectangle_H
#define MinimumBoundingRectangle_H
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/common/common.h>
#include <pcl/common/angles.h>
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
const float limit_max = std::numeric_limits <float>::max();
class MinimumBoundingRectangle {
public:
MinimumBoundingRectangle();
MinimumBoundingRectangle(PointCloudT::Ptr _cloud);
void setInputCloud(PointCloudT::Ptr _cloud);
void setDelta(int delta =1);
PointT rotate(PointT point, float angle);
void rotateTransform(PointCloudT::Ptr in_cloud, PointCloudT::Ptr out_cloud,float angle);
void compute();
float getMinAngle();
void getLocalMBR(PointT& a_point, PointT& b_point, PointT& c_point, PointT& d_point);
void getMBR(PointT& a_point, PointT& b_point, PointT& c_point, PointT& d_point);
~MinimumBoundingRectangle();
private:
const int angle_range = 90;
int angle_delta = 1;
PointCloudT::Ptr mbr_cloud;
PointT mbr_max, mbr_min, mbr_center;
float mbr_min_angle = 0;
std::vector<float> mbr_angle;
};
#endif // !MinimumBoundingRectangle_H
具体实现
#include "MinimumBoundingRectangle.h"
/*
* class MinimumBoundingRectangle
*/
MinimumBoundingRectangle::MinimumBoundingRectangle() {
mbr_cloud.reset(new PointCloudT);
this->setDelta();
}
MinimumBoundingRectangle::MinimumBoundingRectangle(PointCloudT::Ptr _cloud) {
mbr_cloud.reset(new PointCloudT);
this->setInputCloud(_cloud);
this->setDelta();
}
/*
* set angle-delta of rotate.
* range(1,100) is recommend.
*/
void MinimumBoundingRectangle::setDelta(int delta) {
if (delta < 1) return;
this->angle_delta = delta;
mbr_angle.clear();
mbr_angle.resize(angle_range * angle_delta);
for (int i = angle_range * angle_delta; i; ) {
mbr_angle[--i] = i * 1.0f / angle_delta;
}
}
/*
* input a point cloud
*/
void MinimumBoundingRectangle::setInputCloud(PointCloudT::Ptr _cloud) {
*mbr_cloud = *_cloud;
PointT min_point, max_point;
pcl::getMinMax3D(*mbr_cloud, min_point, max_point);
mbr_center.x = min_point.x+(max_point.x-min_point.x) * 0.5;
mbr_center.y = min_point.y+( max_point.y-min_point.y) * 0.5;
}
/*
* rotate point cloud by an angle.
*/
PointT MinimumBoundingRectangle::rotate(PointT point, float angle) {
float deltaX = point.x - mbr_center.x;
float deltaY = point.y - mbr_center.y;
float theta = pcl::deg2rad(angle);
float cos_angle = cos(theta);
float sin_angle = sin(theta);
point.x = deltaX * cos_angle - deltaY * sin_angle + mbr_center.x;
point.y = deltaX * sin_angle + deltaY * cos_angle + mbr_center.y;
return point;
}
void MinimumBoundingRectangle::rotateTransform(PointCloudT::Ptr in_cloud, PointCloudT::Ptr out_cloud,float angle) {
for (int j = in_cloud->size(); j;)
out_cloud->points[--j] = rotate(in_cloud->points[j],angle);
}
/*
* compute a MBR.
* Rotate object by an angle and gain points: Xmax,Xmin,Ymax,Ymin.
* These four points will be create a rectangle.
*
*/
void MinimumBoundingRectangle::compute() {
if (mbr_cloud->size() < 1) return;
PointCloudT::Ptr temp_cloud(new PointCloudT);
temp_cloud->resize(mbr_cloud->size());
PointT min_point, max_point;
float min_area = limit_max;
for (int i = mbr_angle.size(); i;) {
--i;
rotateTransform(mbr_cloud, temp_cloud, mbr_angle[i]);
pcl::getMinMax3D(*temp_cloud, min_point, max_point);
if (max_point.x - min_point.x + max_point.y - min_point.y < min_area) {
min_area = max_point.x - min_point.x + max_point.y - min_point.y;
mbr_max = max_point;
mbr_min = min_point;
mbr_min_angle = mbr_angle[i];
}
}
}
/*
* Return four vertices of MBR.
* The MBR is based on main direction of object;
*
*/
float MinimumBoundingRectangle::getMinAngle() {
return this->mbr_min_angle;
}
void MinimumBoundingRectangle::getLocalMBR(PointT& a_point, PointT& b_point, PointT& c_point, PointT& d_point) {
a_point = { mbr_min.x ,mbr_min.y,0 };
b_point = { mbr_min.x ,mbr_max.y,0 };
c_point = { mbr_max.x ,mbr_max.y,0 };
d_point = { mbr_max.x ,mbr_min.y,0 };
}
void MinimumBoundingRectangle::getMBR(PointT& a_point, PointT& b_point, PointT& c_point, PointT& d_point) {
a_point = { mbr_min.x ,mbr_min.y,0 };
b_point = { mbr_min.x ,mbr_max.y,0 };
c_point = { mbr_max.x ,mbr_max.y,0 };
d_point = { mbr_max.x ,mbr_min.y,0 };
a_point = rotate(a_point, -mbr_min_angle);
b_point = rotate(b_point, -mbr_min_angle);
c_point = rotate(c_point, -mbr_min_angle);
d_point = rotate(d_point, -mbr_min_angle);
}
MinimumBoundingRectangle::~MinimumBoundingRectangle() {
}