目标识别中很重要的一点,获取物体的位置及位姿信息。下面提供博主的一种通过物体最小外接矩形来判别的简单方法,必须承认,有一定的局限性,同时精度不高。
首先,假设我们已经识别到目标物体,如下图,用正交的矩形框将其标记出来。这个标记的矩形框所蕴含的信息是比较少的。
通过某些方法(例如将矩形框旋转角度并保持图形外接),我们可以获得目标物体的最小外接矩形(如下图蓝色矩形框)。
不难发现:
矩形中心 ≈ 目标物体形心
矩形旋转角度 ≈ 目标物体主体轴线相对于正交坐标的转角
通过这个方法,我们就可以简单地获取目标物体的位置和位姿信息。
以下图中一把瑞士军刀为例。
首先通过二值化确定目标物体所在的区域。
之后再运用最小外接矩形进行框选,通过计算外接矩形的中心点坐标和转角,获得目标物体的位置和位姿信息。
注意:这种方法仅仅是一种简单的判断,具有一定的局限性。例如,如果目标物体形状长宽区分度不高,亦或者形状怪异不均匀,就很难得到较好的结果。
如下图所示是一个集装箱扭锁图片,可以发现其主体部分多出来的拉杆影响到了最小外接矩形的判断。这种情况如果继续想使用本方法的话,就需要去除干扰部分。可以参考我的另一篇博客中提及的一种去除干扰的方法。
#include
#include
#include
using namespace cv;
using namespace std;
Mat toBinary(Mat src);
bool ascendSort(vector<Point> a, vector<Point> b);
Mat getContour(Mat src, Mat binary);
Mat srcImage,binaryImage,contourImage;
int main()
{
srcImage = imread("01.jpg");//input image
imshow("srcImage", srcImage);
binaryImage = toBinary(srcImage);//convert to binary image
imshow("binaryImage", binaryImage);
contourImage = getContour(srcImage, binaryImage);
imshow("contourImage", contourImage);
waitKey(0);
return 0;
}
Mat toBinary(Mat src)
{
Mat temp = src.clone();
int thresh = 110, maxValue = 254;
cvtColor(temp, temp, CV_BGR2GRAY);//convert to gray image
threshold(temp, temp, thresh, maxValue, THRESH_BINARY);//binary processing
return temp;
}
bool ascendSort(vector<Point> a, vector<Point> b)
{
return a.size() > b.size();
}
Mat getContour(Mat src,Mat binary)
{
Mat temp = src.clone();
vector< vector< Point> > contours;//save all contours data
vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);//find contours
sort(contours.begin(), contours.end(), ascendSort);//ascending sort
vector< vector<Point> >::iterator itc = contours.begin(); //iterator of contour vector
int i = 0;
while (itc != contours.end())
{
if (itc->size() > 150)//ignore the small object
{
if (i>0)
{
Rect rect = boundingRect(*itc);//get the rectangle bounding
rectangle(temp, rect, { 0, 0, 255 }, 2, 8);//draw the rectangle
RotatedRect resultRect;
resultRect = minAreaRect(*itc);//get the min area rectangle
Point2f pt[4];
resultRect.points(pt);//get the coordinate of vertex
//draw the min area rectangle
line(temp, pt[0], pt[1], Scalar(255, 0, 0), 2, 8);
line(temp, pt[1], pt[2], Scalar(255, 0, 0), 2, 8);
line(temp, pt[2], pt[3], Scalar(255, 0, 0), 2, 8);
line(temp, pt[3], pt[0], Scalar(255, 0, 0), 2, 8);
cout << "**************形心*************" << endl;
cout << "X坐标:" << resultRect.center.x << " Y坐标:" << resultRect.center.y << " 偏转角度:" << resultRect.angle << endl;
cout << "*******************************" << endl;
}
i++;
}
++itc;
}
return temp;
}
ps: 1.代码中最小外接矩形主要使用了minAreaRect()
函数;
2.细心的朋友可能会发现,我去掉了轮廓点集中的第一组集合,因为第一组集合会框选出整个窗口,目前我也没弄清楚是什么原因,有待改进。
如有错误,欢迎指正!