• OpenCV Mat数据相关


           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,内容比较简单,仅供自己学习,也供有需求的人参考。
    
    以下参考自:http://www.cnblogs.com/wangguchangqing/p/4016179.html
    
    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;
       }
      }
    }

     
     
  • 相关阅读:
    寒假作业3
    寒假作业2
    寒假作业
    Binary Indexed Tree
    Quick Union
    Prim's Algorithm & Kruskal's algorithm
    面向对象阶段总结 | 肆
    面向对象阶段总结 | 叁
    面向对象阶段总结 | 贰
    面向对象阶段总结 | 壹
  • 原文地址:https://www.cnblogs.com/mathyk/p/10602871.html
Copyright © 2020-2023  润新知