PCL建筑物点云最小外接矩形实现C++

3 篇文章 0 订阅

 参考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() {

}

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 20
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值