由于本人从事的是图像算法开发,视频语义分析方面的工作,向广大图形处理爱好者推广OpenCV是我们非常高兴的一件事情,希望能抛砖引玉吧。首先,按照教程配置好OpenCV,linux或者window都可。在具体介绍之前,本人希望大家在学习时,尽量写标准的代码,这样不易出未知错,因为未知错误是无穷尽的。不用标准的写法,看起来好像是对的,可能某一天运行就出错了,有经历的人应该能理解我这句话。程序也是先跑出正确的结果(用比较慢,但符合人们思维的东西,代码,访问变量形式等等)->进行程序的后期优化(优化运行的速度),循序渐进。我的OpenCV会讲的很详细,大家并不需要教材!
OpenCV用#include <opencv2/opencv.hpp>,这里面已经包含了基本要用的全部头文件,包含这一个就可以了。对于库的话,用到哪个包含哪个,在前期的开发阶段,全部包含也可。Opencv可以显示的无符号字符与浮点图(要求在0-1)之间。最后在保存的时候会全部转化为无符号字符(后在细谈);
打开失败这个判断必须得有。彩色图是BGR的,我们先用灰度的图来作一些测试,这里定义了Mat对象后 用了函数进行了初始化;
怎么去访问呢?遍历的访问用Mat_<uchar> _img =img 这样来的话 改变_img也既改变了img ,有趣的是,若这里不是uchar 则对于灰度图它并没有改变原来的,只是可以访问而已。所以我们还是得先来看看Mat这个东西。
Mat 的初始化必须用CV_16UC1这种opencv的标准类型,Mat img(2,2,CV_16UC1, Scalar(0,1,2))--------Scalar没关系 如果一维的话自取第一个 后面的可以不写,默认为零,第一个也不写的话 全部为0,还是希望写一下;但是Mat_却只能用C++的类型 所以有以下的对照表
CV_8UC1 --------- unsigned char -------uchar
CV_8SC1 -------char 、、、几乎不用
CV_16UC1------------ unsigned short int
CV_16SC1------------short int
CV_32SC1------------int
CV_32FC1----------float
CV_64FC1 -------double
只有这七中 没有其他的。只能类型对应了 Mat_ 对象 就代表了Mat对象,更改会生效,否则不生效。当时 Mat_对于Mat值的读取是完全生效的,Mat_=Mat;赋值会成功。这可以认为它们指向了不同的地方,完成了数据的拷贝; 类型相同,则指向了相同的一块地方,Mat_与Mat之间不能引用,比较神奇,但就是这样的。定以后再用create方法初始化也可,但这样会以固定的值来初始化。img.create(2,2,CV_16UC1);各种初始化后才能用(i,j)坐标访问方法。
对于多维度的情形。
读取时候就要用Vec技术了,它内部已经定义好了。
Vec2b ----------------2维的 unsigned char
Vec2s-----------------short int
Vec2w----------------unsigned short int
Vec2i---------------int
Vec2f--------------float
Vec2d--------------double
常见的6种对应关系。
Mat_如此强大是不是Mat没用了呢?显然不是的,很多函数只是支持Mat,用Mat_会出现很多的错误,但Mat_与Mat可以相互赋值(用对方来构造自己),使它们指向同一块地方。Mat与Mat_ ,Mat与Mat ,Mat_与Mat_ 它们之间的转化还是需要说明的。
Mat与Mat:
Mat img;
img.create(2,2,CV_16SC1);
Mat f;
f.create(3,3,CV_8SC3);
img=f;
cout<<img<<endl<<f<<endl;它们之间的转化 相等 无视类型设定的大小,可以任意等于,使得指针指向同一块地方。若利用Mat_指向它们的地方,改变值,那么指向那里得到的值都将改变。
Mat与Mat_之间的转化;
(1)有Mat-》Mat_,这个前面已经有说明,Mat初始化后有了类型,Mat_要规定好类型,然后去指向Mat说指向的地方,如果类型相同 (这里指type,是CV_8UC3这种形式的,_mat也是的type输出 也必须是这种类型,这在if判断上很有用,输出则没有太多的意义。)若我们要将一个越界MAT转化为不越界的Mat(类型转化了) 可以用_mat,因为mat=_mat后,他的类型是由_mat决定的,这种转化最好还有_mat=_mat的过程。首先用一个类型不相同的_mat指向mat空间(防止改变原来 比原来的大一点比较好),然后对于_mat的每个元素用,saturate_cast<uchar>(feng(i,j)[k]);防止越界,阀值阶段。最好在定义一个_img为对应类型,转化过去,最后在定义一个mat直接等于,但这样存在了3个空间,我们可以用大括号将过程中的空间成为块,出块自动删除。C++中的块非常好用,内层替代外层,外层访问不到内层。这样就可以产生符合类型条件的mat。有些时候,mat的类型变化是很有用的。#include <string>
#include <opencv2\opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat f;
Mat_<Vec3b> _img;
f.create(3,3,CV_16UC3);
{
Mat_<Vec3i> feng=f;
cout<<fe<<endl;
int i,j,k;
for (i=0;i<fe.rows;i++)
for(j=0;j<fe.cols;j++)
for (k=0;k<3;k++)
{
fe(i,j)[k]=saturate_cast<uchar>(fe(i,j)[k]);
}
_img=fe;
}
int i(10);
cout<<_img<<endl;
if (_img.type()==CV_8UC3)
{
cout<<"xxxx"<<endl;
}
}
Mat_与Mat_的转化:
由mat_的声明类型所决定,mat_必须有声明类型。有mat_或者mat去初始化自己;
有些时候还会涉及到mat的通道转化,3通道转化为1通道。这种转化不能够随便去等于,合理的方法是用逐值复制的方法。声明一个一维的矩阵,然后逐值复制这样子是合理的 ,opencv的内部应该也是这样实现的。
这些天有点忙,写的比较乱!