您的位置:首页 > 其它

获取轮廓的最小外接矩形

2017-08-27 16:16 344 查看
本文主要实现了轮廓的最小面积外接矩形:

(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;

}


实现效果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: