我在beaglebone上使用OpenCV来跟踪垂直和水平矩形。
为了确定矩形是水平还是垂直,我使用从minAreaRect中提取的高度宽度比。
但是我注意到,有时,如果我让程序在同一个图像上循环运行,则相同的固定矩形交换的宽度和高度值,其中它将前一个宽度值报告为当前高度,同样对于之前的高度值。
这使得代码不能令人满意,因为它无法再成功使用高度/宽度比。
有人可以解释一下可能导致矩形高度/宽度自行交换的原因吗?
这是一个示例输出,注意迭代之间的高度和宽度
Hierarchy: 1
Contour Size: 53
Contour: 0
X: 350
Y: 196
Height: 236
Width: 26
Ratio (W/H): 0.110169
Ratio (H/W): 9.07692
Vert: 0
Horiz: 0
Image proc. time: 1.9ms
Contours: 1
Hierarchy: 1
Contour Size: 83
Contour: 0
X: 244
Y: 300
Height: 26
Width: 236
Ratio (W/H): 9.07692
Ratio (H/W): 0.110169
Vert: 0
Horiz: 0
Image proc. time: 2.2ms
Contours: 1
Hierarchy: 1
Contour Size: 59
Contour: 0
X: 350
Y: 196
Height: 236
Width: 26
Ratio (W/H): 0.110169
Ratio (H/W): 9.07692
Vert: 0
Horiz: 0
Image proc. time: 2.4ms
这是我用来生成此输出的代码
vector<Vec4i> hierarchy;
Target targets;
/// Show in a window
namedWindow( "Contours", WINDOW_AUTOSIZE );
//Find rectangles
findContours(thresholded, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
cout<<"Contours: "<<contours.size()<<endl;
cout<<"Hierarchy: "<<hierarchy.size()<<endl;
//run through all contours and remove small contours
unsigned int contourMin = 25;
for (vector<vector<Point> >::iterator it = contours.begin(); it!=contours.end(); )
{
cout<<"Contour Size: "<<it->size()<<endl;
if (it->size()<contourMin)
it=contours.erase(it);
else
++it;
}
//Vector for Min Area Boxes
vector<RotatedRect> minRect(contours.size());
/// Draw contours
Mat drawing = Mat::zeros(original.size(), CV_8UC3 );
NullTargets(targets);
//run through large contours to see if they are our targerts
if(!contours.empty() && !hierarchy.empty())
{
for(unsigned int i = 0; i < contours.size(); i++)
{
//capture corners of copntour
minRect[i] = minAreaRect(Mat(contours[i]));
//if(hierarchy[i][100] != -1)
drawContours( drawing, contours, i, RED, 2, 8, hierarchy, 0, Point());
//draw a minimum box around the target in green
Point2f rect_points[4];
minRect[i].points(rect_points);
for (int j = 0; j < 4; j++)
line(drawing,rect_points[j],rect_points[(j+1)%4],GREEN,1,8);
//define minAreaBox
Rect box;
box.x = minRect[i].center.x - (minRect[i].size.width/2);
box.y = minRect[i].center.y - (minRect[i].size.height/2);
box.width = minRect[i].size.width;
box.height = minRect[i].size.height;
double WHRatio = box.width/((double)box.height);
double HWRatio = ((double)box.height)/box.width;
//check if contour is vert, we use HWRatio because it is greater that 0 for vert target
if ((HWRatio > MinVRatio) && (HWRatio < MaxVRatio))
{
targets.VertGoal = true;
targets.VerticalTarget = box;
targets.VerticalAngle = minRect[i].angle;
targets.VerticalCenter = Point(box.x + box.width/2, box.y + box.height/2);
targets.Vertical_H_W_Ratio = HWRatio;
targets.Vertical_W_H_Ratio = WHRatio;
}
//check if contour is horiz, we use WHRatio because it is greater that 0 for vert target
else if ((WHRatio > MinHRatio) && (WHRatio < MaxHRatio))
{
targets.HorizGoal = true;
targets.HorizontalTarget = box;
targets.HorizontalAngle = minRect[i].angle;
targets.HorizontalCenter = Point(box.x + box.width/2, box.y + box.height/2);
targets.Horizontal_H_W_Ratio = HWRatio;
targets.Horizontal_W_H_Ratio = WHRatio;
}
if(targets.HorizGoal && targets.VertGoal)
targets.HotGoal = true;
cout<<"Contour: "<<i<<endl;
cout<<"\tX: "<<box.x<<endl;
cout<<"\tY: "<<box.y<<endl;
cout<<"\tHeight: "<<box.height<<endl;
cout<<"\tWidth: "<<box.width<<endl;
cout<<"\tangle: "<<minRect[i].angle<<endl;
cout<<"\tRatio (W/H): "<<WHRatio<<endl;
cout<<"\tRatio (H/W): "<<HWRatio<<endl;
cout<<"\tVert: "<<targets.VertGoal<<endl;
cout<<"\tHoriz: "<<targets.HorizGoal<<endl;
cout<<"\tHot Goal: "<<targets.HotGoal<<endl;
//rectangle(drawing,box,YELLOW);
//ID the center in yellow
Point center(box.x + box.width/2, box.y + box.height/2);
line(drawing, center, center, YELLOW, 3);
line(drawing ,Point(320,240),Point(320,240),YELLOW,3);
}
答案 0 :(得分:3)
当您使用RotatedRect时,您应该记住它没有真正的宽度或高度,因为如果您向角度添加90度,它们可以交换。因此,使用RotatedRect的“width”或“height”来初始化“box”是至少可以说是有问题的。如果要从RotatedRect计算比率,则应考虑角度。或者,如果您不想从头开始使用角度使用Rect而不是RotatedRect(将minAreaRect替换为boundingRect)。
在旁注中,您不是按照数字顶点过滤多边形,这通常是非常不可靠的数字。大多边形可能只有很少的顶点而小的多边形可能有很多。最好使用轮廓区域(来自contourArea函数)或边界框区域,因为无论如何都要计算它。