检测图中多个四边形的四个角点

检测图中多个四边形的四个角点

原图:

检测后效果图

/*
工程在69那个例程文件目录

检测四边形轮廓以及角点
*/









#include <opencv.hpp>  
#include <iostream>  
#include<time.h>
#include<math.h>
#include <iostream>  
#include <set>
using namespace cv;
using namespace std;

RNG rng(12345);

float getDistance(CvPoint pointO, CvPoint pointA);
float getAngle(CvPoint pointM, CvPoint pointL, CvPoint pointR);
int main()
{
	Mat srcImage = Mat::zeros(600, 800, CV_8UC3);
	Mat srcImage0 = imread("10.jpg", 0);
	resize(srcImage0, srcImage, srcImage.size());
	srcImage = srcImage > 200;//二值化

	imshow("原图", srcImage);
	//getStructuringElement函数会返回指定形状和尺寸的结构元素
	Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
	//morphologyEx(srcImage, srcImage, MORPH_CLOSE, element);//闭运算滤波
	vector<vector<Point>> contours, RectContours;//轮廓,为点向量,新的轮廓
	findContours(srcImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);//找轮廓
	vector<vector<Point>> hull(contours.size());//用于存放凸包
	Mat drawing(srcImage.size(), CV_8UC3, cv::Scalar(0));
	int i = 0;
	vector<float> length(contours.size());//用于保存每个轮廓的长度
	vector<float> Area_contours(contours.size()), Area_hull(contours.size()), Rectangularity(contours.size()), circularity(contours.size());
	for (i = 0; i < contours.size(); i++)
	{//把所有的轮廓画出来
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		length[i] = arcLength(contours[i], true);//轮廓的长度
		if (length[i] >200 && length[i] <2000)
		{//通过长度匹配滤除小轮廓
			convexHull(Mat(contours[i]), hull[i], false);//把凸包找出来,寻找凸包函数
			Area_contours[i] = contourArea(contours[i]);   //轮廓面积
			Area_hull[i] = contourArea(hull[i]);           //凸包面积
			Rectangularity[i] = Area_contours[i] / Area_hull[i]; //矩形度
			circularity[i] = (4 * 3.1415*Area_contours[i]) / (length[i] * length[i]);//圆形度
			if (Rectangularity[i]>0.9&&circularity[i]<0.7)
			{//通过矩形度和圆形度滤除数字
				//drawContours(drawing, contours, i, Scalar(255, 255, 255), 1);
				RectContours.push_back(hull[i]);//把提取出来的方框导入到新的轮廓组
				drawContours(drawing, hull, i, color, 1);//得到方框
			}
		}
	}
	float distance = 0, distanceMax = 0;
	Point connorPoint1, connorPoint2, connorPoint3, connorPoint4;
	int j = 0, k = 0;
	vector<float>Theta(30);
	vector<Point>ConnorPoint(4);
	for (k = 0; k < RectContours.size(); k++)
	{//历遍每个轮廓找角点
		j = 0;
		for (i = 0; i < RectContours[k].size(); i++)
		{//历遍当个轮廓各点间夹角
			if (i == 0)
			{
				Theta[i] = getAngle(RectContours[k][i], RectContours[k][RectContours[k].size() - 1], RectContours[k][i + 1]);
			}
			else if (i == RectContours[k].size() - 1)
			{
				Theta[i] = getAngle(RectContours[k][i], RectContours[k][i - 1], RectContours[k][0]);
			}
			else
			{
				Theta[i] = getAngle(RectContours[k][i], RectContours[k][i - 1], RectContours[k][i + 1]);
			}
			if (Theta[i] / 3.1415 * 180 < 170)
			{//两点间夹角小于170度
				if (getDistance(RectContours[k][i], ConnorPoint[0])>10 && getDistance(RectContours[k][i], ConnorPoint[1])>10
					&& getDistance(RectContours[k][i], ConnorPoint[2])>10 && getDistance(RectContours[k][i], ConnorPoint[3])>10)
				{//新找到的角点与已经保存的角点间距离要大于10
					ConnorPoint[j] = RectContours[k][i]; //四个角点
				//	circle(drawing, RectContours[k][i], 3, Scalar(255, 255, 255), FILLED, LINE_AA);
					circle(drawing, ConnorPoint[j], 3, Scalar(255, 255, 255), FILLED, LINE_AA);
					//每个四边形的角点显示逻辑这里还是有些问题
					cout << "\n轮廓 " << j << "  的四个角点坐标分别为:\n" << ConnorPoint[0] << ConnorPoint[1] << ConnorPoint[2] << ConnorPoint[3] << endl;
					j++;
				}
			}

		}
	}

	
	for (int i = 0; i < ConnorPoint.size(); i++)
	{
		cout << "\n\t\t毛哥好\n" << endl;
	}
		


	imshow("轮廓", drawing);
	/********透视变换过程*************************************************************************/
	////检测是否是四边形,很多图片检测不到
	//	if (approx.size() != 4)
	//	{
	//		std::cout << "The object is not quadrilateral(四边形)!" << std::endl;
	//		return -1;
	//	}
	//	//get mass center  寻找四边形中点
	//	for (unsigned int i = 0; i < corners.size(); i++)
	//	{
	//		center += corners[i];
	//	}
	//	center *= (1. / corners.size());
	//
	//	//确定四个点的中心线
	//	sortCorners(corners, center);
	//
	//	cv::Mat dst = src.clone();
	//
	//	//Draw Lines  画直线
	//	for (unsigned int i = 0; i<lines.size(); i++)
	//	{
	//		cv::Vec4i v = lines[i];
	//		cv::line(dst, cv::Point(v[0], v[1]), cv::Point(v[2], v[3]), CV_RGB(0, 255, 0));    //目标版块画绿线   
	//	}
	//
	//	//draw corner points  画角点
	//	cv::circle(dst, corners[0], 3, CV_RGB(255, 0, 0), 2);
	//	cv::circle(dst, corners[1], 3, CV_RGB(0, 255, 0), 2);
	//	cv::circle(dst, corners[2], 3, CV_RGB(0, 0, 255), 2);
	//	cv::circle(dst, corners[3], 3, CV_RGB(255, 255, 255), 2);
	//
	//	//draw mass center  画出四边形中点
	//	cv::circle(dst, center, 3, CV_RGB(255, 255, 0), 2);
	//
	//	cv::Mat quad = cv::Mat::zeros(300, 220, CV_8UC3);//设定校正过的图片从320*240变为300*220  
	//
	//	//corners of the destination image  
	//	std::vector<cv::Point2f> quad_pts;
	//	quad_pts.push_back(cv::Point2f(0, 0));
	//	quad_pts.push_back(cv::Point2f(quad.cols, 0));//(220,0)  
	//	quad_pts.push_back(cv::Point2f(quad.cols, quad.rows));//(220,300)  
	//	quad_pts.push_back(cv::Point2f(0, quad.rows));
	//
	//	// Get transformation matrix  
	//	cv::Mat transmtx = cv::getPerspectiveTransform(corners, quad_pts);   //求源坐标系(已畸变的)与目标坐标系的转换矩阵  
	//
	//	// Apply perspective transformation透视转换  
	//	cv::warpPerspective(src, quad, transmtx, quad.size());

	//	cv::namedWindow("image", 0);
	//	cv::imshow("image", dst);
	//
	//	cv::namedWindow("quadrilateral", 0);
	//	cv::imshow("quadrilateral", quad);


	waitKey(0);
	return 0;
}





float getDistance(CvPoint pointO, CvPoint pointA)
{//求两点之间距离
	float distance;
	distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
	distance = sqrtf(distance);

	return distance;
}

float getAngle(CvPoint pointM, CvPoint pointL, CvPoint pointR)
{//求三点之间的夹角
	CvPoint L, R;
	float dist_L, dist_R, Theta;
	L.x = pointL.x - pointM.x;
	L.y = pointL.y - pointM.y;
	R.x = pointR.x - pointM.x;
	R.y = pointR.y - pointM.y;
	dist_L = getDistance(pointL, pointM);
	dist_R = getDistance(pointR, pointM);
	Theta = acos((L.x*R.x + L.y*R.y) / (dist_L*dist_R));
	return Theta;
}
发布了465 篇原创文章 · 获赞 694 · 访问量 96万+

猜你喜欢

转载自blog.csdn.net/mao_hui_fei/article/details/80428681