关闭

【OpenCV3.3】特征值、奇异值分解与图像矩阵重构

9469人阅读 评论(0) 收藏 举报
分类:

      在图像处理方面,矩阵分解被广泛用于降维(压缩)、去噪、特征提取、数字水印等,是十分重要的数学工具,其中特征分解(谱分解)和奇异值分解是两种常用方法,本文简单介绍如何在OpenCV中使用它们对图像进行分解,然后重新构造图像。

      本文不会阐述两种分解的数学背景知识,但是为了方便读者唤醒记忆,会先贴出(部分)数学定义,详细的介绍和证明建议阅读矩阵理论相关书籍或者参考资料。

特征值分解

矩阵对角化定理(Matrix diagonalization theorem):对于 N×N 方阵 A ,如果它有 N 个线性无关的特征向量,那么存在一个特征分解

A=QΛQ−1

其中, Q N×N 方阵,且其第 i 列为A 的特征向量qiΛ是对角矩阵,其对角线上的元素为对应的特征值,即 Λiii

更进一步,如果方阵 A 是对称方阵,可得 Q 的每一列都是 A 的互相正交且归一化(单位长度)的特征向量,即 Q−1=QT,此即 对称对角化定理(Symmetric diagonalization theorem)。

奇异值分解

定义    设的特征值为

则称 A 的奇异值;当 A为零矩阵时它的奇异值都是0。

定理    设,则存在m阶酉矩阵 U n 阶酉矩阵V,使得

其中,而为矩阵A 的全部非零奇异值。改写上式为

称该式为矩阵 A 奇异值分解

      由上述定义(结合矩阵理论)可以看到,特征分解相比奇异值分解其应用条件要苛刻得多,特征分解要求矩阵与 对角矩阵(可对角化) 或 Jordan标准形矩阵 相似,这在图像上一般是不满足的,而奇异值分解适用于任何矩阵,应用范围也就更加广泛,但是奇异值分解本身时间复杂度相当高,随着矩阵规模的增长,计算复杂度将呈立方增长,所以很多情况下直接套用而不考虑优化是达不到性能指标的。

      落实到OpenCV中,提供了两个直接计算的方法,其中cv::eigen用于计算对称矩阵的特征值和特征向量,cv::SVD::compute用于进行奇异值分解,两者在目前版本使用的都是雅可比(Jacobi)法,下面是具体的C++代码例子,完成了两种分解与矩阵重构:

#include "stdafx.h"
#define CV_SHOW(a) cv::namedWindow(#a, cv::WINDOW_NORMAL); cv::imshow(#a, a); cv::resizeWindow(#a, a.cols * 3, a.rows * 3)

//-------------------------------------------------------------------------

INT WINAPI WinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPSTR, _In_ INT)
{
	cv::ipp::setUseIPP(true);

	// test.jpg是任意一副图片
	cv::Mat image = cv::imread("test.jpg", cv::IMREAD_REDUCED_GRAYSCALE_2);
	CV_SHOW(image);

	// 转换为OpenCV接受的计算类型,CV_32F或CV_64F
	cv::Mat srcimage;
	image.convertTo(srcimage, CV_32FC1);

	// 因为非方阵没有特征值,故取一个正方形, 注意未必是对称矩阵,并且 cv::eigen 计算时只会取上三角矩阵,故还原出的图片只是一半+对称
	cv::Mat square_word(srcimage, cv::Rect(0, 0, MIN(srcimage.cols, srcimage.rows), MIN(srcimage.cols, srcimage.rows)));
	cv::Mat vals, vecs;
	cv::eigen(square_word, vals, vecs);
	// 上述函数返回的特征值是列向量,转为对角矩阵,方便后面直接应用矩阵乘法
	cv::Mat diagonal_vals(vals.rows, vals.rows, vals.type(), cv::Scalar(0));
	float *__restrict vals_data = vals.ptr<float>(0);
	for (int i = 0; i < vals.rows; ++i) { // 尝试减少i的迭代次数,可以看到恢复后的图像与原图差距越来越大
		diagonal_vals.ptr<float>(i)[i] = vals_data[i];
	}
	// 根据公式,我们需要计算特征向量构成的矩阵的逆矩阵;由于属于不同特征值的特征向量线性无关,故而vecs必定可逆;
	// 注意每个特征向量以行形式存在vecs里,需要先转为列形式
	cv::transpose(vecs, vecs);
	cv::Mat vecs_inverted;
	cv::invert(vecs, vecs_inverted);
	// 恢复原图(的一半)
	cv::Mat e = vecs * diagonal_vals * vecs_inverted;
	// cv::imshow时如果输入图像是32位浮点类型,每个像素值会乘以255,这不是我们想要的
	e.convertTo(e, CV_8UC1);
	CV_SHOW(e);

	// 奇异值分解适用于任何矩阵,直接对srcimage进行计算
	cv::Mat w, U, Vt;
	cv::SVD::compute(srcimage, w, U, Vt);
	// 同样的,存放奇异值的W是列向量,转为对象矩阵
	cv::Mat W(w.rows, w.rows, w.type(), cv::Scalar(0));
	float *__restrict w_data = w.ptr<float>(0);
	for (int i = 0; i < w.rows; ++i) { // 奇异值已经按递减排序,一般取前面几个大的值就足以还原出基本原图,即有损压缩,这一过程也会将一些噪声压缩掉
		W.ptr<float>(i)[i] = w_data[i];
	}
	// 恢复原图
	cv::Mat svd = U * W * Vt;
	// 显示
	svd.convertTo(svd, CV_8UC1);
	CV_SHOW(svd);

	return cv::waitKey();
}

        参考资料

  1. 黄廷祝,钟守铭,李正良. 矩阵理论[M].北京:高等教育出版社,2003.32-37.
  2. 程云鹏,张凯院,徐仲. 矩阵论[M].西北工业大学出版社,2006.9.1
  3. 特征值分解和主成份分析
0
0
查看评论

OpenCV3.0 Examples学习笔记(18)-pca.cpp-PCA类实现降维处理

这个系列的目的是通过对OpenCV示例,进一步了解OpenCV函数的使用,不涉及具体原理。 目录 简介 Example运行截图 Example分析 Example代码 简介 本文记录了对OpenCV示例pca.cpp的分析。 资料地址:http://docs.openc...
  • u012566751
  • u012566751
  • 2017-02-16 15:37
  • 1727

opencv中SVD分解并恢复重构矩阵

opencv中SVD分解并恢复重构矩阵 特征值分解可以用在主成分分析(PCA)中,当使用opencv对一个矩阵进行了特征值分解后,可以根据分解出的u,w,v矩阵将原矩阵恢复回来。 //@cpp #include<opencv.hpp> using namespace std; using...
  • Daky_u
  • Daky_u
  • 2016-05-16 23:55
  • 5428

OpenCV中使用SVD分解与重构

OpenCV中使用SVD分解与重构
  • jacke121
  • jacke121
  • 2017-03-07 16:26
  • 1927

opencv SVD算法

#include #include using namespace std; using namespace cv; //SVD算法 int main() { string filename = "C:/Users/Administrator/Desktop/标准测试图片/Fig0...
  • zhanggusheng
  • zhanggusheng
  • 2017-04-13 19:05
  • 781

opencv学习一

opencv学习应该按照opencv的模块化设计进行学习。 基本也就分这么几块: core:简洁核心模块,基本函数,基本数据结构 imgproc:图像处理模块,线性和非线性图像滤波,几何图像转换,颜色空间转换,直方图等。 video:视频分析模块,运动估计,背景消除,物体跟踪算法 calib3d:...
  • langb2014
  • langb2014
  • 2016-03-04 16:45
  • 7037

OpenCV学习笔记(一)(二)(三)(四)(五)

OpenCV学习笔记(一) 决心开始研究OpenCV。闲言少叙,sourceforge网站最近的版本是2011年8月的OpenCV2.3.1,下载安装,我这里使用的开发环境是vs2008,网上搜了一下配置的教程,与之前的几个OpenCV版本的配置过程大体相同:(教程网上很多,知之为知之,不...
  • GarfieldEr007
  • GarfieldEr007
  • 2016-04-14 12:54
  • 2192

SVD应用的经典例子

Singular Value Decomposition (SVD) Tutorial
  • makenothing
  • makenothing
  • 2015-12-17 16:32
  • 1857

Opencv2.4.9源码分析——Expectation Maximization

一、原理   期望极大算法(EM,Expectation Maximization)是一种能够得到极大似然参数估计的迭代方法。虽然EM算法在不同的领域被更早的提出,但它是由Dempster等人于1977年被正式命名并给出解释。 对于一个除了拥有未知参数和可观测变量外,还包含隐含变量的统计模...
  • zhaocj
  • zhaocj
  • 2016-09-02 20:10
  • 2435

K-SVD学习笔记

K-SVD是一个用于稀疏表示的字典学习算法,是一个迭代算法,是K-Means算法的泛化。 对于问题(1) K-SVD的算法流程如下: I)固定字典,利用追踪算法(Pursuit Algorithm)求得(近似)最优的系数矩阵; II)每次更新一个列(SVD),固定字典的其它所有的列。计算新的列及...
  • JDPlus
  • JDPlus
  • 2015-11-26 15:56
  • 4372

PCA SVD opencv 降维对比

这里选用HOG 特征的数据对比 #include "stdafx.h" #include #include #include using namespace cv; using namespace std; vector get(string filename) ...
  • yeyang911
  • yeyang911
  • 2014-06-17 21:15
  • 1741
    联系作者
    通过QQ与我联系(全天候7*24小时基本不在线)
    最新评论
    免责声明
    如果转载的文章侵犯了您的版权,请务必告知,我将立刻删除;
    博客所有文章允许转载,原创类不要求注明出处,随意就好;
    如果是转载的文章,建议直接转载原始来源,因为原作者极可能有更新