- /************************************************************************/
- // 求解向量和轮廓的交点
- // by jsxyhelu(jsxyhelu.cnblogs.com)
- // 2018/10/05
- /************************************************************************/
- #include "stdafx.h"
- #include "opencv2/imgcodecs.hpp"
- #include "opencv2/highgui.hpp"
- #include "opencv2/imgproc.hpp"
- #include "opencv2/photo.hpp"
- using namespace std;
- using namespace cv;
- // 寻找最大外接轮廓
- vector<Point> FindBigestContour(Mat src){
- int max_area_contour_idx = 0;
- double max_area = -1;
- vector<vector<Point> >contours;
- findContours(src,contours,RETR_LIST,CHAIN_APPROX_SIMPLE);
- //handle case if no contours are detected
- CV_Assert(0 != contours.size());
- for (uint i=0;i<contours.size();i++){
- double temp_area = contourArea(contours[i]);
- if (max_area < temp_area ){
- max_area_contour_idx = i;
- max_area = temp_area;
- }
- }
- return contours[max_area_contour_idx];
- }
- // 程序主要部分
- int main( int argc, char** argv )
- {
- // 读入图像, 转换为灰度
- Mat src = imread("E:/sandbox/cloud.PNG");
- Mat src_gray;
- cvtColor(src, src_gray, COLOR_BGR2GRAY);
- // 阈值处理
- Mat threshold_output;
- cv::threshold(src_gray,threshold_output,150,255,THRESH_OTSU|THRESH_BINARY_INV);
- // 轮廓分析
- vector<vector<Point> > contours;
- vector<Vec4i> hierarchy;
- vector<Point> biggestContour = FindBigestContour(threshold_output);// 寻找最大轮廓
- Rect boundRect = boundingRect( Mat(biggestContour) ); // 获得轮廓最小外接矩形
- cv::rectangle(src,boundRect,Scalar(0,0,255));
- //pca 分析, 求出斜率和经过的一点
- Mat data_pts = Mat(biggestContour.size(), 2, CV_64FC1);//Construct a buffer used by the pca analysis
- for (int i = 0; i < data_pts.rows; ++i)
- {
- data_pts.at<double>(i, 0) = biggestContour[i].x;
- data_pts.at<double>(i, 1) = biggestContour[i].y;
- }
- PCA pca_analysis(data_pts, Mat(), CV_PCA_DATA_AS_ROW);// 执行 PCA 运算
- Point pos = Point2f(pca_analysis.mean.at<double>(0, 0),
- pca_analysis.mean.at<double>(0, 1)); // 主方向直线经过的一点
- vector<Point2d> eigen_vecs(2); // 保存 PCA 分析结果, 其中 0 组为主方向, 1 组为垂直方向
- vector<double> eigen_val(2);
- for (int i = 0; i < 2; ++i)
- {
- eigen_vecs[i] = Point2d(pca_analysis.eigenvectors.at<double>(i, 0),
- pca_analysis.eigenvectors.at<double>(i, 1));
- eigen_val[i] = pca_analysis.eigenvalues.at<double>(i,0);
- }
- line(src, pos - 0.02 * Point(eigen_vecs[0].x * eigen_val[0],eigen_vecs[0].y * eigen_val[0]),
- pos+0.02 * Point(eigen_vecs[0].x * eigen_val[0],eigen_vecs[0].y * eigen_val[0]) , Scalar(255, 255, 0));// 绘制概略主方向
- // 求出主方向直线和外接矩形的交点,
- float k = eigen_vecs[0].y/eigen_vecs[0].x; // 斜率
- Point2f pt1 = Point2f(boundRect.x,k*(boundRect.x - pos.x)+pos.y);
- Point2f pt2 = Point2f((boundRect.x+boundRect.width),k*((boundRect.x+boundRect.width)-pos.x)+pos.y);
- circle(src,pt1,5,Scalar(0,255,255),-1);
- circle(src,pt2,5,Scalar(0,255,255),-1);
- // 遍历两个交点之间的线段, 得出和轮廓的交点
- LineIterator it(src, pt1, pt2, 8);
- for(int i = 0; i < it.count; i++, ++it)
- {
- Point pt(it.pos());// 获得线段上的点
- if (abs(pointPolygonTest(biggestContour,pt,true)) < 1)
- circle(src,pt,5,Scalar(0,0,255),-1);
- }
- waitKey();
- return 0;
- }
来源: https://www.cnblogs.com/jsxyhelu/p/9745618.html