PCA真实操作中的大坑真的是伤不起啊。。。。今天讲一个潜意识出错的问题。在本人博客中有另外两篇转载的博客是记录PCA的思路讲解,有需要的可以看一下。
Mat m(10, 2, CV_32F, Scalar(0));
Mat dt = cv::Mat_<double>(m);
dt.at<double>(0,0) = 2.5;
dt.at<double>(0,1) = 2.4;
dt.at<double>(1,0) = 0.5;
dt.at<double>(1,1) = 0.7;
dt.at<double>(2,0) = 2.2;
dt.at<double>(2,1) = 2.9;
dt.at<double>(3,0) = 1.9;
dt.at<double>(3,1) = 2.2;
dt.at<double>(4,0) = 3.1;
dt.at<double>(4,1) = 3.0;
dt.at<double>(5,0) = 2.3;
dt.at<double>(5,1) = 2.7;
dt.at<double>(6,0) = 2;
dt.at<double>(6,1) = 1.6;
dt.at<double>(7,0) = 1;
dt.at<double>(7,1) = 1.1;
dt.at<double>(8,0) = 1.5;
dt.at<double>(8,1) = 1.6;
dt.at<double>(9,0) = 1.1;
dt.at<double>(9,1) = 0.9
//执行pca算法
PCA pca(dt, Mat(), CV_PCA_DATA_AS_ROW);//第三个参数表示按照行模式读取数据,第四个参数表示所选主成分占比
Mat eigenvalues = pca.eigenvalues.clone();//计算得到的主成分特征值
Mat eigenvectors = pca.eigenvectors.clone(); //计算得到的主成分特征
得到的主成分特征为:

从上面可以看出,得到两个主成分特征向量:(-0.735178656,0.677873399)与(-0.67787339,-0.735178656)。
接下来,问题出现了。本人是要求解特征向量与水平直线间得夹角,从而进行图像的倾斜矫正。
如上图所示,我们将蓝色线看做是所求得的向量,求其与水平方向的夹角 sita。
这里出现了第一个问题,我按照特征值的大小进行排列,我使用最大特征值所对应的特征向量进行求解角度时总是求解得不对,然后抱着尝试的态度使用第二个特征向量进行角度求解,竟然成功了,这其中的原因现在还是不是太了解,为什么第一个不行,第二个就可以。
第一个问题出现后,接着第二个问题出现了,在这里我们需要摒弃我们传统的思维模式,看到获取的特征向量就认为是(x,y)模式。在PCA中其特征向量属于(y,x)模式,即第一个值为y轴坐标值,而第二个值为x轴坐标值。
所以对于上图中我们所求得角度应该采用特征向量:
(-0.735178656,0.677873399) 其夹角 sita = arctan( (-0.735178656)/ 0.677873399 );
这里需要记录一下,我是用C++中的反三角函数求得角度值。这里简单介绍一下:《C++中cos,sin,asin,acos这些三角函数操作的是弧度,而非角度》
弧度=角度*Pi/180;
例子1:
比如对边和邻边分别为a,b
设角度为x,则
x=atan(a/b);
其中x为弧度制
如需转换为角度值,则x*180/3.1415
例子2:
//计算旋转角度 {弧度=角度*Pi/180} {两点间距离公式 根号下(|X1-X2|的平方+|Y1-Y2|的平方)}
double angle_tanValue=sqrt(pow(point.x-point.x,2)+pow(point.y-Right_Top_Point.y,2))/
sqrt(pow(Turn_Point_L[1].x-point.x,2)+pow(Turn_Point_L[1].y-Right_Top_Point.y,2));
//求出tan 与 sin 的弧度
double angle_atanValue=atan(angle_tanValue);
double angle_sinValue=sin(angle_atanValue);
//弧度转换成角度
double angle=angle_atanValue*180/3.1415;
//取绝对值
angle=fabs(angle);