检测四边形轮廓以及角点,新版 */ #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); float getDist_P2L(CvPoint pointP, CvPoint pointA, CvPoint pointB); int list_connor(int i1, int i2, int i3); 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]);//圆形度 //drawContours(drawing, contours, i, color, 1);//得到方框 if (Rectangularity[i]>0.8&&circularity[i]<0.9) {//通过矩形度和圆形度滤除数字 //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, point_add; vector<Point> connor4_add(3); //先找到的三个角点 int conP_i1, conP_i2, conP_i3, conP_i_add; int j = 0, flag = 0; Point finally_contours[80][4];//轮廓,为点向量,新的轮廓 for (j = 0; j < RectContours.size(); j++) //四边形轮廓个数 { distance = 0; distanceMax = 0; for (i = 0; i < RectContours[j].size(); i++) //每个轮廓点的个数11到19点不等 {//找第一个角点 distance = getDistance(RectContours[j][i], RectContours[j][0]); if (distance>distanceMax) { distanceMax = distance; connorPoint1 = RectContours[j][i]; //第一个角点 conP_i1 = i; } } distance = 0; distanceMax = 0; for (i = 0; i < RectContours[j].size(); i++) {//找第二个角点 distance = getDistance(RectContours[j][i], connorPoint1); if (distance>distanceMax) { distanceMax = distance; connorPoint2 = RectContours[j][i]; //第二个角点 conP_i2 = i; } } distance = 0; distanceMax = 0; for (i = 0; i < RectContours[j].size(); i++) {//找第三个角点 distance = getDistance(RectContours[j][i], connorPoint1) + getDistance(RectContours[j][i], connorPoint2); if (distance>distanceMax) { distanceMax = distance; connorPoint3 = RectContours[j][i]; //第三个角点 conP_i3 = i; } } flag = list_connor(conP_i1, conP_i2, conP_i3);//对三个角点由大到小排序 switch (flag) {//对三个角点排序 case 0:break; case 123:break; case 132:point_add = connorPoint2; connorPoint2 = connorPoint3; connorPoint3 = point_add; break;//2,3交换 case 213:point_add = connorPoint1; connorPoint1 = connorPoint2; connorPoint2 = point_add; break;//1,2交换 case 231:point_add = connorPoint1; connorPoint1 = connorPoint2; connorPoint2 = point_add; point_add = connorPoint2; connorPoint2 = connorPoint3; connorPoint3 = point_add; break;//1,2交换+2,3交换 case 321:point_add = connorPoint3; connorPoint3 = connorPoint1; connorPoint1 = point_add; break;//1,3交换 case 312:point_add = connorPoint3; connorPoint3 = connorPoint1; connorPoint1 = point_add; point_add = connorPoint2; connorPoint2 = connorPoint3; connorPoint3 = point_add; break;//1,3交换+2,3交换 } switch (flag) {//对三个角点排序 case 0:break; case 123:break; case 132:conP_i_add = conP_i2; conP_i2 = conP_i3; conP_i3 = conP_i_add; break;//2,3交换 case 213:conP_i_add = conP_i1; conP_i1 = conP_i2; conP_i2 = conP_i_add; break;//1,2交换 case 231:conP_i_add = conP_i1; conP_i1 = conP_i2; conP_i2 = conP_i_add; conP_i_add = conP_i2; conP_i2 = conP_i3; conP_i3 = conP_i_add; break;//1,2交换+2,3交换 case 321:conP_i_add = conP_i3; conP_i3 = conP_i1; conP_i1 = conP_i_add; break;//1,3交换 case 312:conP_i_add = conP_i3; conP_i3 = conP_i1; conP_i1 = conP_i_add; conP_i_add = conP_i2; conP_i2 = conP_i3; conP_i3 = conP_i_add; break;//1,3交换+2,3交换 } distance = 0; distanceMax = 0; for (i = conP_i3; i < conP_i2; i++) {//相隔两角点之间找到怀疑是4角点的点 distance = getDistance(RectContours[j][i], connorPoint3) + getDistance(RectContours[j][i], connorPoint2); if (distance>distanceMax) { distanceMax = distance; connor4_add[0] = RectContours[j][i]; } } distance = 0; distanceMax = 0; for (i = conP_i2; i < conP_i1; i++) {//相隔两角点之间找到怀疑是4角点的点 distance = getDistance(RectContours[j][i], connorPoint1) + getDistance(RectContours[j][i], connorPoint2); if (distance>distanceMax) { distanceMax = distance; connor4_add[1] = RectContours[j][i]; } } distance = 0; distanceMax = 0; for (i = conP_i1; i < RectContours[j].size() + conP_i3; i++) {//相隔两角点之间找到怀疑是4角点的点 if (i< RectContours[j].size()) { distance = getDistance(RectContours[j][i], connorPoint1) + getDistance(RectContours[j][i], connorPoint3); if (distance>distanceMax) { distanceMax = distance; connor4_add[2] = RectContours[j][i]; } } else { distance = getDistance(RectContours[j][i - RectContours[j].size()], connorPoint1) + getDistance(RectContours[j][i - RectContours[j].size()], connorPoint3); if (distance>distanceMax) { distanceMax = distance; connor4_add[2] = RectContours[j][i - RectContours[j].size()]; } } } if (getDist_P2L(connor4_add[0], connorPoint3, connorPoint2)>10) { connorPoint4 = connor4_add[0]; } else if (getDist_P2L(connor4_add[1], connorPoint2, connorPoint1)>10) { connorPoint4 = connor4_add[1]; } else if (getDist_P2L(connor4_add[2], connorPoint1, connorPoint3)>10) { connorPoint4 = connor4_add[2]; } circle(drawing, connorPoint1, 3, Scalar(255, 255, 255), FILLED, LINE_AA); circle(drawing, connorPoint2, 3, Scalar(255, 255, 255), FILLED, LINE_AA); circle(drawing, connorPoint3, 3, Scalar(255, 255, 255), FILLED, LINE_AA); circle(drawing, connorPoint4, 3, Scalar(255, 255, 255), FILLED, LINE_AA); finally_contours[j][0] = connorPoint1; finally_contours[j][1] = connorPoint2; finally_contours[j][2] = connorPoint3; finally_contours[j][3] = connorPoint4; cout << "\n轮廓 " << j+1 << " 的四个角点坐标分别为:\n" << finally_contours[j][0] << finally_contours[j][1] << finally_contours[j][2] << finally_contours[j][3] << endl; } //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 getDist_P2L(CvPoint pointP, CvPoint pointA, CvPoint pointB) {//点到直线的距离:P到AB的距离 //求直线方程 int A = 0, B = 0, C = 0; A = pointA.y - pointB.y; B = pointB.x - pointA.x; C = pointA.x*pointB.y - pointA.y*pointB.x; //代入点到直线距离公式 float distance = 0; distance = ((float)abs(A*pointP.x + B*pointP.y + C)) / ((float)sqrtf(A*A + B*B)); return distance; } //对角点进行排序,因为之前检测出的轮廓是带序号的 int list_connor(int i1, int i2, int i3) {//排序 int flag = 0; Point point_add; if (i1 >= i2&&i2 >= i3) flag = 123; else if (i1 >= i3&& i3 >= i2) flag = 132; else if (i2 >= i1&&i1 >= i3) flag = 213; else if (i2 >= i3&&i3 >= i1) flag = 231; else if (i3 >= i2&&i2 >= i1) flag = 321; else if (i3 >= i1&&i1 >= i2) flag = 312; return flag; } 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; }
检测图中若干四边形轮廓以及四个角点
猜你喜欢
转载自www.cnblogs.com/lx17746071609/p/11038376.html
今日推荐
周排行