判断识别方案设计
- 功能介绍
- 读入摄像头及预处理得到的装有Point类型的容器;
- 通过计算转折点数目来判断形状,根据要求分为水平线/垂直线/三角形/矩形/圆(转折点数目依次为2,2,3,4,4+);
- 通过转折点和容器中坐标拟合出最理想的形状,并描出其外框(线);
- 返回string来输出其形状名称.
- 思路分析
- 读入Point2i类型的容器;
- 调用arcLength()求封闭图形的周长,为后续操作中的阈值设定最准备;
- 调用approxPolyDP()函数,得到装有转折点坐标的容器;
- 采用switch-case分支结构对进行下一步的判断(以本实验为例,采用(int)angle.size()作为条件);
- 分支中具体函数如下:
- 直线判断:
- 读入装有转折点的容器;
- 采用tan的方式判断直线的水平和垂直状态;
- 得到直线的状态后,根据不同的状态对直线进行归中处理;
- 调用line()函数进行描边.
- 三角形判断:
- 读入装有转折点的容器;
- 调用polylines()函数,利用求得的转折点坐标信息进行描边.
- 矩形判断:
- 读入装有转折点的容器;
- 调用minAreaRect()函数进行矩形的拟合(可返回得到矩形中心和倾斜角度等信息,注:无转折点信息);
- 调用box.points()获取角点位置;
- 调用line()函数进行描边(该处采用polylines()函数效果不理想).
- 圆判断:
- 读入装有转折点的容器;
- 调用minEnclosingCircle()函数,获取拟合程度最好的圆的半径和圆心信息;
- 调用circle()函数进行描边.
- 直线判断:
- 代码介绍
判断函数
void Detect_Shape(std::vector<cv::Point2i> pt)
{
using namespace std;
using namespace cv;
string Shape_Name;
int flag_line;
double epsilon = 0.06 * arcLength(pt , true);
vector<Point2i> angle;
approxPolyDP(pt,angle,epsilon,true);
switch((int)angle.size())
{
case 2:{
flag_line = D_Line(angle);
if(flag_line == 1)
Shape_Name = "vertical line";
else
Shape_Name = "horizonal line";
break;
}
case 3:{
D_Triangle(angle);
Shape_Name = "triangle";
break;
}
case 4:{
D_Rectangle(angle);
Shape_Name = "rectangle";
break;
}
default:{
D_Round(angle);
Shape_Name = "round";
break;
}
}
cout<<"It is a "<< Shape_Name <<endl;
return;
}
直线
int D_Line(std::vector<cv::Point2i> angle)
{
using namespace std;
using namespace cv;
int flag_line;
int dy = abs(angle[0].y - angle[1].y);
int dx = abs(angle[0].x - angle[1].x);
double tan = dy/dx;
if(tan > 1)
{
flag_line = 1;
int x = (angle[0].x + angle[1].x)/2;
line(Mask,Point(x,angle[0].y),Point(x,angle[1].y),Scalar(0,255,0),3);
}
else
{
flag_line = 2;
int y = (angle[0].y + angle[1].y)/2;
line(Mask,Point(angle[0].x,y),Point(angle[1].x,y),Scalar(0,255,0),3);
}
imshow("Line",Mask);
return flag_line;
}
三角形
void D_Triangle(std::vector<cv::Point2i> angle)
{
using namespace std;
using namespace cv;
polylines(Mask, angle, true, Scalar(0,255,0), 3, LINE_AA);
imshow("Triangle",Mask);
return;
}
矩形
void D_Rectangle(std::vector<cv::Point2i> angle)
{
using namespace std;
using namespace cv;
Point2f vertices[4];
RotatedRect box = minAreaRect(angle);
box.points(vertices);
for(int i = 0;i<4;i++)
{
line(Mask, vertices[i], vertices[(i+1)%4], Scalar(0,255,0), 3);
}
imshow("Rectangle",Mask);
return;
}
圆
void D_Round(std::vector<cv::Point2i> angle)
{
using namespace std;
using namespace cv;
Point2f circle_centers;
float circle_radius;
minEnclosingCircle(angle, circle_centers, circle_radius);
circle(Mask,circle_centers,circle_radius,Scalar(0,255,0),3,LINE_AA,0);
imshow("Round",Mask);
return;
}
- 待改进问题
- 暂基本满足设想,后需要优化程序设计