热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OpenCV——相当通俗易懂的SVD奇异值分解

在说明前,我也是查了大量文档,弄清楚各个名词的意思,才写下这篇博客。。。特征值和特征向量:根据公式:A是

在说明前,我也是查了大量文档,弄清楚各个名词的意思,才写下这篇博客。。。

特征值和特征向量:

根据公式:Ax = \lambda x

A是n*n的方阵(必须是方阵),x是特征向量,λ是特征值。

一般情况下,会有n个特征值,和n个特征向量。(这里的一般是指方阵是满秩,各行各列都是线性无关)。

引出问题:如果不是n*n维的矩阵,怎么求?

假设矩阵X是m*n,则可以求XX^TX^TX矩阵的特征分解。

一般的非方阵的特征分解称为奇异值分解。

奇异值分解(Singular Value Decomposition)是线性代数中一种重要的矩阵分解,奇异值分解则是特征分解在任意矩阵上的推广。在信号处理、统计学等领域有重要应用。

奇异值分解SVD:

A是m*n大小的矩阵

根据公式:A = USV^T

U是左奇异矩阵

同理V是右奇异矩阵

剩下一个S:奇异值矩阵,理论上S的大小应该是m*n才能满足矩阵乘法运算。

A = USV^T =》 AA^T = USV^TVS^TU^T =》 US^2U^T

理解:V^TV = I, V是单位正交基,不知道的可百度。

理解:SS^T = S^2,S是奇异值,一般的是n行一列的矩阵,为了方便计算,我们设计S变成对角矩阵,即n*1 =》n*n。

右奇异矩阵举例:

其中V是矩阵A^TA的特征向量,   n*n大小

 (A^TA)V = \lambda V 得到奇异值S=\sqrt{\lambda },且S是n列矩阵,V是n*n维,反求左奇异值

AV=SU  =》 U = \frac{1}{S}AV 最后得到U是m*n维

A_{m*n}=U_{m*n}S_{n*n}V_{n*n}^T

左奇异矩阵举例:

其中U是矩阵AA^T的特征向量 m*m大小

(AA^T)U = \lambda U得到奇异值S=\sqrt{\lambda },且S是m列矩阵,U是m*m维,反求右奇异值

A^TU=SV  =》 V = \frac{1}{S}A^TU 得到V是n*m维(这里是U的转置)

A_{m*n}=U_{m*m}S_{m*m}V_{m*n}^T

opencv求SVD:

#include
#include using namespace cv;
using namespace std;
void main()
{Mat src &#61; imread("1.jpg", IMREAD_GRAYSCALE);Mat src_ &#61; src.clone();src.convertTo(src, CV_64FC1);Mat U, W, V;SVD::compute(src, W, U, V);int set_dim &#61; min(src.rows, src.cols);//cout <<"W >> <" <" <> <" <" <> <" <" <> " <(i, i) &#61; W.at(i, 0);}Mat dst &#61; U * W_ * V;system("pause");
}

opencv里的W,U,V分别对应前文的 S,U,V^T 且维数计算是左奇异矩阵举例的模式。

利用eigen自己实现svd&#xff1a;

详细看注释

void main()
{Mat m &#61; imread("1.jpg", IMREAD_GRAYSCALE);Mat src &#61; m.clone();Mat S, U;m.convertTo(m, CV_64FC1);double t1 &#61; getTickCount();eigen(m * m.t(), S, U); //求出奇异值矩阵 和 左奇异矩阵U &#61; U.t(); //根据公式 U变成转置后的int set_dim &#61; min(src.rows, src.cols);for (int i &#61; 0; i (i, 0);double sq_val &#61; sqrt(val);S.at(i, 0) &#61; sq_val; //λ &#61; sqrt(S)}Mat V;V &#61; m.t() * U; //根据公式for (int i &#61; 0; i (j, i) &#61; V.at(j, i) / S.at(i, 0);}}Mat Vt &#61; V.t();Mat S_ &#61; Mat(S.rows, S.rows, CV_64FC1, Scalar(0));for (int i &#61; 0; i (i, i) &#61; S.at(i, 0);}dst &#61; U * S_ * Vt;imshow("src", src);imshow("dst", dst);waitKey();}

降维分析&#xff1a;

一直S是对角矩阵&#xff0c;且按降序排列&#xff0c;根据实际测试前10%甚至1%的奇异值就能涵盖99%以上的特征。

可以设置r &#61; ratio * n (ratio&#xff1a;比率)

公式&#xff1a;A_{m*n}&#61;U_{m*n}S_{n*n}V_{n*n}^T  &#xff08;公式1&#xff09;&#61;》 A_{m*n}&#61;U_{m*r}S_{r*r}V_{r*n}^T&#xff08;公式2&#xff09;

如果取r &#61; 0.01&#xff0c;降维后公式2维度是公式1 的 亿分之一。

#include
#include using namespace cv;
using namespace std;Mat getForeMatrix(int rows, int cols, Mat & img, int type)
{Mat tmp &#61; Mat(rows, cols, type, Scalar(0));for (int i &#61; 0; i (i, j) &#61; img.at(i, j);else if (type &#61;&#61; CV_32FC1)tmp.at(i, j) &#61; img.at(i, j);elsetmp.at(i, j) &#61; img.at(i, j);}}return tmp;
}
void main()
{Mat src &#61; imread(filename, IMREAD_GRAYSCALE);Mat src_ &#61; src.clone();src.convertTo(src, CV_64FC1);Mat U, W, V;SVD::compute(src, W, U, V, SVD::Flags::MODIFY_A);double t2 &#61; (getTickCount() - t1) / getTickFrequency();cout <<"cost time >> " <> <" <" <> <" <" <> <" <" <> " <(i, i) &#61; W.at(i, 0);}Mat U_ &#61; getForeMatrix(set_dim, set_rows , U, CV_64FC1);Mat V_ &#61; getForeMatrix(set_rows , V.cols, V, CV_64FC1);Mat dst &#61; U_ * W_ * V_;system("pause")
}

不正确的希望指出。。。不胜感激

更新错误日志2019.12.23&#xff0c;看了下左奇异矩阵举例&#xff1a;不需要将U转置。且更改了一些定义问题

最后&#xff1a;若要显示最终图像&#xff0c;需要将CV_64FC1图像转成CV_8UC1格式。

 


推荐阅读
  • 在稀疏直接法视觉里程计中,通过优化特征点并采用基于光度误差最小化的灰度图像线性插值技术,提高了定位精度。该方法通过对空间点的非齐次和齐次表示进行处理,利用RGB-D传感器获取的3D坐标信息,在两帧图像之间实现精确匹配,有效减少了光度误差,提升了系统的鲁棒性和稳定性。 ... [详细]
  • 在过去,我曾使用过自建MySQL服务器中的MyISAM和InnoDB存储引擎(也曾尝试过Memory引擎)。今年初,我开始转向阿里云的关系型数据库服务,并深入研究了其高效的压缩存储引擎TokuDB。TokuDB在数据压缩和处理大规模数据集方面表现出色,显著提升了存储效率和查询性能。通过实际应用,我发现TokuDB不仅能够有效减少存储成本,还能显著提高数据处理速度,特别适用于高并发和大数据量的场景。 ... [详细]
  • 本文详细探讨了OpenCV中人脸检测算法的实现原理与代码结构。通过分析核心函数和关键步骤,揭示了OpenCV如何高效地进行人脸检测。文章不仅提供了代码示例,还深入解释了算法背后的数学模型和优化技巧,为开发者提供了全面的理解和实用的参考。 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 本文提出了一种基于栈结构的高效四则运算表达式求值方法。该方法能够处理包含加、减、乘、除运算符以及十进制整数和小括号的算术表达式。通过定义和实现栈的基本操作,如入栈、出栈和判空等,算法能够准确地解析并计算输入的表达式,最终输出其计算结果。此方法不仅提高了计算效率,还增强了对复杂表达式的处理能力。 ... [详细]
  • ### 优化后的摘要本文对 HDU ACM 1073 题目进行了详细解析,该题属于基础字符串处理范畴。通过分析题目要求,我们可以发现这是一道较为简单的题目。代码实现中使用了 C++ 语言,并定义了一个常量 `N` 用于字符串长度的限制。主要操作包括字符串的输入、处理和输出,具体步骤涉及字符数组的初始化和字符串的逆序操作。通过对该题目的深入探讨,读者可以更好地理解字符串处理的基本方法和技巧。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 开发笔记:实现1353表达式中的括号匹配(栈的应用) ... [详细]
  • 在使用 Qt 进行 YUV420 图像渲染时,由于 Qt 本身不支持直接绘制 YUV 数据,因此需要借助 QOpenGLWidget 和 OpenGL 技术来实现。通过继承 QOpenGLWidget 类并重写其绘图方法,可以利用 GPU 的高效渲染能力,实现高质量的 YUV420 图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。 ... [详细]
  • 本文详细介绍了在 Oracle 数据库中使用 MyBatis 实现增删改查操作的方法。针对查询操作,文章解释了如何通过创建字段映射来处理数据库字段风格与 Java 对象之间的差异,确保查询结果能够正确映射到持久层对象。此外,还探讨了插入、更新和删除操作的具体实现及其最佳实践,帮助开发者高效地管理和操作 Oracle 数据库中的数据。 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 深入解析C语言中结构体的内存对齐机制及其优化方法
    为了提高CPU访问效率,C语言中的结构体成员在内存中遵循特定的对齐规则。本文详细解析了这些对齐机制,并探讨了如何通过合理的布局和编译器选项来优化结构体的内存使用,从而提升程序性能。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 深入解析 OpenCV 2 中 Mat 对象的类型、深度与步长属性
    在OpenCV 2中,`Mat`类作为核心组件,对于图像处理至关重要。本文将深入探讨`Mat`对象的类型、深度与步长属性,这些属性是理解和优化图像操作的基础。通过具体示例,我们将展示如何利用这些属性实现高效的图像缩小功能。此外,还将讨论这些属性在实际应用中的重要性和常见误区,帮助读者更好地掌握`Mat`类的使用方法。 ... [详细]
  • 基于Node.js的高性能实时消息推送系统通过集成Socket.IO和Express框架,实现了高效的高并发消息转发功能。该系统能够支持大量用户同时在线,并确保消息的实时性和可靠性,适用于需要即时通信的应用场景。 ... [详细]
author-avatar
渊博的效力
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有