获取轮廓的最小外接矩形

本文主要实现了轮廓的最小面积外接矩形:

(1)对获取的凸包点,计算凸包线的角度;

(2)将凸包点按照计算的凸包线角度进行旋转;

(3)获取旋转后的点在x、y两方向上各自的最大最小值;

(4)利用获取的最大最小值计算此时最小外接矩形的面积。


typedef struct min_area_rect
{
	point_t* pt;
	int width;
	int height;
	float angle;
}min_area_rect_t;

min_area_rect_t* get_rotate_rect(IplImage* img, point_t *p, const int num);

#include "min_area_rect.h"


//计算凸包线角度
float* get_angle(point_t *p,const int num)
{
	float* angle = (float*)malloc(num * sizeof(float));
	float temp = 0;
	for (int i = 0; i < num - 1; i++)
	{
		temp = atan2(p[i + 1].y - p[i].y,p[i + 1].x - p[i].x);
		if (temp < 0)
			temp += PI / 2;
		angle[i] = -temp;
	}

	return angle;
}

//剔除冗余角度
unsigned int* angle_unique(float* angle,const int num)
{
	unsigned int* state = (int*)malloc(num * sizeof(unsigned int));
	for (int i = 0; i < num; i++)
		state[i] = 1;

	for (int i = 0; i < num; i++)
	{
		for (int j = i + 1; j < num; j++)
		{
			if (angle[i] == angle[j])
				state[j] = 0;
		}
	}

	return state;
}

//计算旋转凸包点坐标
point_t* get_rotate_point(point_t* p,float theta, const int num)
{
	point_t* r_p = (point_t*)malloc(num * sizeof(point_t));

	for (int i = 0; i < num; i++)
	{
		r_p[i].x = p[i].x * cos(theta) - p[i].y * sin(theta);
		r_p[i].y = p[i].x * sin(theta) + p[i].y * cos(theta);
	}

	return r_p;
}

//计算旋转后凸包点的坐标对应的原始坐标
point_t* get_remap_point(point_t* p, float theta)
{
	point_t* r = (point_t*)malloc(4 * sizeof(point_t));
	for (int i = 0; i < 4; i++)
	{
		r[i].x = p[i].x * cos(theta) + p[i].y * sin(theta);
		r[i].y = -p[i].x * sin(theta) + p[i].y * cos(theta);
	}

	return r;
}

float get_distance(const point_t p1, const point_t p2)
{
	return sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}

min_area_rect_t* get_rotate_rect(IplImage* img, point_t *p, const int num)
{
	float* angle;
	unsigned int* state;
	point_t* r_p = NULL;
	point_t* rect_p = (point_t*)malloc(4 * sizeof(point_t));

	angle = get_angle(p, num);
	state = angle_unique(angle, num);

	float min_area = 100000.;
	float min_angle = 0.;
	for (int i = 0; i < num; i++)
	{
		float area = 0.0;
		float max_x = -1000;
		float min_x = 1000;
		float max_y = -1000;
		float min_y = 1000;

		if (state[i] == 1)
		{
			r_p = get_rotate_point(p, angle[i], num);
			for (int j = 0; j < num; j++)
			{
				if (r_p[j].x > max_x)
					max_x = r_p[j].x;
				if (r_p[j].x < min_x)
					min_x = r_p[j].x;
				if (r_p[j].y > max_y)
					max_y = r_p[j].y;
				if (r_p[j].y < min_y)
					min_y = r_p[j].y;
			}

			area = ((max_x - min_x) * (max_y - min_y));
			if (area < min_area)
			{
				min_area = area;
				min_angle = angle[i];
				rect_p[0].x = min_x;
				rect_p[0].y = min_y;
				rect_p[1].x = min_x;
				rect_p[1].y = max_y;
				rect_p[2].x = max_x;
				rect_p[2].y = min_y;
				rect_p[3].x = max_x;
				rect_p[3].y = max_y;
			}
		}
	}

	min_area_rect_t* _minAreaRect = (min_area_rect_t*)malloc(sizeof(min_area_rect_t));
	_minAreaRect -> pt = get_remap_point(rect_p, min_angle);
	_minAreaRect->width = get_distance(rect_p[0],rect_p[1]);
	_minAreaRect->height = get_distance(rect_p[0],rect_p[2]);
	_minAreaRect->angle = min_area;

	free(angle);
	free(state);
	free(r_p);
	free(rect_p);

	return _minAreaRect;

}

实现效果:











  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值