opencv PCA 主軸方向角度範圍

哈库拉發表於2024-10-27

PCA 主軸方向角度,範圍 [-45,135]
點集排序(從左到右、從右至左)不同,角度在-45度時有差異

opencv PCA 主軸方向角度範圍

double calLineOrientationInDegree(const vector<Point>& pts)
{
    //Construct a buffer used by the pca analysis
    int sz = static_cast<int>(pts.size());
    Mat data_pts = Mat(sz, 2, CV_64F);
    for (int i = 0; i < data_pts.rows; i++)
    {
        data_pts.at<double>(i, 0) = pts[i].x;
        data_pts.at<double>(i, 1) = pts[i].y;
    }
    //Perform PCA analysis
    PCA pca_analysis(data_pts, Mat(), PCA::DATA_AS_ROW);
    //Store the center of the object
    Point2d cntr = Point2d(static_cast<double>(pca_analysis.mean.at<double>(0, 0)),
        static_cast<double>(pca_analysis.mean.at<double>(0, 1)));
    //Store the eigenvalues and eigenvectors
    vector<Point2d> eigen_vecs(2);
    vector<double> eigen_val(2);
    for (int i = 0; i < 2; i++)
    {
        eigen_vecs[i] = Point2d(pca_analysis.eigenvectors.at<double>(i, 0),
            pca_analysis.eigenvectors.at<double>(i, 1));
        eigen_val[i] = pca_analysis.eigenvalues.at<double>(i);
    }
    
    eigenVecs = eigen_vecs;
    double angle = atan2(eigen_vecs[0].y, eigen_vecs[0].x) * 180 / 3.1415926; // orientation in degrees 
    return angle;
}

// 測試PCA 主軸角度範圍
// 點集從左到右,從右到左
void test_PCA_mainAxis_AngleRange()
{
    // 構造點集
    double angle = 10;
    //int ang = 135;
    for (int ang = 0;ang < 365;ang += 5)
    {
        angle = ang;
        cv::Mat white(1000, 1000, CV_8UC3, Scalar(255, 255, 255));
        std::vector<cv::Point> pts;
        pts.clear();
        double vsin = sin(angle / 180.0 * 3.1415926);
        double vcos = cos(angle / 180.0 * 3.1415926);
        Point offset(300, 300);
        for (int i = 0;i < 200;i++)
        {

            int px = int(double(i) * vcos) + offset.x;
            int py = int(double(i) * vsin) + offset.y;

            Point pt(px, py);
            pts.push_back(pt);
            circle(white, pt, 3, Scalar(0, 0, 255), -1);
        }
        // 排序 
        std::sort(pts.begin(), pts.end(), [](Point& p1, Point& p2) {
            return p1.x < p2.x;
            });

        // 計算pca 角度
        double pac_angle = calLineOrientationInDegree(pts);
        cv::putText(white, cv::format("%.1f", pac_angle), Point(30, 30), cv::FONT_HERSHEY_PLAIN, 2, Scalar(255, 0, 20), 2);

        // 從右向左
        std::sort(pts.begin(), pts.end(), [](Point& p1, Point& p2) {
            return p1.x > p2.x;
            });
        double pac_angle2 = calLineOrientationInDegree(pts);
        cv::putText(white, cv::format("%.1f", pac_angle2), Point(130, 30), cv::FONT_HERSHEY_PLAIN, 2, Scalar(25, 0, 220), 2);

        // show pts
        cv::imshow("xx", white);

        //cv::waitKey(0);
        while (1)
        {
            if (cv::waitKey(10) == 27)
            {
                cv::destroyAllWindows();
                break;
            }
        }
    }
}

相關文章