使用openCV与C++求图片特征值及特征向量并进行图片处理

利用openCV求图片特征值及特征向量

1、运用openCV与c++所涉及的头文件

#include<iostream>
#include<cstring>
#include<highgui.h>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;//工程所需头文件
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2、以灰度形式导入图片

 Mat image;
  image =imread("C:\\Users\\taekookie\\source\\repos\\图片处理\\图片处理\\任务.jpg",0);//通过绝对路径导入图片
  imshow("原图", image);//展示原图
  waitKey(0);
  destroyAllWindows();
  • 1
  • 2
  • 3
  • 4

最开始读入图片时选择的是相对路径imread(“任务.jpg"),在代码调试时报错,故而改为了绝对路径。而imshow()函数使用时,需保持独立单一窗口,否则会出现图片显示未响应现象,所以代码中加入了waitKey();与 destroyAllWindows()。

3、将图片像素值矩阵转变为可操作的数据类型

 Mat src;
 image.convertTo(src, CV_32FC1);
  • 1

4、通过open CV中的eigen()计算特征值与特征向量

  cv::Mat eValuesMat;//特征值
  cv::Mat eVectorsMat;//特征向量
  eigen(src, eValuesMat, eVectorsMat);//通过openCV中eigen函数得到特征值与特征向量
  • 1
  • 2

5.1、保留最大的50个特征值对图片进行处理

a、对特征值进行排序

for (int i = 0; i < eValuesMat.rows; i++)//对特征值进行由大到小的排序
{
for (int j = 1; j < eValuesMat.rows - i; j++)
{
if (eValuesMat.at<float>(i,0) < eValuesMat.at<float>(i + j,0))
{
p = eValuesMat.at<float>(i+j, 0);
eValuesMat.at<float>(i, 0) = eValuesMat.at<float>(i + j, 0);
eValuesMat.at<float>(i + j, 0) = p;
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

b、选取最大的50个特征值

int m=50;
 Mat Max(eValuesMat.rows, eValuesMat.rows, eValuesMat.type(), Scalar(0));
 for (int i = 0; i < m; i++)
 {
 Max.ptr<float>(i)[i] = eValuesMat.ptr<float>(i)[0];//最大的m个特征值组成的对角阵
 }
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

c、求解特征向量的逆阵

eVectorsMat = eVectorsMat.t();//eigen函数所得特征向量以行形式存储,故而进行转置后再参与运算
Mat inv;
invert(eVectorsMat, inv);//对特征向量矩阵求逆
  • 1
  • 2

由于特征向量是以行形式承载,故先进行转置

d、计算新的矩阵,并以RGB图片形式保存

new_src1 = eVectorsMat * Max * inv;
new_src1.convertTo(new_src1, CV_8UC1);//转换新矩阵数据类型
cvtColor(new_src1, new_src1, CV_GRAY2RGB);//改变图片类型
imwrite("Max.jpg", new_src1);
  • 1
  • 2
  • 3

e、由于openCV中eigen()函数只处理矩阵的上三角部分,所以还需要将src进行转置,处理下三角部分,并使两部分拼接在一起才能真正实现图片完整的处理

Mat img=imread("C:\\Users\\taekookie\\source\\repos\\test\\test\\Max.jpg", 0);
Mat timg = imread("C:\\Users\\taekookie\\source\\repos\\test\\test\\Max1.jpg", 0);
Mat s, ts;
img.convertTo(s, CV_32FC1);
timg.convertTo(s, CV_32FC1);
for (int i = 0; i < 512; i++)//实现上三角部分与下三角部分图片的拼接
{
s.at<float>(i, j) = ts.at<float>(i, j);
}
imwrite("finalR.jpg", s);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5.2、随机选取50个特征值对图片进行处理

a、通过srand()函数随机选取50个特征值

unsigned n=50;
srand(n);//通过随机函数取相应数量特征值
int i = 0, j = 0;
while (i = rand() % (eValuesMat.rows) + 1)
{
if (j == (eValuesMat.rows - 50))break;
eValuesMat.at<float>(i, 0) = 0;
j++;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

b、eigen()函数形成的特征值不是对角阵形式,故进行特征值对角化

Mat vals(eValuesMat.rows, eValuesMat.rows, eValuesMat.type(), Scalar(0));//由于eigen函数得到的特征值非对角阵形式,故而将其转换成对角阵形式
float* vals_data = eValuesMat.ptr<float>(0);//通过Mat类自带指针与自定义指针类进行赋值
for (i = 0; i < eValuesMat.rows; i++)
{
vals.ptr<float>(i)[i] = vals_data[i];
}
  • 1
  • 2
  • 3
  • 4
  • 5

c、计算新矩阵并保存(代码与5.1(d)类似)

d、进行上三角部分与下三角部分的拼接(代码与5.1(e)类似)

6、效果呈现
原图:

选取最大的50个特征值:
a、上三角部分

b、下三角部分

c、拼接后:

随机选取50个特征值:
a、上三角:

b、下三角

c、拼接后

(0)

相关推荐