【OpenCV】通过最小外接矩形判断物体的平面位置及位姿

文章目录

  • 基本原理
  • 识别示例
  • 代码

基本原理

目标识别中很重要的一点,获取物体的位置及位姿信息。下面提供博主的一种通过物体最小外接矩形来判别的简单方法,必须承认,有一定的局限性,同时精度不高。

首先,假设我们已经识别到目标物体,如下图,用正交的矩形框将其标记出来。这个标记的矩形框所蕴含的信息是比较少的。
【OpenCV】通过最小外接矩形判断物体的平面位置及位姿_第1张图片
通过某些方法(例如将矩形框旋转角度并保持图形外接),我们可以获得目标物体的最小外接矩形(如下图蓝色矩形框)。

【OpenCV】通过最小外接矩形判断物体的平面位置及位姿_第2张图片
不难发现:
矩形中心 ≈ 目标物体形心
矩形旋转角度 ≈ 目标物体主体轴线相对于正交坐标的转角

通过这个方法,我们就可以简单地获取目标物体的位置和位姿信息。
【OpenCV】通过最小外接矩形判断物体的平面位置及位姿_第3张图片

识别示例

以下图中一把瑞士军刀为例。
【OpenCV】通过最小外接矩形判断物体的平面位置及位姿_第4张图片
首先通过二值化确定目标物体所在的区域。

【OpenCV】通过最小外接矩形判断物体的平面位置及位姿_第5张图片
之后再运用最小外接矩形进行框选,通过计算外接矩形的中心点坐标和转角,获得目标物体的位置和位姿信息。
【OpenCV】通过最小外接矩形判断物体的平面位置及位姿_第6张图片
注意:这种方法仅仅是一种简单的判断,具有一定的局限性。例如,如果目标物体形状长宽区分度不高,亦或者形状怪异不均匀,就很难得到较好的结果。
如下图所示是一个集装箱扭锁图片,可以发现其主体部分多出来的拉杆影响到了最小外接矩形的判断。这种情况如果继续想使用本方法的话,就需要去除干扰部分。可以参考我的另一篇博客中提及的一种去除干扰的方法。
【OpenCV】通过最小外接矩形判断物体的平面位置及位姿_第7张图片

代码

#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.细心的朋友可能会发现,我去掉了轮廓点集中的第一组集合,因为第一组集合会框选出整个窗口,目前我也没弄清楚是什么原因,有待改进。

如有错误,欢迎指正!

你可能感兴趣的:(OpenCV)