PCA图像转正C++

《PCA图像转正C++》

  去年写的博客,写到另一个号里面了,今天恰好一个同事问到了,想起来把这篇博客迁移过来,顺便完善一下。PCA的功能还是挺多的,最常用的就是降维,原理也比较简单,找到方差最大的方向。这里直接把工程中的两个脚本抽离出来,方便查阅,供大家参考。

Key Words:主成分分析、C++实现


Beijing, 2021.01

作者:RaySue

Agile Pioneer  

PCA原理

  简单说下PCA的原理,就是求解向量 v,让原始数据在 v 方向上的方差最大,各个主成分之间相互正交。求解目标就是最大化在向量 v 上的方差,来求解 v 向量,原理细节参见参考链接。

   具体计算就比较简单了,数据去中心化,计算特征间的协方差矩阵,然后计算协方差的特征值和特征向量就是对应的主成分和方差贡献率。

MaskRotation.h

//
// Created by surui on 2019/12/17.
//

#ifndef IDEATRAINER_MASKROTATION_H
#define IDEATRAINER_MASKROTATION_H

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

#define PI acos(-1)


class MaskRotation {

public:

    /**
     * input mask foreground pixels' value is 255
     * @param mask
     * @param points
     */
    static void getAllForeGroundPoints(Mat mask, Mat &points);

    /**
     * pca fit data
     * @param Points
     * @return angle
     */
    static float pca(const Mat &Points);

    /**
     * rotate mask to upright by pca's angle
     * @param angle
     * @param mask
     */
    static void rotateToUpright(float angle, Mat &mask);

};


#endif //IDEATRAINER_MASKROTATION_H


MaskRotation.cpp

//
// Created by surui on 2019/12/17.
//

void MaskRotation::getAllForeGroundPoints(Mat mask, Mat &points) {
    int height = mask.rows;
    int width = mask.cols;
    for (int i = 0; i < height; ++i) {
        const uchar *rowi = mask.ptr<uchar>(i);
        for (int j = 0; j < width; ++j) {
            if (rowi[j] == 255) {
                Mat point = Mat(cv::Size(2, 1), CV_32FC1);
                point.at<float>(0, 0) = i;
                point.at<float>(0, 1) = j;
                points.push_back(point);
            }
        }
    }
}


float MaskRotation::pca(const Mat &Points) {
    int components = 2;
    float angle = 0.0;
    try {
        cv::PCA pca(Points, cv::Mat(), CV_PCA_DATA_AS_ROW, components);
        float scx = pca.eigenvectors.at<float>(0, 0);
        float scy = pca.eigenvectors.at<float>(0, 1);
        float cosx = scy / sqrt(scx * scx + scy * scy);
        angle = (float) ((acos(cosx) - PI / 2) / PI * 180);
    } catch (cv::Exception e) {
        cout << "Error pca : " << e.msg << endl;
    }
    return angle;
}


void MaskRotation::rotateToUpright(float angle, Mat &mask) {
    int height = mask.rows;
    int width = mask.cols;
    try {
        Point2f center(width / 2, height / 2);
        Mat M = cv::getRotationMatrix2D(center, angle, 1.0);
        cv::warpAffine(mask, mask, M, cv::Size(width, height), cv::INTER_LINEAR, cv::BORDER_REPLICATE);
        M.release();
    } catch (cv::Exception e) {
        cout << "Error image rotate : " << e.msg << endl;
    }

}

参考

https://zhuanlan.zhihu.com/p/33262929

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值