#include
#include
using namespace std;
using namespace cv;
double calcPCA(vector& contours, Mat& dst);//PCA主成分分析计算
//https://www.cnblogs.com/little-monkey/p/8111309.html
int main(int argc, char** argv)
{
Mat src,gray,temp_threshold,temp_contours,dst;
src = imread("../path.jpg");
if (src.empty())
{
cout << "could not load image..." << endl;
return -1;
}
//namedWindow("src", WINDOW_AUTOSIZE);
//imshow("src", src);
cvtColor(src, gray, COLOR_BGR2GRAY);//转为灰度图
threshold(gray,temp_threshold,0, 255, THRESH_BINARY | THRESH_OTSU);//二值化
vector hierarchy;
vector<vector> contours;
findContours(temp_threshold,contours,hierarchy, RETR_LIST, CHAIN_APPROX_NONE);//查找轮廓
temp_contours = src.clone();
for (int i = 0; i 1e5 || area < 1e2) continue;//过滤掉轮廓面积大于10^5和小于10^2的轮廓
drawContours(temp_contours, contours, i, Scalar(0, 0, 255), 2, 8);//绘制轮廓
double theta = calcPCA(contours[i], temp_contours);//PCA主成分分析
}
imshow("PCA", temp_contours);
waitKey(0);
return 0;
}
double calcPCA(vector& contours, Mat& dst)
{
int size = static_cast(contours.size());//static_cast强制类型转换
Mat data_contours = Mat(size, 2, CV_64FC1);//用来获取contours中的点的坐标//size个对象,2个维度(即平面坐标x,y)
for (int i = 0; i < size; i++)
{
data_contours.at(i, 0) = contours[i].x;
data_contours.at(i, 1) = contours[i].y;
}
//执行PCA的一系列步骤:样本数据-均值,算协方差,算特征值和特征向量……
PCA pca(data_contours, Mat(), PCA::DATA_AS_ROW);
//新的PCA基的中心值
Point center = Point(static_cast(pca.mean.at(0, 0)),
static_cast(pca.mean.at(0, 1)));
circle(dst, center, 2, Scalar(255, 0, 255), 2, 8);//绘制中心点
vector vecs(2);//特征矩阵
vector vals(2);//特征向量
for (int i = 0; i < 2; i++)
{
vals[i] = pca.eigenvalues.at(i, 0);
vecs[i] = Point2d(pca.eigenvectors.at(i, 0),
pca.eigenvectors.at(i, 1));
}
//将原直角坐标系中的数据在下面新的一组基中表示,使得数据特征最大化
Point p1 = center + 0.02*Point(static_cast(vecs[0].x * vals[0]), static_cast(vecs[0].y * vals[0]));
Point p2 = center - 0.05*Point(static_cast(vecs[1].x * vals[1]), static_cast(vecs[1].y * vals[1]));
line(dst, center, p1, Scalar(0, 255, 0), 2, 8);//新的基一//主特征方向
line(dst, center, p2, Scalar(255, 255, 0), 2, 8);//新的基二
//角度
double theta = atan2(vecs[0].y, vecs[0].x);
cout << "基角度为:" << 180 * (theta / CV_PI) << endl;
return 0;
}
src为:
输出结果: