opencv3学习:reshape函数
在opencv中,reshape函数比较有意思,它既可以改变矩阵的通道数,又可以对矩阵元素进行序列化,非常有用的一个函数。
函数原型:
C++: Mat Mat::reshape(int cn, int rows=) const
参数比较少,但设置的时候却要千万小心。
cn: 表示通道数(channels), 如果设为0,则表示保持通道数不变,否则则变为设置的通道数。
rows: 表示矩阵行数。 如果设为0,则表示保持原有的行数不变,否则则变为设置的行数。
首先设置一个初始矩阵:一个20行30列1通道的一个矩阵
int main()
{
Mat data = Mat(, , CV_32F); //设置一个20行30列1通道的一个矩阵
cout << "行数: " << data.rows << endl;
cout << "列数: " << data.cols << endl;
cout << "通道: " << data.channels() << endl;
system("pause");
return ;
}
输出:

第一次变化:通道数不变,将矩阵序列化1行N列的行向量。
int main()
{
Mat data = Mat(, , CV_32F); //设置一个20行30列1通道的一个矩阵
cout << "行数: " << data.rows << endl;
cout << "列数: " << data.cols << endl;
cout << "通道: " << data.channels() << endl;
cout << endl;
Mat dst = data.reshape(, );
cout << "行数: " << dst.rows << endl;
cout << "列数: " << dst.cols << endl;
cout << "通道: " << dst.channels() << endl;
system("pause");
return ;
}

第二次变化:通道数不变,将矩阵序列化N行1列的列向量。
int main()
{
Mat data = Mat(, , CV_32F); //设置一个20行30列1通道的一个矩阵
cout << "行数: " << data.rows << endl;
cout << "列数: " << data.cols << endl;
cout << "通道: " << data.channels() << endl;
cout << endl;
Mat dst = data.reshape(, data.rows*data.cols);
cout << "行数: " << dst.rows << endl;
cout << "列数: " << dst.cols << endl;
cout << "通道: " << dst.channels() << endl;
system("pause");
return ;
}

可见,序列成列向量比行向量要麻烦一些,还得去计算出需要多少行。但我们可以先序列成行向量,再转置
Mat dst = data.reshape(, ); //序列成行向量
Mat dst = data.reshape(, ).t(); //序列成列向量
第三次变化:通道数由1变为2,行数不变。
int main()
{
Mat data = Mat(, , CV_32F); //设置一个20行30列1通道的一个矩阵
cout << "行数: " << data.rows << endl;
cout << "列数: " << data.cols << endl;
cout << "通道: " << data.channels() << endl;
cout << endl;
Mat dst = data.reshape(, 0);
cout << "行数: " << dst.rows << endl;
cout << "列数: " << dst.cols << endl;
cout << "通道: " << dst.channels() << endl;
system("pause");
return ;
}

从结果可以看出,列数被分出一半,放在第二个通道里去了。
同理,如果通道数由1变为3,行数不变。则每通道的列数变为原来的三分之一。
需要注意的是,如果行保持不变,改变的通道数一定要能被列数整除,否则会出错。
第四次变化:通道数由1变为2,行数变为原来的五分之一。
int main()
{
Mat data = Mat(, , CV_32F); //设置一个20行30列1通道的一个矩阵
cout << "行数: " << data.rows << endl;
cout << "列数: " << data.cols << endl;
cout << "通道: " << data.channels() << endl;
cout << endl;
Mat dst = data.reshape(, data.rows/);
cout << "行数: " << dst.rows << endl;
cout << "列数: " << dst.cols << endl;
cout << "通道: " << dst.channels() << endl;
system("pause");
return ;
}

可见,不管怎么变,都遵循这样一个等式:
变化之前的 rows*cols*channels = 变化之后的 rows*cols*channels
我们只能改变通道数和行数,列数不能改变,它是自动变化的。
但是要注意的是,在变化的时候,要考虑到是否整除的情况。如果改变的数值出现不能整除,就会报错。
最后,我们再验证一下:opencv在序列化的时候是行序列化还是列序列化呢?
我们知道,在matlab里面,是列序列化, 即取值为从上到下,从左到右,opencv又是怎么样的呢
int main()
{
Mat data = (Mat_<int>(, ) << , , , , , ); //2行3列的矩阵
cout << data << endl;
Mat dst1 = data.reshape(, ); //通道不变,序列成列向量
cout <<endl<< dst1 << endl;
Mat dst2 = data.reshape(, ); //通道不变,序列成行向量
cout << endl << dst2 << endl;
system("pause");
return ;
}

从结果看出,不管是变化成行向量还是列向量,opencv都是行序列化,即从左到右,从上到下,与matlab是不一样的。
简单的一个函数,功能却很强大!你会用了吗
opencv3学习:reshape函数的更多相关文章
- JavaScript学习09 函数本质及Function对象深入探索
JavaScript学习09 函数本质及Function对象深入探索 在JavaScript中,函数function就是对象. JS中没有方法重载 在JavaScript中,没有方法(函数)重载的概念 ...
- Matlab 的reshape函数
看Matlab的help文档讲得不是清楚. 先给上一段代码: >> a=[1 2 3;4 5 6;7 8 9;10 11 12]; >> b=reshape(a,2,6); 这 ...
- Matlab 的reshape函数(转)
看Matlab的help文档讲得不是清楚. 先给上一段代码: >> a=[1 2 3;4 5 6;7 8 9;10 11 12]; >> b=reshape(a,2,6); 这 ...
- C++学习之函数指针
C++学习之函数指针 和数据项类似,函数也有地址,函数的地址是存储在机器语言代码的内存的开始地址.通常,这些地址对用户而言,不重要也没什么用处,但对程序而言,它却很有用. 一.函数 ...
- Javascript学习5 - 函数
原文:Javascript学习5 - 函数 在Javascript中,函数和对象是交织在一起的.有些函数的特性与对象相关联.这一点的内容在第六部分会讨论到. 这一部分主要讨论函数与其它比较熟悉的语言( ...
- OpenCV3学习笔记
http://blog.csdn.net/u010429424/article/details/73691001 http://blog.csdn.net/zhaoxfxy/article/detai ...
- 《python基础教程(第二版)》学习笔记 函数(第6章)
<python基础教程(第二版)>学习笔记 函数(第6章) 创建函数:def function_name(params): block return values 记录函数:def f ...
- python学习8—函数之高阶函数与内置函数
python学习8—函数之高阶函数与内置函数 1. 高阶函数 a. map()函数 对第二个输入的参数进行第一个输入的参数指定的操作.map()函数的返回值是一个迭代器,只可以迭代一次,迭代过后会被释 ...
- python学习7—函数定义、参数、递归、作用域、匿名函数以及函数式编程
python学习7—函数定义.参数.递归.作用域.匿名函数以及函数式编程 1. 函数定义 def test(x) # discription y = 2 * x return y 返回一个值,则返回原 ...
随机推荐
- Swift学习--闭包的简单使用(三)
一.Swift中闭包的简单使用 override func viewDidLoad() { super.viewDidLoad() /** 闭包和OC中的Block非常相似 OC中的block类似于匿 ...
- 关于破解IDEA
博客的意义就在于分享 哈哈 今天想装个 IDEA玩玩 去官网 下了个 安装包 想破解 结果度娘 帮解决了 直接po方法 很简单 就是安装好注册的时候 选择 License server ,填 http ...
- Validation of viewstate MAC failed. 解决方法
前段时间公司为了减轻服务器压力,对网页做了集群,分布在多台服务器,通过DNS轮回解析到各台服务器,结果页面只要打开停留到DNS解析到下一个地址,就会出现出下错误信息. Validation of vi ...
- win8下出现安装sql2012 正在启动操作系统功能"NetFx3"
今天上午装win8系统,发现在装sql server 2012的时候,一直停在"正在启动操作系统功能"NetFx3""不动了,在网上找了下相关的资料,发现原来N ...
- Linux线程学习(一)
一.Linux进程与线程概述 进程与线程 为什么对于大多数合作性任务,多线程比多个独立的进程更优越呢?这是因为,线程共享相同的内存空间.不同的线程可以存取内存中的同一个变量.所以,程序中的所有线程都可 ...
- Effective Java 08 Obey the general contract when overriding equals
When it's the case that each instance of the class is equal to only itself. 1. Each instance of the ...
- Effective Java 72 Don't depend on the thread scheduler
Principle Any program that relies on the thread scheduler for correctness or performance is likely t ...
- 由获取微信access_token引出的Java多线程并发问题
背景: access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.开发者需要进行妥善保存.access_token的存储至少要保留512个字符空间.acces ...
- Java异常处理和设计【转】
Java异常处理和设计 在程序设计中,进行异常处理是非常关键和重要的一部分.一个程序的异常处理框架的好坏直接影响到整个项目的代码质量以及后期维护成本和难度.试想一下,如果一个项目从头到尾没有考虑过异常 ...
- Azure 上为Liunx VM 挂载File类型的存储。
1. Create a storage account in Azure, copy the storage account endpoint URL (with postfix of "f ...