OpenCV中常见的与图像操作有关的数据容器有Mat,cvMat和IplImage。这三种类型都可以代表和显示图像,区别是:Mat类型侧重于计算,数学性较高,OpenCV对Mat类型的计算进行了优化;CvMat和IplImage类型更侧重于“图像”,opencv对其中的图像操作(缩放、单通道提取、图像阈值操作等)进行了优化。在opencv2.0之前,opencv是完全用C实现的,但是,IplImage类型与CvMat类型的关系类似于面向对象中的继承关系。实际上,CvMat之上还有一个更抽象的基类----CvArr,这在源代码中会常见。

1. opencv文档中明确声明,CvMat已经过时了(CvMat is now obsolete, consider using Mat instead)不建议用;
2. 派生关系:CvArr -> CvMat -> IplImage
3. Mat用的一套东西是imread,imshow等,有别于CvArr及其子类的cvLoadImage(),cvShowImage()...

Mat类型:矩阵类型,Matrix。

     在openCV中,Mat是一个多维的密集数据数组。可以用来处理向量和矩阵、图像、直方图等等常见的多维数据。
Mat有3个重要的方法:
1、Mat mat = imread(const String* filename); 读取图像
2、imshow(const string frameName, InputArray mat); 显示图像
3、imwrite (const string& filename, InputArray img); 储存图像
Mat类型较CvMat与IplImage类型来说,有更强的矩阵运算能力,支持常见的矩阵运算。在计算密集型的应用当中,将CvMat与IplImage类型化为Mat类型将大大减少计算时间花费。

 

1.像素值的读取可使用at()函数:

uchar value = grayim.at<uchar>(i,j);  //读出第i行第j列像素值
graym.at<uchar>(i,j) = 128; //将第i行第j列像素值设置为128

 2.使用Mat的成员函数ptr<>()

uchar* data = image.ptr<uchar>(j);

 3.使用迭代器遍历图像

cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();
for (; it != itend; ++it)
{
    (*it)[0] = (*it)[0] / div*div + div / 2;
    (*it)[1] = (*it)[1] / div*div + div / 2;
    (*it)[2] = (*it)[2] / div*div + div / 2;
}

 

 4.图像的载入、显示和输出到文件。   imread、imshow、imwrite

 5.滑动条的创建和使用。

int createTrackbar(const string& trackbarname,const string& winname,int* value,int count,TrackbarCallback onChange=0,void* userdata=0);

第一个参数::轨迹名称

第二个参数:窗口名字

第三个参数:一个指向整型的指针,表示滑块位置。

第四个参数:int类型的count表示滑块可以达到的最大位置值。

第五个参数:指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调,默认值是0。

第六个参数:用户传给回调函数的数据,用来处理轨迹条事件。如果第三个参数value实参是全局变量的话,完全可以不用去管userdata参数。

 

1、Mat类常用的构造方法
Mat();//无参数构造
Mat(int rows, int cols, int type);//创建行数为rows,列数为cols,类型为type的图像
Mat(Size size, int type);//创建大小为size,类型为type的图像
Mat(int rows, int cols, int type, const Scalar& s);//创建创建行数为rows,列数为cols,类型为type的图像,且全部元素(像素)初始化为 s
Mat(Size size, int type, const Scalar& s);//创建大小为size,类型为type的图像,且全部元素(像素)初始化为 s
Mat(const Mat& m);//将m赋值给新创建的对象,是浅拷贝



#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
    //创建空矩阵
    Mat img1;
     //创建6x6的8位单通道矩阵(图像)
    Mat img2(6, 6, CV_8UC1);
     //创建7x7的8位三通道矩阵(图像)
    Mat img3(cv::Size(7, 7), CV_8UC3);
     //创建8x8的32位三通道矩阵(图像),并且用cv::Scalar(0,255)填充
    Mat img4(8, 8, CV_8UC3,cv::Scalar(0,255));
     //创建7x7的8位三通道矩阵(图像),并且用填充cv::Scalar(1, 2, 3)填充
    Mat img5(cv::Size(7, 7), CV_8UC3, cv::Scalar(1,2,3));
    Mat img6(img2);
    cout << img1 << endl;
    cout << img2 << endl;
    cout << img3 << endl;
    cout << img4 << endl;
    cout << img5 << endl;
    cout << img6 << endl;
    return 0;
}

 6.常用数据结构和函数

   1)Point类 

Point point;
point.x = 10;
point.y = 8;
Point_<int>、Point2i、Point互相等价;Point_<float>、Point2f互相等价。

2)颜色表示 Scalar类

Scalar(b,g,r);

3)尺寸:Size类 

typedef Size_<int> Size2i;
typedef Size2i Size;
Size_<int>、Size2i、Size三个类等价

4)矩形:Rect类

Rect类的成员变量 x,y,width,height,成员函数Size()返回尺寸,area()返回面积,contains(Ponit)点是否在矩形中,inside(Rect)矩形是否在该矩形内,tl()返回左上角点坐标,br()返回右下角点坐标;
Rect rect = rect1 & rect2;求交集
Rect rect = rect1 | rect2;求并集
Rect rectShift = rect + point;
Rect rectScale = rect + size;

5)颜色空间换:cvtColor()函数

     可以实现RGB颜色向HSV、HSI等颜色空间的换,也可以转换成灰度颜色。

cvtColor(srcImage,dstImage,COLOR_GRAY2BGR);

 

问题:

如果Mat 中想存小数,那么声明是就要用CV_32FC1等浮点数的类型,并且在访问像素的时候,指向每一行(i行)的指针:

不再是: uchar *data = src.ptr<uchar>(i); 了 (uchar 是0~255的无符号整数)

而是用:float *data = src.ptr<float>(i)。(以前不懂也没注意这个,程序一直出错)。

PS:因为再写颜色相关图的程序,需要保存一个掩码mark 矩阵,其中每个元素存一个【0~1】的权重,用以前的遍历图片像素的代码改的,结果总不对,后来才发现是新创建的矩阵的元素用的 uchar ,是无符号整型,不能存小数的,才恍然大悟,也才有了这篇blog,内容比较简单,仅供自己学习,也供有需求的人参考。

TYPE表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值

CV_8UC1     CV_8UC2     CV_8UC3     CV_8UC4
CV_8SC1     CV_8SC2     CV_8SC3     CV_8SC4
CV_16UC1    CV_16UC2    CV_16UC3    CV_16UC4
CV_16SC1    CV_16SC2    CV_16SC3    CV_16SC4
CV_32SC1    CV_32SC2    CV_32SC3    CV_32SC4
CV_32FC1    CV_32FC2    CV_32FC3    CV_32FC4
CV_64FC1    CV_64FC2    CV_64FC3    CV_64FC4
 
这里U(unsigned integer)表示的是无符号整数,S(signed integer)是有符号整数,F(float)是浮点数。 
例如:CV_16UC2,表示的是元素类型是一个16位的无符号整数,通道为2. 
C1,C2,C3,C4则表示通道是1,2,3,4 
type一般是在创建Mat对象时设定,如果要取得Mat的元素类型,则无需使用type,使用下面的depth
depth 
矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。depth也是一系列的预定义值, 
将type的预定义值去掉通道信息就是depth值: 
CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F
elemSize 
矩阵一个元素占用的字节数,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes
elemSize1 
矩阵元素一个通道占用的字节数,例如:type是CV_16CS3,那么elemSize1 = 16  / 8 = 2 bytes = elemSize / channels
Mat的常见属性
data     uchar型的指针。Mat类分为了两个部分:矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针。
dims     矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵dims=3.
rows     矩阵的行数
cols     矩阵的列数
size     矩阵的大小,size(cols,rows),如果矩阵的维数大于2,则是size(-1,-1)
channels 矩阵元素拥有的通道数,例如常见的彩色图像,每一个像素由RGB三部分组成,则channels = 3

 

关于将mat数据存放到xml中

void CapVideoFace()
{       
          int indexNum = 0;  //跳帧数.
    	  VideoCapture capture;
	  cv::Mat frame;
	  capture.open("resource/999.mp4");//读取视频文件 
	  //capture.open("rtsp://admin:admin123@10.129.74.198:554/cam/realmonitor?channel=1&subtype=1"); //读取rtsp流
	  if (!capture.isOpened())
          {
                LoggerN("capture open failed.");
                return;
          }
	  while (capture.read(frame)) {
	      //cv::Mat frame = imread("resource/2.jpg",1);
	      if (frame.data != NULL && indexNum++%3 ==0) {
FileStorage fs("xuchao.xml", FileStorage::WRITE);
          fs << "vocabulary" << frame;
          fs.release();
                
          FileStorage fsRead("xuchao.xml", FileStorage::READ);
          Mat mat_vocabulary;
          fsRead["vocabulary"] >> mat_vocabulary;
          fsRead.release();

indexNum == 0;
		    std::string strPic = Mat2Base64(frame, "jpg");
		    char* pBuffer = new char[3*1024*1024];
		    memcpy(pBuffer,strPic.c_str(),strPic.length());     detector[detectorIndex++].Put(pBuffer);
		    if(detectorIndex == THREADNUM)
		        detectorIndex = 0;
	       }
	  }
}