在本文中,稀疏表示的原理不再具体讲解,有需要的同学请自行百度。

本文采用OMP算法来求解稀疏系数。首先随机生成字典数据和待测试数据

字典数据:

dic =[
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];

  这是一个5*10的矩阵,行数代表维度,列数代表样本数。列数在字典中也叫字典原子,此处有10个原子,原子数大于维数,符合过完备要求。

信号数据:

signal=[  9;   8;   8;   3;   9];

  为了简便,只模拟了一个信号数据,是一个5*1的矩阵,如果有多个数据,则应该是5*n的矩阵。求解的时候,可用循环求解。

一、在matlab中实现稀疏表示,求解稀疏系数

clc;close all;clear all;
dic =[
, , , , , , , , , ;
, , , , , , , , , ;
, , , , , , , , , ;
, , , , , , , , , ;
, , , , , , , , , ]; %字典
signal=[ ; ; ; ; ]; %原始信号
dic=dic*diag(./sqrt(sum(dic.^))); %字典原子单位化,即每列的norm为1
signal=signal/norm(signal); %信号单位化
[A,res]=OMP(dic,signal,); %稀疏度设定为6,即非零元素最多为6个
A %输出系数
res %输出残差
epsilon=norm(signal-dic*A) %验证残差 ||Y-Dx||

其中OMP算法:

%OMP计算稀疏系数
function [A,res]=OMP(D,X,L)
% 输入参数:
% D - 过完备字典,注意:必须字典的各列必须经过了规范化
% X - 信号
% L - 稀疏度,系数中非零元个数的最大值
% 输出参数:
% A - 当前信号的系数
% res - 残差 %%
residual=X; %初始化残差
indx=zeros(L,1);
for i=1:L,
proj=D'*residual;%D转置与residual相乘,得到与residual与D每一列的内积值
[~,pos]=max(abs(proj));%找到内积最大值的位置
pos=pos(1);%若最大值不止一个,取第一个
indx(i)=pos;%将这个位置存入索引集的第j个值
a=pinv(D(:,indx(1:i)))*X;%indx(1:j)表示第一列前j个元素
residual=X-D(:,indx(1:i))*a;
res=norm(residual);
if res< 1e-6
break;
end
end
A=zeros(size(D,2),1);
A(indx(indx~=0))=a;
end

  

  结果:

A =

    0.1450
0.9391 0.4210
0.1049 -0.5503 res = 3.1402e-16 epsilon = 3.1402e-16

从系数中可以看出,从10个原子共选出了5个原子进行表示,最后的残差非常小,说明稀疏表示的结果和原数据非常接近。

二、在opencv2中实现稀疏表示

void getData(Mat &data, Mat &signal);
int main(int argc, char* argv[])
{
Mat dic, signal;
getData(dic, signal); //获取模拟数据
Mat temp(, dic.cols, CV_32F); //用一个矩阵保存每个原子的模长
for (int i = ; i<dic.cols; i++)
{
temp.col(i) = norm(dic.col(i)); //每个原子的模长
}
divide(dic, repeat(temp, dic.rows, ), dic); //字典原子单位化
signal = signal / norm(signal); //信号单位化
Mat A=src.OMP(dic, signal, ); //调用OPM求解
float res =(float)norm(signal - dic*A); //计算残差
cout << "系数:" <<endl<< A << endl;
cout<<endl<<"残差:"<< endl<<res << endl; //输出残差
waitKey();
return ;
}
void getData(Mat &dic, Mat &signal)
{
dic = (Mat_<float>(, ) <<
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , );
signal = (Mat_<float>(, ) << , , , , );
}

其中,OMP函数为:

Mat SRC::OMP(Mat& dic, Mat& signal,int sparsity)

{
if (signal.cols>)
{
cout << "wrong signal" << endl;
exit(-);
}
vector<int> selectedAtomOrder; //保存所有选出的字典原子序号
Mat coef(dic.cols, , CV_32F, Scalar::all()); //需要返回的系数
Mat residual = signal.clone(); //初始化残差
Mat indx(, , CV_32F);//初始化临时系数
Mat phi; //保存已选出的原子向量
float max_coefficient;
unsigned int atomOrder; //每次所选择的原子的序号 for (;;)
{
max_coefficient = ;
//取出内积最大列
for (int i = ; 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 == )
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-) //如果残差小于阈值或达到要求的稀疏度,就返回
{
for (int k = ; k < selectedAtomOrder.size(); k++)
{
coef.row(selectedAtomOrder[k]).setTo(indx.row(k)); //得到最终的系数
}
return coef;
}
}
}

最终输出结果为:

系数:
[0.14503297;
0.9391216;
;
;
0.42096639;
0.1048916;
;
;
-0.55029994;
] 残差:
1.70999e-007

看以看出,opencv得到的系数和matlab得到的系数基本是一样,只是小数点后保留的位数区别。因为小数位数不相同,所以最后残差有点不同,但不影响最终结果,我们只需要系数相同即可。

在matlab和opencv中分别实现稀疏表示的更多相关文章

  1. 使用C++将OpenCV中Mat的数据写入二进制文件,用Matlab读出

    在使用OpenCV开发程序时,如果想查看矩阵数据,比较费劲,而matlab查看数据很方便,有一种方法,是matlab和c++混合编程,可以用matlab访问c++的内存,可惜我不会这种方式,所以我就把 ...

  2. 在OpenCV中实现matlab中的im2double功能

    最近在把matlab的代码转化到VS2010上. matlab中采用im2double将读入的图像转换为double型,在OpenCV中就需要对图像进行深度的转换. 读入一幅灰度图像,深度为1(8U) ...

  3. Matlab中psf2otf()函数在opencv中的实现

    在Matlab中有个psf2otf()函数,可以将小尺寸的点扩散函数,扩大尺寸,并作二维傅里叶变换,opencv中没有这个函数,所以编了这么个函数: /************************ ...

  4. opencv中Mat与IplImage,CVMat类型之间转换

    opencv中对图像的处理是最基本的操作,一般的图像类型为IplImage类型,但是当我们对图像进行处理的时候,多数都是对像素矩阵进行处理,所以这三个类型之间的转换会对我们的工作带来便利. Mat类型 ...

  5. 【kate总结】matlab调用opencv总结

    正常情况下,编写好matlab调用opencv的代码. 1.输入   MEX XX.CPP(所有的mex都要编译) 2.将生成的.mexw64 放到要调用的文件夹下即可 出错总结: 本人写的matla ...

  6. 立体视觉-opencv中立体匹配相关代码

    三种匹配算法比较 BM算法: 该算法代码: view plaincopy to clipboardprint? CvStereoBMState *BMState = cvCreateStereoBMS ...

  7. opencv中Mat类型数据操作与遍历

    Mat作为opencv中一种数据类型常常用来存储图像,相对与以前的IplImgae类型来说,Mat类型省去了人工的对内存的分配与释放,转而自动分配释放.Mat Class主要包括两部个数据部分:一个是 ...

  8. OpenCV中Mat的列向量归一化

    OpenCV中Mat的列向量归一化 http://blog.csdn.net/shaoxiaohu1/article/details/8287528 OpenCV中Mat的列向量归一化 标签: Ope ...

  9. [OpenCV-Python] OpenCV 中的图像处理 部分 IV (四)

    部分 IVOpenCV 中的图像处理 OpenCV-Python 中文教程(搬运)目录 21 OpenCV 中的轮廓 21.1 初识轮廓目标 • 理解什么是轮廓 • 学习找轮廓,绘制轮廓等 • 函数: ...

随机推荐

  1. 如何在Java Filter 中注入 Service

    在项目中遇到一个问题,在 Filter中注入 Serivce失败,注入的service始终为null.如下所示: public class WeiXinFilter implements Filter ...

  2. 第一篇 UEditor入门部署和体验

    UEditor 是由百度「FEX前端研发团队」开发的所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码. UEditor富文本编辑器,轻量, ...

  3. malloc calloc 和 realloc

    realloc()函数 原型:extern void *realloc(void *mem_address, unsigned int newsize); 语法:指针名=(数据类型*)realloc( ...

  4. spark Basic code demo

    spark-shell --master=spark://namenode01:7077 --executor-memory 2g --driver-class-path /app/spark141/ ...

  5. 基于Retrotfit2.1+Material Design+ijkplayer开发的一个APP(新闻,gif 动图,视频播放)

    此项目主要目的还是为了练习框架的使用,仅供学习用途. 数据来源 新闻 直接用的聚合数据提供的接口:https://www.juhe.cn/docs/api/id/235gif动图 通过jsoup爬的某 ...

  6. 查看Ubuntu版本

    一.查看Ubuntu版本号 方法一 root@wiki:~# cat /etc/issue Ubuntu 14.04.1 LTS \n \l 方法二 root@wiki:~# sudo lsb_rel ...

  7. 关于JavaScipt对象的基本知识

    关于JavaScipt对象的基本知识 JavaScript是运用“对象化编程”的,又叫“面向对象编程”的.所谓“对象化编程”,意义是把JavaScript能涉及的领域划分成各种对象,对象后面还连续划分 ...

  8. POJ-1979 Red and Black(DFS)

    题目链接:http://poj.org/problem?id=1979 深度优先搜索非递归写法 #include <cstdio> #include <stack> using ...

  9. Java语法基础(一)----关键字、标识符、常量、变量

    一.关键字: 关键字:被Java语言赋予特定含义的单词.组成关键字的字母全部小写.注:goto和const作为保留字存在,目前并不使用.main并不是关键字. 二.标识符: 标识符:就是给类,接口,方 ...

  10. 利用OpacityMask制作打洞效果

    起因 项目上存在一个连线功能,在设计的原型中,在连线中间文字上下各有15像素的空白.接手的同事觉得没思路,问我能不能在不影响连线后面的背景情况下解决该问题.我就抽了点时间给他写了个Demo.回家后趁热 ...