参考资料:
1、《矩阵分析与应用》张贤达
2、博客:《在matlab和opencv中分别实现稀疏表示》 https://www.cnblogs.com/denny402/p/5016530.html
一、稀疏向量与稀疏表示
1、信号的稀疏表示:使用少量基本信号的线性组合表示一目标信号。
2、稀疏向量(sparse vector)或者稀疏矩阵(sparse matrix):一个含有大多数零元素的向量或者矩阵。
二、稀疏矩阵方程求解
本博客介绍正交匹配追踪算法OMP(orthogonal matching pursuit)。
基本思想:不是针对某个代价函数进行最小化,而是考虑迭代地构造一个稀疏解X:只使用字典矩阵A的少量列向量的线性组合对观测向量X实现稀疏逼近AX=Y,其中字典矩阵A被选择的列向量所组成的作用集是以逐列的方式建立的。在每一步迭代,字典矩阵中同当前残差向量r=AX-Y最相似的列向量被选择作为作用集的新的一列。如果残差随着迭代的进行递减,则可以保证算法收敛。正交匹配追踪能够保证每步迭代后残差向量与以前选择的所有列向量正交,以保证迭代的最优性,从而减少迭代次数。
三、在opencv中实现稀疏表示
void getData(Mat &data, Mat &signal);
int main(int argc, char* argv[])
{
Mat dic, signal;
getData(dic, signal); //获取模拟数据
Mat temp(1, dic.cols, CV_32F); //用一个矩阵保存每个原子的模长
for (int i = 0; i<dic.cols; i++)
{
temp.col(i) = norm(dic.col(i)); //每个原子的模长
}
divide(dic, repeat(temp, dic.rows, 1), dic); //字典原子单位化
signal = signal / norm(signal); //信号单位化
Mat A=src.OMP(dic, signal, 8); //调用OPM求解
float res =(float)norm(signal - dic*A); //计算残差
cout << "系数:" <<endl<< A << endl;
cout<<endl<<"残差:"<< endl<<res << endl; //输出残差
waitKey(0);
return 0;
}
void getData(Mat &dic, Mat &signal)
{
dic = (Mat_<float>(5, 10) <<
6, 7, 9, 9, 7, 0, 6, 3, 6, 9,
1, 8, 7, 8, 5, 3, 8, 1, 7, 3,
3, 3, 5, 4, 8, 2, 6, 1, 2, 2,
6, 1, 0, 7, 3, 5, 0, 6, 3, 3,
7, 5, 0, 5, 3, 0, 2, 7, 1, 7);
signal = (Mat_<float>(5, 1) << 9, 8, 8, 3, 9);
}
其中,OMP函数为:
Mat SRC::OMP(Mat& dic, Mat& signal,int sparsity)
{
if (signal.cols>1)
{
cout << "wrong signal" << endl;
exit(-1);
}
vector<int> selectedAtomOrder; //保存所有选出的字典原子序号
Mat coef(dic.cols, 1, CV_32F, Scalar::all(0)); //需要返回的系数
Mat residual = signal.clone(); //初始化残差
Mat indx(0, 1, CV_32F);//初始化临时系数
Mat phi; //保存已选出的原子向量
float max_coefficient;
unsigned int atomOrder; //每次所选择的原子的序号
for (;;)
{
max_coefficient = 0;
//取出内积最大列
for (int i = 0; i <dic.cols; i++)
{
float coefficient = (float)dic.col(i).dot(residual);
if (abs(coefficient) > abs(max_coefficient))
{
max_coefficient = coefficient;
atomOrder = i;
}
}
selectedAtomOrder.push_back(atomOrder); //添加选出的原子序号
Mat& temp_atom = dic.col(atomOrder); //取出该原子
if (phi.cols == 0)
phi = temp_atom;
else
hconcat(phi, temp_atom, phi); //将新原子合并到原子集合中(都是列向量)
indx.push_back(0.0f); //对系数矩阵新加一项
solve(phi, signal, indx, DECOMP_SVD); //求解最小二乘问题
residual = signal - phi*indx; //更新残差
float res_norm = (float)norm(residual);
if (indx.rows >= sparsity || res_norm <= 1e-6) //如果残差小于阈值或达到要求的稀疏度,就返回
{
for (int k = 0; k < selectedAtomOrder.size(); k++)
{
coef.row(selectedAtomOrder[k]).setTo(indx.row(k)); //得到最终的系数
}
return coef;
}
}
}
最终输出结果为:
系数:
[0.14503297;
0.9391216;
0;
0;
0.42096639;
0.1048916;
0;
0;
-0.55029994;
0]
残差:
1.70999e-007