PCA的作用是压缩数据,去除冗余的特征,将原始多维数据在一组新的基上表示,新的基由原始数据协方差矩阵的特征向量构成,使得投影方差最大,即特征最大化,在我的这篇博客中有详细推导https://blog.csdn.net/qq_24946843/article/details/81775368
#include<opencv2\opencv.hpp>
using namespace cv;
using namespace std;
double calcPCAorientation(vector<Point>&pts, Mat &image);
int main(int arc, char** argv) {
Mat src = imread("3.jpg");
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
Mat gray, binary;
cvtColor(src, gray, CV_BGR2GRAY);
threshold(gray, binary, 0,255,THRESH_BINARY|THRESH_OTSU);
//imshow("binary", binary);
vector<vector<Point>>contours;
findContours(binary, contours, RETR_LIST, CHAIN_APPROX_NONE);
Mat result = src.clone();
for (int i = 0; i < contours.size(); i++) {
double area = contourArea(contours[i]);
if (area > 1e5|| area < 1e2)continue;
drawContours(result, contours, i, Scalar(0, 0, 255),2);
calcPCAorientation(contours[i], result);
}
imshow("result", result);
waitKey(0);
return 0;
}
double calcPCAorientation(vector<Point>&pts, Mat &image) {
int size = pts.size();
Mat data_pts = Mat(size, 2, CV_64FC1);
for (int i = 0; i < size; i++) {
data_pts.at<double>(i, 0) = pts[i].x;
data_pts.at<double>(i, 1) = pts[i].y;
}
//PCA
PCA pca_analysis(data_pts, Mat(), CV_PCA_DATA_AS_ROW);
Point cnt = Point(pca_analysis.mean.at<double>(0, 0), pca_analysis.mean.at<double>(0, 1));//平均值
circle(image, cnt, 2, Scalar(0, 255, 0), 2);
vector<Point2d>vecs(2);//特征向量
vector<double>vals(2);//特征值
for (int i = 0; i < 2; i++) {
vals[i] = pca_analysis.eigenvalues.at<double>(i, 0);
vecs[i] = Point2d(pca_analysis.eigenvectors.at<double>(i, 0), pca_analysis.eigenvectors.at<double>(i, 1));
}
Point p1 = cnt + Point(static_cast<int>(vecs[0].x*200), static_cast<int>(vecs[0].y*200));
Point p2 = cnt - Point(static_cast<int>(vecs[1].x*50), static_cast<int>(vecs[1].y*50));
//即将原直角坐标系中的数据在下面新的一组基中表示,使得数据特征最大化
line(image, cnt, p1, Scalar(255, 0, 0), 2);//主特征方向
line(image, cnt, p2, Scalar(0, 255, 0), 2);//与主特征垂直方向
double angle = atan2(vecs[0].y, vecs[0].x);
printf("angle:%.2f\n", 180*angle/CV_PI);
printf("%d,%d\n", vals[0], vals[1]);
return angle;
}
可得到这些零件的中心,利用Hu矩亦可求得,另外可看到这些零件的主方向,进而得到其偏移角度。