opencv学习笔记六十四:PCA原理与应用

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矩亦可求得,另外可看到这些零件的主方向,进而得到其偏移角度。

猜你喜欢

转载自blog.csdn.net/qq_24946843/article/details/82872226
今日推荐