1 /** 2 * @file introduction_to_pca.cpp 3 * @brief This program demonstrates how to use OpenCV PCA to extract the orienation of an object 4 * @author OpenCV team 5 */ 6 7 #include <iostream> 8 #include <opencv2/opencv.hpp> 9 10 using namespace std; 11 using namespace cv; 12 13 // Function declarations 14 void drawAxis(Mat&, Point, Point, Scalar, const float); 15 double getOrientation(const vector<Point> &, Mat&); 16 17 /** 18 * @function drawAxis 19 */ 20 void drawAxis(Mat& img, Point p, Point q, Scalar colour, const float scale = 0.2) 21 { 22 //! [visualization1] 23 double angle; 24 double hypotenuse; 25 angle = atan2( (double) p.y - q.y, (double) p.x - q.x ); // angle in radians 26 hypotenuse = sqrt( (double) (p.y - q.y) * (p.y - q.y) + (p.x - q.x) * (p.x - q.x)); 27 // double degrees = angle * 180 / CV_PI; // convert radians to degrees (0-180 range) 28 // cout << "Degrees: " << abs(degrees - 180) << endl; // angle in 0-360 degrees range 29 30 // Here we lengthen the arrow by a factor of scale 31 q.x = (int) (p.x - scale * hypotenuse * cos(angle)); 32 q.y = (int) (p.y - scale * hypotenuse * sin(angle)); 33 line(img, p, q, colour, 1, CV_AA); 34 35 // create the arrow hooks 36 p.x = (int) (q.x + 9 * cos(angle + CV_PI / 4)); 37 p.y = (int) (q.y + 9 * sin(angle + CV_PI / 4)); 38 line(img, p, q, colour, 1, CV_AA); 39 40 p.x = (int) (q.x + 9 * cos(angle - CV_PI / 4)); 41 p.y = (int) (q.y + 9 * sin(angle - CV_PI / 4)); 42 line(img, p, q, colour, 1, CV_AA); 43 //! [visualization1] 44 } 45 46 /** 47 * @function getOrientation 48 */ 49 double getOrientation(const vector<Point> &pts, Mat &img) 50 { 51 //! [pca] 52 //Construct a buffer used by the pca analysis 53 int sz = static_cast<int>(pts.size()); 54 Mat data_pts = Mat(sz, 2, CV_64FC1); 55 for (int i = 0; i < data_pts.rows; ++i) 56 { 57 data_pts.at<double>(i, 0) = pts[i].x; 58 data_pts.at<double>(i, 1) = pts[i].y; 59 } 60 61 //Perform PCA analysis 62 PCA pca_analysis(data_pts, Mat(), CV_PCA_DATA_AS_ROW); 63 64 //Store the center of the object 65 Point cntr = Point(static_cast<int>(pca_analysis.mean.at<double>(0, 0)), 66 static_cast<int>(pca_analysis.mean.at<double>(0, 1))); 67 68 //Store the eigenvalues and eigenvectors 69 vector<Point2d> eigen_vecs(2); 70 vector<double> eigen_val(2); 71 for (int i = 0; i < 2; ++i) 72 { 73 eigen_vecs[i] = Point2d(pca_analysis.eigenvectors.at<double>(i, 0), 74 pca_analysis.eigenvectors.at<double>(i, 1)); 75 76 eigen_val[i] = pca_analysis.eigenvalues.at<double>(0, i); 77 } 78 79 //! [pca] 80 //! [visualization] 81 // Draw the principal components 82 circle(img, cntr, 3, Scalar(255, 0, 255), 2); 83 Point p1 = cntr + 0.02 * Point(static_cast<int>(eigen_vecs[0].x * eigen_val[0]), static_cast<int>(eigen_vecs[0].y * eigen_val[0])); 84 Point p2 = cntr - 0.02 * Point(static_cast<int>(eigen_vecs[1].x * eigen_val[1]), static_cast<int>(eigen_vecs[1].y * eigen_val[1])); 85 drawAxis(img, cntr, p1, Scalar(0, 255, 0), 1); 86 drawAxis(img, cntr, p2, Scalar(255, 255, 0), 5); 87 88 double angle = atan2(eigen_vecs[0].y, eigen_vecs[0].x); // orientation in radians 89 //! [visualization] 90 91 return angle; 92 } 93 94 /** 95 * @function main 96 */ 97 int main(int, char** argv) 98 { 99 //! [pre-process] 100 // Load image 101 // Mat src = imread("pca_test1.jpg"); 102 Mat src = imread(argv[1]); 103 104 // Check if image is loaded successfully 105 if(!src.data || src.empty()) 106 { 107 cout << "Problem loading image!!!" << endl; 108 return EXIT_FAILURE; 109 } 110 111 imshow("src", src); 112 113 // Convert image to grayscale 114 Mat gray; 115 cvtColor(src, gray, COLOR_BGR2GRAY); 116 117 // Convert image to binary 118 Mat bw; 119 threshold(gray, bw, 50, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); 120 //! [pre-process] 121 122 //! [contours] 123 // Find all the contours in the thresholded image 124 vector<Vec4i> hierarchy; 125 vector<vector<Point> > contours; 126 findContours(bw, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); 127 128 for (size_t i = 0; i < contours.size(); ++i) 129 { 130 // Calculate the area of each contour 131 double area = contourArea(contours[i]); 132 // Ignore contours that are too small or too large 133 if (area < 1e2 || 1e5 < area) continue; 134 135 // Draw each contour only for visualisation purposes 136 drawContours(src, contours, static_cast<int>(i), Scalar(0, 0, 255), 2, 8, hierarchy, 0); 137 // Find the orientation of each shape 138 getOrientation(contours[i], src); 139 } 140 //! [contours] 141 142 imshow("output", src); 143 144 waitKey(0); 145 return 0; 146 }