Высота и ширина прямоугольника OpenCV меняются местами

Я использую OpenCV на beaglebone для отслеживания вертикальных и горизонтальных прямоугольников.

Чтобы определить, является ли прямоугольник горизонтальным или вертикальным, я использую соотношение высоты и ширины, извлеченное из 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);

}

-1

Решение

Когда вы работаете с RotatedRect, вы должны помнить, что он не имеет реальной ширины или высоты, потому что их можно поменять местами, если вы добавите 90 градусов к углу. В результате использование ‘width’ или ‘height’ RotatedRect для инициализации ‘box’ проблематично по меньшей мере. Если вы хотите вычислить соотношение из RotatedRect, вы должны принять во внимание угол. Или, если вы не хотите использовать угол, используйте Rect вместо RotatedRect с самого начала (замените minAreaRect на boundingRect).

Кроме того, вы не фильтруете полигоны по числовым вершинам на них, что обычно является очень ненадежным числом. У больших полигонов может быть очень мало вершин, а у маленьких может быть много. Лучше использовать область контура (из функции contourArea) или область его ограничительной рамки, так как вы все равно вычисляете ее.

3

Другие решения

Других решений пока нет …