学习opencv(第三次任务)

任务要求

1.找出图像各几何图像的边长或半径;获取个图象边长或半径;获取图像形状
2.用PCA降维 将二维数组降到一维

平台

在opencv下 使用的c++代码

原理,思路

第一题: 用拟合曲线求出角点,角点的个数代表了每个图形,角点坐标可以求出中心坐标
第二题: 运用线性代数转化
1、对所有样本进行中心化(去均值操作);
2、计算样本的协方差矩阵;
3、对协方差矩阵做特征值分解;
4、取最大的特征值所对应的特征向量;
5、将原样本矩阵与投影矩阵相乘: X*V即为降维后数据集X’ ;
6、输出:降维后的数据集X’
7、还原降维压缩的矩阵:Y = X’ * V^T
8、输出还原矩阵Y

代码

第一题

下面展示一些 内联代码片

下面展示一些 内联代码片

头文件
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
//定义全局变量
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;


/// Function header
void thresh_callback(int, void*);


/** @function main */
int main(int argc, char** argv)
{
    // 加载源图像
    src = imread("D:/QT Projects/csdn_mode2/1.png");

    /*
     * 输入原图
     * 输出灰度图
     */
    cvtColor(src, src_gray, COLOR_BGRA2GRAY);

    /*
     * 输入灰度图
     * 输出原图片为高斯滤波图 卷积核为3*3
     */
    GaussianBlur(src_gray, src_gray, Size(3, 3), 5);

    //调用
    thresh_callback(0, 0);
    //等待键盘事件响应,否者一直等待
    waitKey(0);
    return(0);
}

/** @function thresh_callback */
void thresh_callback(int, void*)
{
    //给src_copy复制src的值并分配内存空间
    Mat src_copy = src.clone();
    //创建threshold_output用于后续的曲线拟合
    Mat threshold_output;
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    /*
     * 输入灰度图
     * 输出二值图像
     */
    threshold(src_gray, threshold_output, thresh, 255, THRESH_BINARY);

   /*
    * 输入二值图
    * 输出二维数组 contours
    */
    findContours(threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    /*Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);*/

    //曲线拟合
    vector<vector<Point> >poly(contours.size());
    for (int i = 0; i < contours.size(); i++)
    {
        /*
         * 输入曲线contours
         * 输出折线poly
         */
        approxPolyDP(Mat(contours[i]), poly[i], 5,true);
    }
    //遍历poly数组将每一个图像的角点坐标相加 除以角点个数 即为几何中心的坐标
    for(int i=1;i<4;i++){
        //x,y为几何中心的对应最表  n代表角点的个数  flag用于控制后面的判断
        int x=0;
        int y=0;
        int n=0;
        int flag=1;
        for(int j=0;j<poly[i].size();j++){
        //每个int j 这个循环结束后 x,y代表的都是角点对应轴的坐标和, n就是角点个数
        x+=poly[i][j].x;
        y+=poly[i][j].y;
        n++;
        }
        //坐标和除以个数 即为几何中心对应的坐标
        x/=n;
        y/=n;
        /* circle()函数
         * 输入几何中心的坐标点(Point类)
         * 输出  以几何中心为圆心 半径为3,颜色为黑色的小圆点
         */
        circle(src,Point(x,y),3,Scalar(0),1,8,0);

        //将数值类型的 x y坐标转化为string类
        string x1=to_string(x);
        string y1=to_string(y);
         /*
          * 输入目标图像,要输出的文字串,坐标点
          * 输出在对应点point处字体为FONT_HERSHEY_SIMPLEX,黑色的一行文字
          */
         putText(src,"("+x1+","+y1+")",Point(x,y-30),FONT_HERSHEY_SIMPLEX,1,Scalar(0),1,4,false);

         /*
          * 接下来的三个if:  遍历poly的同时,每一次循环通过poly[i]的大小判断边数多少 六边形等于6  五角星等于10  圆则更多;
          * flag用于标志本次循环是否完成了判断(已经完成为0  待完成为1)  减少判断次数
          */
         //六边形判断
        if(poly[i].size()==6 && flag==1){
            //用两点间距离公式求解边长(两个点为角点)
            double side_len=sqrt(pow(poly[i][0].x-poly[i][1].x,2)+pow(poly[i][0].y-poly[i][1].y,2));
            string b=to_string(side_len);
            //打印边长(side_Length)
            putText(src,"side_Length= "+b,Point(x,y),FONT_HERSHEY_SIMPLEX,0.8,Scalar(0),1,4,false);
            flag=0;
            //打印图像所属类型
            putText(src,"hexagon",Point(x,y+side_len),FONT_HERSHEY_SIMPLEX,0.8,Scalar(0),1,4,false);
        }
        //五角星判断
        if(poly[i].size()==10 && flag==1){
             //用两点间距离公式求解边长(两个点为角点)
            double side_len=sqrt(pow(poly[i][0].x-poly[i][1].x,2)+pow(poly[i][0].y-poly[i][1].y,2));
            string b=to_string(side_len);
            //打印边长(side_Length)
            putText(src,"side_Length= "+b,Point(x,y),FONT_HERSHEY_SIMPLEX,0.8,Scalar(0),1,4,false);
            flag=0;
            //打印图像所属类型
            putText(src,"five_Star",Point(x,y+side_len),FONT_HERSHEY_SIMPLEX,0.8,Scalar(0),1,4,false);
        }
        //圆的判断
        if(poly[i].size()>10 && flag==1){
             //用两点间距离公式求解半径(一个是拟合出来的圆边上的一点 一个是圆心)
            double side_len=sqrt(pow(poly[i][0].x-x,2)+pow(poly[i][0].y-y,2));
            string b=to_string(side_len);
            //打印半径radius
            putText(src,"radius="+b,Point(x,y),FONT_HERSHEY_SIMPLEX,0.8,Scalar(0),1,4,false);
            flag=0;
            //打印图像所属类型
            putText(src,"circle",Point(x+50,y+side_len),FONT_HERSHEY_SIMPLEX,0.8,Scalar(0),1,4,false);

        }
    }
    // 把结果显示在窗体
    imshow("src", src);
}

第二题

下面展示一些 内联代码片

头文件
#include<Eigen>
#include<Eigenvalues>
#include <opencv2/opencv.hpp>
#include<opencv2/core/eigen.hpp>
/*
 * 最好在release模式下运行
 */
int main()
{
    int m=5;        //数组的行
    int n=2;        //数组的列

    //初始化数组
    double matrix[5][2]={{2.3,2.9},{0.5,0.3},{1.6,1.4},{0.9,0.8},{1.8,1.1}};

    //求每个维度的均值向量 (不同向量的同一个维度  所有数值的平均值)   创建了长度为2的一位数组E来保存均值向量
    vector<double>E(2);
    for( int j=0 ; j<2 ; j++ ){
        double sum=0;
        for( int i=0 ; i<m ; i++ ){
            //对同一个维度的值累加到sum
            sum+=matrix[i][j];
        }
        //求得均值向量
        E[j]=sum/m;
    }

    //中心化矩阵 初始化倒置矩阵
    vector<vector<float>>centerMatrix(m,vector<float>(n));
    vector<vector<float>>centerMatrixT(n,vector<float>(m));
    for( int i=0 ; i<m ; i++ ){
        for( int j=0 ; j<n ; j++ ){
            //中心化矩阵(对应的矩阵值减去该维度上的均值向量)
            centerMatrix[i][j]=matrix[i][j]-E[j];
            //初始化初始矩阵的倒置矩阵
            centerMatrixT[j][i]=matrix[i][j];
        }
    }

    //计算协方差矩阵  covMatrix = 1 / (m-1) * matrixT * matrix
    Mat covMatrix(2,2,CV_32FC1);
    for ( int i=0 ; i<n ; i++ )
            for ( int j=0 ; j<n ; j++)
                for ( int k=0 ; k<m ; k++ ){
                    //运用矩阵乘法的原理  直接累加得到对应协方差矩阵值
                    covMatrix.at<float>(i,j)+=centerMatrixT[i][k] * centerMatrix[k][j];
                    covMatrix.at<float>(i,j)/=(m-1.0);
                }

    //val保存特征值  vec保存特征向量  MatrixXd 创建大小不定的double类矩阵
    MatrixXd val,vec;
    Matrix2d R_matrix;

    /*
     * 输入Mat类型矩阵
     * 输出Matrix类矩阵
     */
    cv2eigen(covMatrix,R_matrix);
    //计算特征值和特征向量,使用selfadjont按照对阵矩阵的算法去计算,可以让产生的vec和val按照有序排列
    SelfAdjointEigenSolver<MatrixXd> eig(R_matrix);
    //协方差矩阵的特征值
    val=eig.eigenvalues();
    //协方差矩阵的特征向量
    vec=eig.eigenvectors();
    //特征向量的矩阵转化到Mat矩阵里面
    Mat feature_Mat(3,3,CV_32FC1);

    /*
     * 输入Matrix类型矩阵
     * 输出Mat类型矩阵
     */
    eigen2cv(vec,feature_Mat);

    //将原矩阵放到以特征向量为基底的空间下面  创建final矩阵储存结果
    Mat final(1,5,CV_32FC1);
    //去最大特征向量的倒置与原矩阵相乘
    for( int i=0 ; i<1 ; i++ ){
        for( int j=0 ; j<5 ; j++ ){
            final.at<float>(i,j)=(float)(feature_Mat.at<float>(0,1)*centerMatrixT[0][j]+        //利用矩阵乘法的性质(这里本该是feature_Mat的倒置矩阵来做乘法的   我这里用的是原矩阵 所有下标值应该翻过来)
                                        feature_Mat.at<float>(1,1)*centerMatrixT[1][j]);
        }
    }

    //输出最终结果
    cout<<"Final_Data:"<<final;


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值