精华内容
下载资源
问答
  • OPENCV_Mat类存取方法

    2016-05-13 17:27:23
    OPENCV_Mat类存取方法
  • opencv Mat常用操作

    千次阅读 2016-08-04 21:34:19
    二、其他数据结构 Point2f P(5,1); Point3f P3f(2,6,7); vectorv;v.push_back((float)CV_PI);v.push_back(2);v.push_back(3.01f);//不断入 vector vPoints(20);//一次定义20个 三、常用方法 ...

    除了api reference之外,opencv 自带的cheatsheet也是很好的查找资料。

    原博客地址:http://blog.sina.com.cn/s/blog_afe2af380101bqhz.html

    一、矩阵MatI,img,I1,I2,dst,A,B;

    double k,alpha;
    Scalar s;
    1.加法
    I=I1+I2;//等同add(I1,I2,I);
    add(I1,I2,dst,mask,dtype);
    scaleAdd(I1,scale,I2,dst);//dst=scale*I1+I2;
    2.减法
    absdiff(I1,I2,I);//I=|I1-I2|;
    A-B;A-s;s-A;-A;
    subtract(I1,I2,dst);
    3.乘法
    I=I.mul(I);//点乘,I.mul(I,3);-->I=3*I.^2
    Mat C=A.mul(5/B);//==divide(A,B,C,5);
    A*B;矩阵相乘
    I=alpha*I;
    Mat::cross(Mat);//三维向量(或矩阵)的叉乘,A.cross(B)
    double Mat::dot(Mat);//2个向量(或矩阵)的点乘的结果,A.dot(B)
    mul-------multiply
    pow(src,double p,dst);//如果p是整数dst(I)=src(I)^p;其他|src(I)|^p
    4.除法
    divide(I1,I2,dst,scale,intdtype=-1);//dst=saturate_cast(I1*scale/I2);
    A/B;alpha/A;都是点除
    5.转换
    I.convertTo(I1,CV_32F);//类型转换
    A.t();//转置
    flip(I,dst,intflipCode);//flipCode=0是上下翻转,>0时左右翻转,<0时一起来
    sqrt(I,dst);
    cvtColor(I,dst,int code,int dstCn=0);
    resize:对图像进行形变
    --------------------------------------------------------------------------
    6.其他
    Scalar s=sum(I);各通道求和
    norm,countNonZero,trace,determinant,repeat都是返回Mat或者Scalar
    countNonZero:用来统计非零的向量个数.(rows*cols个)
    Scalar m=mean(I);//各通道求平均
    Mat RowClone=C.row(1).clone();//复制第2行
    addWeight(I1,alpha,I2,beta,gamma,dst,intdtype=-1);//dst=saturate(alpha*I1+beta*I2+gamma);dtype是dst的深度
    ----------------------------------------------------------------------------
    7.运算符
    log10()
    exp(I,dst);//dst=exp(I);计算每个数组元素的指数
    log(I,dst);//如果Iij!=0;则dstij=log(|Iij|)
    randu(I,Scalar::all(0),Scalar::all(255));
    Mat::t()转置
    Mat::inv(intmethod=DECOMP_LU)求逆。method=DECOMP_CHOLESKY(专门用于对称,速度是LU的2倍),DECOMP_SVD//A.inv();A.inv()*B;
    invert(I1,dst,int method=DECOMP_LU);//用法同上
    MatExpr abs(Mat)//求绝对值
    A cmpop B;A compop alpha;alpha cmpopA;这里cmpop表示>,>=,==,!=,<=,<等,结果是CV_8UC1的mask的0或255
    按位运算:A logicop B;A logicop s;s logicopA;~A;这里logicop代表&,|,^
    bitwise_not(I,dst,mask);//inverts所有的队列
    还有bitwise_and,bitwise_or,bitwise_xor,
    min(A,B);min(A,alpha);max(A,B);max(A,alpha);都返回MatExpr,返回的dst和A的类型一样
    double determinant(Mat);//行列式
    bool eigen(I1,dst,int lowindex=-1,int highindex=-1);//
    bool eigen(I1,dst,I,int...);//得到特征值向量dst和对应特征值的特征向量
    minMaxLoc(I1,&minVal,&maxVal,Point *minLoc=0,Point*MaxLoc=0,mask);
    //minLoc是2D时距原点最小的点(未考证)
    ------------------------------------------------------------------------------
    8.初始化
    MatI(img,Rect(10,10,100,100));//用一块地方初始化。
    Mat I=img(Range:all(),Range(1,3));//所有行,1~3列
    Mat I=img.clone();//完全复制
    img.copyTo(I);//传递矩阵头
    MatI(2,2,CV_8UC3,Scalar(0,0,255));//I=[0,0,255,0,0,255;0,0,255,0,0,255];
    Mat E=Mat::eye(4,4,CV_64F);//对角矩阵
    Mat O=Mat::ones(2,2,CV_32F);//全一矩阵
    Mat Z=Mat::zeros(3,3,CV_8UC1);//全零矩阵
    Mat C=(Mat_(2,2)<<0,-1,2,3);//如果是简单矩阵的初始化
    Mat::row(i);Mat::row(j);Mat::rowRange(start,end);Mat::colRange(start,end);都只是创建个头
    Mat::diag(int d);d=0是是主对角线,d=1是比主低的对角线,d=-1....
    static Mat Mat::diag(const Mat& matD)
    Mat::setTo(Scalar &s);以s初始化矩阵
    Mat::push_back(Mat);在原来的Mat的最后一行后再加几行
    Mat::pop_back(size_t nelems=1);//移出最下面几行
    -------------------------------------------------------------------------------
    9.矩阵读取和修改
    (1)1个通道:
    for(int i=0;i
    for(int j=0;j
    I.at(i,j)=k;
    (2)3个通道:
    Mat_ _I=I;//他没有4个通道寸,只有3个通道!
    for(int i=0;i
    for(int j=0;j
    {
    _I(i,j)[0]=b;
    _I(i,j)[1]=g;
    _I(i,j)[2]=r;
    }
    I=_I;
    ------------------------------------------------------------
    或者直接用I.at(i,j)[0]....
    -------------------------------------------------
    float *s;
    for(i=0;i
    {s=proImg.ptr(i);
    for(j=0;j
    {a1=s[3*j+1]-m1;
    a2=s[3*j+2]-m2;}}
    -------------------------------------------------------------------------
    (3)其他机制
    I.rows(0).setTo(Scalar(0));//把第一行清零
    saturate_cast(...);//可以确保内容为0~255的整数
    Mat::total();返回一共的元素数量
    size_tMat::elemSize();返回元素的大小:CV_16SC3-->3*sizeof(short)-->6
    size_tMat::elemSize1();返回元素一个通道的大小CV_16SC3-->sizeof(short)-->2
    int Mat::type()返回他的类型CV_16SC3之类
    int Mat::depth()返回深度:CV_16SC3-->CV_16S
    int Mat::channels()返回通道数
    size_t Mat:step1()返回一个被elemSize1()除以过的step
    Size Mat::size()返回Size(cols,rows);如果大于2维,则返回(-1,-1),都是先宽再高的
    bool Mat::empty()如果没有元素返回1,即Mat::total()==0或者Mat::data==NULL
    uchar *Mat::ptr(int i=0)指向第i行
    Mat::at(int i)(int i,int j)(Point pt)(int i,int j,int k)
    RNG随机类:next,float RNG::uniform(float a,float b);..
    double RNG::gaussian(double sigma);
    RNG::fill(I,int distType,Mat low,Mat up);//用随机数填充
    randu(I,low,high);
    randn(I,Mat mean,Mat stddev);
    reduce(I,dst,int dim,int reduceOp,intdtype=-1);//可以统计每行或每列的最大、最小、平均值、和
    setIdentity(dst,Scalar &value=Scalar(1));//把对角线替换为value
    //效果等同:Mat A=Mat::eye(4,3,CV_32F)*5;
    --------------------------------------------------------------
    10.较复杂运算
    gemm(I1,I2,alpha,I3,beta,dst,intflags=0);//I1至少是浮点型,I2同I1,flags用来转置
    //gemm(I1,I2,alpha,I3,beta,dst,GEMM_1_T,GEMM_3_T);-->dst=alpha*I1.t()*I2+beta*I3.t();可用此完全代替此函数
    mulTransposed(I,dst,bool aTa,Mat delta=noArray(),double scale=1,intrtype=-1);
    //I是1通道的,和gemm不同,他可用于任何类型。
    //如果aTa=flase时,dst=scale*(I-delta).t()*(I-delta);
    //如果是true,dst=scale*(I-delta)(I-delta).t();
    calcCovarMatrix(Mat,int,Mat,Mat,int,int=);calcCovarMatrix(Mat I,Matcovar,Mat mean,int flags,int=);
    cartToPolar//转到极坐标
    compare(I1,I2,dst,cmpop);cmpop=CMP_EQ,CMP_GT,CMP_GE,CMP_LT,CMP_LE,COM_NE
    completeSymm(M,boollowerToUpper=false);当lowerToUpper=true时Mij=Mji(ij)
    变成可显示图像:convertScaleAbs(I,dst,alpha,beta);dst=saturate_cast(|alpha*I+beta|);
    dct(I,dst,intflags=0);//DCT变换,1维、2维的矩阵;flags=DCT_INVERSE,DCT_ROWS
    idct,dft,idft
    inRange(I1,I_low,I_up,dst);//dst是CV_8UC1,在2者之间就是255
    Mahalanobis(vec1,vec2,covar);
    merge(vector,Mat);//把多个Mat组合成一个和split相反
    double norm(...):当src2木有时,norm可以计算出最长向量、向量距离和、向量距离和的算术平方根
    solveCubic解3次方程,solvePoly解n次方程
    排列:sort,sortIdx
    mixChannels();对某个通道进行各种传递
    -----------------------------------------------------------------
    11.未懂的函数
    getConvertElem,extractImageCOI,LUT
    magnitude(x,y,dst);//I1,I2都是1维向量,dst=sqrt(x(I)^2+y(I)^2);
    meanStdDev,
    MulSpectrums(I1,I2,dst,flags);傅里叶
    normalize(I,dst,alpha,beta,int normType=NORM_L2,intrtype=-1,mask);//归一化
    PCA,SVD,solve,transform,transpose
    二、其他数据结构
    Point2f P(5,1);
    Point3f P3f(2,6,7);
    vectorv;v.push_back((float)CV_PI);v.push_back(2);v.push_back(3.01f);//不断入
    vector vPoints(20);//一次定义20个


    三、常用方法
    Mat mask=src<0;这样很快建立一个mask了


    四、以后可能用到的函数
    randShuffle,repeat
    展开全文
  • Opencv之Mat操作(重要)

    千次阅读 2015-05-28 09:35:54
    OpenCV2中,数据结构Mat是保存图像像素信息的矩阵,它主要包含两部分:矩阵头和一个指向像素数据的矩阵指针。 矩阵头主要包含,矩阵尺寸、存储方法、存储地址和引用次数等。 矩阵头的大小是一个常数,不会随着图像...

    1.Mat基础

    在计算机内存中,数字图像是已矩阵的形式保存的。OpenCV2中,数据结构Mat是保存图像像素信息的矩阵,它主要包含两部分:矩阵头和一个指向像素数据的矩阵指针。
    矩阵头主要包含,矩阵尺寸、存储方法、存储地址和引用次数等。
    矩阵头的大小是一个常数,不会随着图像的大小而改变,但是保存图像像素数据的矩阵则会随着图像的大小而改变,通常数据量会很大,比矩阵头大几个数量级。这样,在图像复制和传递过程中,主要的开销是由存放图像像素的矩阵而引起的。因此,OpenCV使用了引用次数,当进行图像复制和传递时,不再复制整个Mat数据,而只是复制矩阵头和指向像素矩阵的指针。例如:
    1
    2
    3
    cv::Mat a ; //创建矩阵头
    a = cv::imread( "f:\\psb.jpg" ); //读入图像
    cv::Mat b = a ; //复制 
    上面的a,b有各自的矩阵头,但是其矩阵指针指向同一个矩阵,也就是其中任何一个改变了矩阵数据都会影响另外一个。
    那么,多个Mat共用一个矩阵数据,最后谁来释放矩阵数据呢?
    这就是引用计数的作用,当Mat对象每被复制一次时,就会将引用计数加1,而每销毁一个Mat对象(共用同一个矩阵数据)时引用计数会被减1,当引用计数为0时,矩阵数据会被清理。
     
    上图是Mat对象a,b共用一个矩阵,故其引用计数refcount为2.
    但是有些时候仍然会需要复制矩阵数据本身(不只是矩阵头和矩阵指针),这时候可以使用clone 和copyTo方法。
    cv::Mat c = a.clone();
    cv::Mat d ;
    a.copyTo(d);
    上面代码中的c,d各自拥有自己的矩阵,改变自己的矩阵数据不会相互影响。
    在使用Mat中,需要记住:
    1. OpenCV中的内存分配是自动完成的(不是特别指定的话)
    2. 使用OpenCV的C++ 接口时不需要考虑内存释放问题
    3. Mat的赋值运算和拷贝构造函数只会拷贝矩阵头,仍然共同同一个矩阵
    4. 如果要复制矩阵数据,可以使用clone和copyTo函数

    2.Mat存储方法

    Mat中矩阵的每个元素可以使用不同的数据类型,最小的数据类型是char,占用一个字节或者8位,可以是有符号的(0到255)或者是无符号的(-127到127)。在RGB颜色空间中,使用三个char类型可以表示1600万中颜色,但在图像处理的过程中有可能会使用到float或者double来表示图像的像素。

    Mat的创建

    构造函数
    cv::Mat img(2,2,CV_8UC3,cv::Scalar(0,0,255));
    上述代码创建了一个2行2列的矩阵,矩阵元素使用8位无符号char类型保存,具有3通道,每个像素的初始值是(0,0,255)
    构造函数的前两个参数指定了矩阵的行和列
    第三个参数指定矩阵元素的数据类型以及通道数,其指定规则如下:
    CV_[The number of bits per item][Signed or Unsigned][TypePrefix]C[The channel number]
    四部分分别指定:元素的大小,是有符号还是无符号,数据类型以及通道数
    最后一个参数,Scalar是short型的vector,提供矩阵的初始化。
    Create方法
    该方法不能为矩阵设置初始值,只是在改变尺寸时为矩阵数据重新分配内存。使用方法:
    img.create(4,4,CV_8UC(2));
    创建了一个4行4列有2个通道的矩阵
    MATLAB形式的初始化
    cv::Mat e = cv::Mat::eye(4,4,CV_64F);
    cv::Mat z = cv::Mat::ones(2,2,CV_32F);
    cv::Mat o = cv::Mat::zeros(3,3,CV_8UC1);
    Mat e是4行4列的对角矩阵
    Mat z是2行2列的单位矩阵
    Mat o是3行3列的零矩阵
    小矩阵的初始化
    对于小矩阵可以使用逗号分割的初始化函数
    Mat c =(Mat_<double>(3,3)<<1,2,3,0,-1,0,4,5,6);
    在对图像进行模板运算时,定义模板使用这种方法是很方便的。

    3.Mat的输入输出

    使用imread函数,向Mat对象中写入一个图像。
    a = cv::imread("f:\\psb.jpg");//读入图像
    imread的原型如下
    cv::Mat imread(const string& filename,int flags=1)
    filename指定要读取图像的位置
    flags指定图像的颜色空间  
        flags > 0 3通道的彩色图像
         flags = 0 灰度图像
        flags < 0 不作改变
    也可以有以下的枚举值
    CV_LOAD_IMAGE_ANYDEPTH、 CV_LOAD_IMAGE_COLOR、 CV_LOAD_IMAGE_GRAYSCALE
     
    使用imwrite函数,将Mat对象保存到指定的文件中。
    imwrite的函数原型如下:
    bool imwrite(const string& filename,InputArray img,constvector<int>& params=vector<int>())
    filename,指定的文件
    img  要保存的Mat对象
    params 用来指定图像的保存编码方式。
    使用filename的扩展名来指定图像的保存格式(.jpg  .png  .bmp),对于不同的图像保存类型,params是不同的值
    • JPEG,params用来指定图像的质量(0到100),默认的是95.  CV_IMWRITE_JPEG_QUALITY
    • PNG,params用来指定图像的压缩级别(0到9),压缩级别越高图像占用的空间越小,保存图像所用的时间越久。默认值是3. CV_IMWRITE_PNG_COMPRESSION
    • PPM,PGM,PBM,params是一个标记(0或者1),默认的是1.CV_IMWRITE_PXM_BINARY
    imwrite只能保存8位( 或者是16位无符号(CV_16UC)的PNG,JPEG200或者TIFF图像) 单通道或者三通道的图像, 如果要保存的不是这样的图片,可以使用convertTo或者cvtColor来进行转变。
    下面代码展示了如果使用imwrite向文件中写入一个4通道的png图像
    复制代码
    void createAlphaMat(Mat &mat) 
    {
        for(int i = 0 ; i < mat.rows ; i ++) {
            for(int j = 0 ; j < mat.cols ; j ++) {
                Vec4b &rgba = mat.at<Vec4b>(i,j);
                rgba[0] = UCHAR_MAX ;
                rgba[1] = saturate_cast<uchar>((float (mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX);
                rgba[2] = saturate_cast<uchar>((float (mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX);
                rgba[3] = saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2]));
            }
        }
    }
    int main()
    {
        Mat mat(480,640,CV_8UC4);
        createAlphaMat(mat);
    
        vector<int> compression_params ;
        compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
        compression_params.push_back(9);
    
        imwrite("alpha.png",mat,compression_params);
    
        return 0;
    }
    复制代码

     

    4.Mat的显示

    OpenCV提供了用以窗口的形式显示图片的方法,代码如下:
    Mat img = imread("f:\psb.jpg");
    const string name ="Hu";
    namedWindow(name);
    imshow(name,img);
    waitKey();
     

    OpenCV2:Mat属性type,depth,step

    在OpenCV2中Mat类无疑使占据着核心地位的,前段时间初学OpenCV2时对Mat类有了个初步的了解,见OpenCV2:Mat初学。这几天试着用OpenCV2实现了图像缩小的两种算法:基于等间隔采样和基于局部均值的图像缩小,发现对Mat中的数据布局和一些属性的认知还是懵懵懂懂,本文对Mat的一些重要属性和数据布局做一个总结。

     

    Mat的作用

    The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms (though, very high-dimensional histograms may be better stored in a SparseMat ).

    上面的一段话引用自官方的文档,Mat类用于表示一个多维的单通道或者多通道的稠密数组。能够用来保存实数或复数的向量、矩阵,灰度或彩色图像,立体元素,点云,张量以及直方图(高维的直方图使用SparseMat保存比较好)。简而言之,Mat就是用来保存多维的矩阵的。

    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中元素的数据类型相关的。

    • 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的各个属性:

    复制代码
    Mat img(3, 4, CV_16UC4, Scalar_<uchar>(1, 2, 3, 4));
        
        cout << img << endl;
    
        cout << "dims:" << img.dims << endl;
        cout << "rows:" << img.rows << endl;
        cout << "cols:" << img.cols << endl;
        cout << "channels:" << img.channels() << endl;
        cout << "type:" << img.type() << endl;
        cout << "depth:" << img.depth() << endl;
        cout << "elemSize:" << img.elemSize() << endl;
        cout << "elemSize1:" << img.elemSize1() << endl;
    复制代码

    首先创建了一个3*4的具有4个通道的矩阵,其元素类型是CV_16U。Scalar_是一个模板向量,用来初始化矩阵的每个像素,因为矩阵具有4个通道,Scalar_有四个值。其运行结果: 
    image运行结果首先打印了Mat中的矩阵,接着是Mat的各个属性。注意其type = 26,而depth = 2。这是由于上面所说的各种预定义类型 
    例如,CV_16UC4,CV_8U是一些预定义的常量。

    step

    Mat中的step是一个MStep的一个实例。其声明如下:

    复制代码
    struct CV_EXPORTS MStep
        {
            MStep();
            MStep(size_t s);
            const size_t& operator[](int i) const;
            size_t& operator[](int i);
            operator size_t() const;
            MStep& operator = (size_t s);
    
            size_t* p;
            size_t buf[2];
        protected:
            MStep& operator = (const MStep&);
        };
    复制代码

    从其声明中可以看出,MStep和size_t有比较深的关系。用size_t作为参数的构造函数和重载的赋值运算符

    MStep(size_t s);
    MStep& operator = (size_t s);

    向size_t的类型转换以及重载的[ ]运算符返回size_t

    const size_t& operator[](int i) const;
            
    size_t& operator[](int i);

    size_t的数组以及指针 

    size_t* p;
            
    size_t buf[2];

    那么size_t又是什么呢,看代码

    typedef  unsigned int   size_t;

    size_t就是无符号整数。

    再看一下MStep的构造函数,就可以知道其究竟保存的是什么了。

    inline Mat::MStep::MStep(size_t s) { p = buf; p[0] = s; p[1] = 0; }

    从MStep的定义可以知道,buff是一个size_t[2],而p是size_t *,也就是可以把MStep看做一个size_t[2]。那么step中保存的这个size_t[2]和Mat中的数据有何种关系呢。

    step[0]是矩阵中一行元素的字节数。

    step[1]是矩阵中一个元素的自己数,也就是和上面所说的elemSize相等。

    上面说到,Mat中一个uchar* data指向矩阵数据的首地址,而现在又知道了每一行和每一个元素的数据大小,就可以快速的访问Mat中的任意元素了。下面公式:

    addr(M_{i,j}) = M.data + M.step[0]*i + M.step[1]*j

    step1

    规整化的step,值为step / elemSize1。 定义如下:

    inline size_t Mat::step1(int i) const { return step.p[i]/elemSize1(); }

    仍以上例代码中定义的img为例,来看下step,step1具体的值: 
    imageimg(3*4)的type是CV_16UC4,step[0]是其一行所占的数据字节数4 *4 * 16 / 8  = 32. 
    step[1] 是一个元素所占的字节数,img的一个元素具有4个通道,故:4 * 16 / 8 = 2 
    step1 = step / elemSize1,elemSize1是元素的每个通道所占的字节数。

    N维的step(N > 2)

    上面分析step是一个size_t[2],实际不是很正确,正确的来说step应该是size_t[dims],dims是Mat的维度,所以对于上面的二维的Mat来说,step是size_t[2]也是正确的。 
    下面就对三维的Mat数据布局以及step(维度大于3的就算了吧)。

    上图引用自http://ggicci.blog.163.com/blog/static/210364096201261052543349/  搜集资料时发现了这幅图,一切就变的简单了 眨眼  感谢作者 Ggicci

    三维的数据在Mat中是按面来存储的,上图描述的很清晰,这里不再多说。 
    上面言道,step是一个size_t[dims],dims是维度。so,三维的step就是size_t[3]。其余的不多说了,看图就有了。下面来创建一个三维的Mat,实际看看

    复制代码
    int dims[3] = { 3, 3, 3 };
        Mat src(3, dims, CV_16SC2, Scalar_<short>(1,2));
    
        cout << "step[0]:" << src.step[0] << endl;
        cout << "step[1]:" << src.step[1] << endl;
        cout << "step[2]:" << src.step[2] << endl;
    复制代码

    首先创建一个3*3*3,depth为CV_16S的两通道的Mat 
    step[0]是一个数据面的大小  3 * 3 * (16 / 8 ) * 2 = 36 
    step[1]是一行数据的大小 3 * (16 / 8 ) * 2 = 12 
    step[2]是一个元素的大小 2 * (16 / 8) = 4 
    image 
    PS: 三维的Mat 不能使用 <<运算符进行输出的。

    over

    转自:http://www.cnblogs.com/wangguchangqing/p/4016179.html

    展开全文
  • OpenCv2 学习笔记(1) Mat创建、复制、释放

    万次阅读 多人点赞 2016-11-13 19:45:35
    建议安装好之后,用VS2013建立一个空工程,用属性管理器分别新建一个对应debug和release工程的props配置文件,以后直接根据工程需要添加对应配置文件,而不需要每次新建工程后填写引用目录、目录、附加依赖项,...

    opencv和VS2013的安装图文教程网上有很多,建议安装好之后,用VS2013建立一个空工程,用属性管理器分别新建一个对应debug和release工程的props配置文件,以后直接根据工程需要添加对应配置文件,而不需要每次新建工程后填写引用目录、库目录、附加依赖项,减少重复工作。

    用WLW编辑,段间距有点大!需要说明的是,本学习笔记不会按照先讲数据结构,再讲如何使用。与OpenCv1.x不用中,opencv2.x及3.x中用Mat代替了CvMat和IplImage。因此,对Mat的使用,会从一些例子给出一个直观的感受,之后再根据一些例子遇到新的东西就进行详细的讲解,遵循学习中遇到问题解决问题的方式。

    为了使得Mat的输出更美观,自己写了一个Mat的输出;首先创建工程,cpp文件的主程序如下:

    #include <opencv2/opencv.hpp>
    #include <iostream>
    
    using namespace cv;
    using namespace std;  
    
    
    void coutMat(const char *str, InputArray &_m) // _m可以是各种矩阵形式,包括vec、vector和表达式等。
    
    {   //通过getMat()获取不同输入格式的Mat的数据,浅复制
        cout << str << endl << " " << _m.getMat() << endl << endl; 
    }
    
    void main()
    {
        //编辑代码
        waitKet(); //(调用imshow函数后有效)避免命令行窗口一闪而过,可以借用 getchar() 或者 system("pause")等输入命令
    }
    1、Mat的创建、复制
    /*
    * Create Mat
    */
    Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));   // 构造函数的一种
    cout << "M=" << endl << " " << M << endl << endl;
    
    Mat A;
    M.copyTo(A);
    
    M.release();
    cout << A << endl;        // 释放不影响
    
     Mat B;
    B = M.clone();
    
     M.release();
    cout << "B=" << endl << " " << B << endl<<endl;    

    Mat的一个构造函数 C++: Mat::Mat(int rows, int cols, int type, const Scalar& s) ,其中rows和cols是需要创建的矩阵的行数和列数,type是Mat的数据类型,s是Scalar类型的矩阵初值。

    对于type,是基本数据类型,首先有枚举 enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }; 分别对应,8位无符号(uchar)、8位有符号(char)、16位无符号(ushort)、16位有符号(short)、32位有符号(int)、32位浮点(float)和64位双精度(double);其次 CV_8UC1、CV_16FC2、.. CV_64FC4等是多通道的类型,可以用CV_(深度)(类型)(通道数)描述, 例如本例中CV_8UC3,是指8位无符号3通道,其他类推。

    对于s的Scalar类型,它的源头实际是一个4行1列的Mat,这里的Scalar(0,0,255),直接可以理解成M矩阵的每一个元素都是(0,0,255),当M看成图像,就是一个2x2的红色方块,Scalar有3个值,可以对应RGB色彩,通道顺序为(B,G,R)。那么,CV_8UC2,可以用Scalar(1,2)赋值,CV_64UC4可以用Scalar(0,0.1,0.08,100.1)赋值,其他类推。

    Mat类的两个拷贝函数,copyTo()和clone(),都是进行深复制,也就是会另外开辟一个内存存储被复制的数据区域,对复制得到的新矩阵进行释放releas()不会影响原矩阵的数据(有其他方式会影响,后面遇到再讲)。这里的copyTo()和clone()区别在于,copyTo()可选一个参数掩膜mask,根据mask的值选择复制区域。

    上面例子的结果如下:

    image

    2、Mat的释放

    Mat mat1 = Mat::ones(1, 5, CV_32F);
    Mat mat2 = mat1;                        // 仅创建一个mat2信息头, mat1,mat2 数据区的地址相同
    Mat mat3 = Mat::zeros(1, 4, CV_32F);
    
    mat2.release();          //  因为mat2是对mat1的引用,这里的mat2.release()只会清除mat2的信息头和数据指针
    mat1.release();         //  mat1的数据区都会被释放,但是mat信息头数据还会保存(也就是还能继续被赋值)
    
    cout << mat1 << endl;
    cout << mat2 << endl;
    cout << mat3 << endl << endl;
    
    mat3.copyTo(mat1);// 拷贝会给mat1从新分配数据区域,其原来的数据区还会保留,即mat2的数据是原来mat1的数据,
    //mat1 = mat3.clone();  // 最终结果是mat1和mat3的数据相同,但是数据存储空间不同,  mat2存储的是mat1最初的值
    mat3.release();        // mat3的释放不会影响mat1
    
    cout << mat1 << endl;
    cout << mat2 << endl;
    cout << mat3 << endl << endl;

    有关注释读起来比较拗口,上面的例子最好调试下。总之,对于Mat的引用(也就是浅复制,只分配信息头,数据区共享)情况下的释放,只会清除本身的信息头和置零数据区指针,不会影响被赋值的矩阵。Mat有一个引用机制,有一个成员变量refcount,会自己根据被引用和释放的次数,自动管理内存,所以一般不需要用户自己去释放。对于创建类型的构造函数(深复制),那么会有属于自己的数据区,完全和被赋值的矩阵可以独立开

    3、Mat的复制和释放

    Mat A = (Mat_<uchar>(5, 2) << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); //A为5x2的uchar类型矩阵,并被赋初值1-10
    Mat B = A;        // B引用A,浅复制(仅创建信息头,数据指针指向A的数据区,没有数据的复制)
    Mat C = B.row(3);   // 同样是引用,C指向B的4行
    Mat D = B.clone();  // D是深复制B,实际是A的深复制。
    B.row(4).copyTo(C); // B、C都是引用A,这里相当于是把A的第4行“7,8”两个数换成了第5行“9,10”
    A = D;      //D是从B也就是A深度复制,这里A引用了D
    B.release();// B是引用,浅复制,这里释放的B的信息头并将其将数据指针置为0
    C = C.clone();    // 因为C是浅复制,进过clone()深度之,开辟了内存并完全复制了数据,是完全独立于A的。

    这一个例子,可以更加深入的了解Mat的复制和释放机制,调试的时候可以看下各矩阵的refcount变量。下面的一个例子,copyTo()函数有第二个参数mask情况,代码和结果如下: 

    Mat A = (Mat_<uchar>(5, 2) << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Mat mask = (Mat_<uchar>(5, 2) << 0, 0, 1, 1, 0, 0, 0, 0, 1, 1); 
    
    Mat C,D;
    A.copyTo(C);      // 第二个参数为空,等效于A.copyTo(C,Mat());  
    A.copyTo(D, mask);//mask必须和被复制矩阵大小相同 
    
    coutMat("C = ", C);    //和C一样
    coutMat("D = ", D); //D和C大小一样,但是只复制了第2、5行的数据,其他为0
    4、其他

    对于数学计算还有一些基本的构造函数,如Mat::eye()对角阵(当行、列不同时,主对角线为1)、Mat::ones()单位阵、Mat::zeros()零矩阵等。

    用一个矩阵的一行复制到另外一行,不能通过直接复制,必须通过运算才行(运算的结果会返回一个实际的矩阵)。如矩阵mat的第1行复制到第2行,代码为 mat.row(1)=mat.row(0) 无效,但是 mat.row(1)=mat.row(0)+0; 或者 mat.row(1)=mat.row(0)+mat.row(2); 都是有效的。

    总结

    对于Mat一般只需要区什么是浅复制和深复制即可,何时需要就直接创建,释放可以交给OpenCv管理。另外没有提到的是,当Mat直接被另外一个大小不同的矩阵深幅值时,Mat会先被释放再被复制,不需要同OpenCv1.X中先释放再指定需要的size才能被再次使用。

    展开全文
  • cv::Mat内存结构的理解

    2021-05-13 08:03:11
    mat第一行内部的数据不会互相影响,比如mat.at(0,0)和mat.at(0,1),这2个数据写入和读取不会有异常,因为空间不够,那么会排到第二行,就会影响第二行。当然,如果你非要较真,先mat.at(0, 0) = 1.0f,再mat.at(0, 1) ...

    参考资料

    个人理解

    Mat mat(3,3,CV_8U);mat第一行内部的数据不会互相影响,比如mat.at(0,0)和mat.at(0,1),这2个数据写入和读取不会有异常,因为空间不够,那么会排到第二行,就会影响第二行。

    当然,如果你非要较真,先mat.at(0, 0) = 1.0f,再mat.at(0, 1) = 1,显然第0行第1个数仍然会影响第0行第0个数。因为第二个数的类型和指定的一样啊。

    验证程序:

    #include

    #include

    using namespace std;

    using namespace cv;

    int main(int argc, char** argv)

    {

    cv::Mat mat1(3,3,CV_8U);

    mat1.at(0,0)=1.0;

    mat1.at(1,0)=2.0;

    cout<(0,0): "<(0,0)<(1,0): "<(1,0)<

    cout<

    cv::Mat mat2(3,3,CV_8U);

    mat2.at(0,0)=1.0;

    mat2.at(0,1)=2.0;

    cout<(0,0): "<(0,0)<(0,1): "<(0,1)<

    cout<

    cv::Mat mat3(3,3,CV_8U);

    mat3.at(0,0)=2.0;

    mat3.at(0,1)=1;

    cout<(0,0): "<(0,0)<(0,1): "<(0,1)<

    cout<

    cv::Mat mat4(3,3,CV_8U);

    mat4.at(0,0)=2.0;

    mat4.at(0,1)=1.235;

    cout<(0,0): "<(0,0)<(0,1): "<(0,1)<

    waitKey(0);

    return 0;

    }

    结果:

    mat1.at(0,0): 1.17549e-38,mat1.at(1,0): 2

    .........................................

    mat2.at(0,0): 1,mat2.at(0,1): 2

    .........................................

    mat3.at(0,0): 2.00006,mat3.at(0,1): �

    .........................................

    mat4.at(0,0): 2,mat4.at(0,1): 1.235

    每天都在用cv::Mat,却一直没弄清楚它的内部存储结构。特别是当我们存储不同类型、不同通道数的数据时,Mat内部到底如何组织这些数据。

    要不是今天遇到的一个特殊需求,恐怕我也不会去想这些麻烦事...

    从特殊需求看Mat内存结构

    需求是:存储long类型的数据到Mat中。

    看起来是个挺正常的需求,但Mat偏偏没有提供long对应的type。所谓的type,就是Mat中自定义的CV_8U、CV_32S、CV_64F等等常量,分别对应C++中的基本数据类型unsigned char、int、double。为什么OpenCV非要额外定义这些常量,我也不知道(可能是为了避免不同平台C++编译器导致的数据类型长度不一致?)。但既然设定了这样的规则,我们就要遵守。假使违反了这个规则,会出现什么事情呢?

    比如,如果我们创建CV_8U类型的Mat,却向里面存浮点数,像这样:

    Mat mat(3, 3, CV_8U);

    mat.at(0, 0) = 1.0f;

    float类型占用4个字节,而CV_8U类型的每个元素只拥有1字节的空间。可想而知,上面的代码虽然运行不会报错,但1.0这个浮点数会占据mat中前四个元素的空间。如果我们接下来继续对mat赋值:

    mat.at(0, 1) = 2.0f;

    2.0这个浮点数就会覆盖掉1.0的后三个字节的数据。我们把这两个元素打印出来:

    cout << "mat.at(0, 0) = " << mattt.at(0, 0) << endl;

    cout << "mat.at(0, 1) = " << mattt.at(0, 1) << endl;

    现在,奇迹发生了!!打印结果竟然是对的。

    mat.at(0, 0) = 1

    mat.at(0, 1) = 2

    这结果着实让我吃惊了一把。这意味着第二个浮点数占用的空间并没有和第一个浮点数重叠。当我百思不得其解的时候,又顺手尝试了下面的代码:

    Mat mat(3, 3, CV_8U);

    mat.at(0, 0) = 1.0f;

    mat.at(1, 0) = 2.0f;

    再把结果打印出来:

    mat.at(0, 0) = 1.17549e-38

    mat.at(1, 0) = 2

    终于,错误出现了。第二个浮点数覆盖掉了第一个浮点数的部分数据,导致第一个浮点数紊乱。为了探究出现这两种现象的原因,不妨看一眼Mat类的at方法的源码。

    template inline

    _Tp& Mat::at(int i0, int i1)

    {

    CV_DbgAssert(dims <= 2);

    CV_DbgAssert(data);

    CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]);

    CV_DbgAssert((unsigned)(i1 * DataType<_tp>::channels) < (unsigned)(size.p[1] * channels()));

    CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_tp>::value) == elemSize1());

    return ((_Tp*)(data + step.p[0] * i0))[i1];

    }

    前五行都是异常检测,不必细究。直接看最后一行,data是一个uchar类型的指针,指向Mat数据块的首地址。step.p[0]是矩阵第0维的长度,也就是矩阵每一行所占用的字节数。于是data + step.p[0] * i0得到的是第i0行(行号从0开始)的首地址。请注意,该计算结果与数据类型_Tp无关。接着,将该地址强制转换为_Tp*,然后将其作为一个_Tp类型的数组,按照下标索引元素。由此可以得出结论,用at获取元素的方法,每行的第0个元素的地址固定不动,后面的元素按照指定数据类型所占用的空间,依次排开。由于Mat内部存储空间是连续的,所以第一行的数据依次排开就会影响到第二行。但第一行内部的数据却不会互相影响。当然,如果你非要较真,先mat.at(0, 0) = 1.0f,再mat.at(0, 1) = 1,显然第0行第1个数仍然会影响第0行第0个数。

    Mat的使用经验

    好了,现在我们可以总结一下使用Mat的一些经验。

    1. 尽量按照与type对应的数据类型存取数据。

    如果你不清楚数据类型对应的type是什么,以float为例,可以用DataType::type来获取。

    2. Mat要求在存取数据时指定数据类型。

    无论是使用at方法,还是ptr方法,都需要指定读取的数据类型。有时候你可能纳闷,明明我创建Mat的时候已经指定过数据类型,为什么读取的时候还要再指定一次。个人认为,这可能是OpenCV的一个设计缺陷,但也可能是为了提高灵活性而故意为之。我们回到文章最初的那个问题,如何在Mat中存储long类型的数据?

    3. 在Mat中存储long类型的数据

    现在,我们来试试灵活地使用Mat。既然创建Mat时声明的类型与读取时的类型可以不一致,那么我们完全可以创建一个double类型的Mat,然后用long类型来读取它。double和long的长度都是8字节(在64位计算机上),所以不用考虑数据覆盖的问题。

    Mat mat(3, 3, CV_64F);

    mat.at(0, 0) = 999999999999;

    mat.at(1, 0) = 555555;

    cout << "mat.at(0, 0) = " << mat.at(0, 0) << endl;

    cout << "mat.at(1, 0) = " << mat.at(1, 0) << endl;

    输出结果如下:

    mat.at(0, 0) = 999999999999

    mat.at(1, 0) = 555555

    4. 在Mat中存储自定义类型的数据

    我们可以把上面这种用法推广,用Mat来存储自定义类型的数据。比如,把一个长度为8个字节的结构体存储到Mat中。

    struct Person {

    int age;

    float salary;

    };

    ostream& operator<< (ostream& o, const Person& person)

    {

    return o << "{ age: " << person.age << ", salary: " << person.salary << " }";

    }

    int main(int argc, char **argv)

    {

    Mat mat(3, 3, CV_64F);

    mat.at(0 ,0) = Person {24, 300000.0f};

    mat.at(1, 0) = Person {30, 1000000.0f};

    cout << "mat.at(0, 0) = " << mat.at(0, 0) << endl;

    cout << "mat.at(1, 0) = " << mat.at(1, 0) << endl;

    }

    输出结果如下:

    mat.at(0, 0) = { age: 24, salary: 300000 }

    mat.at(1, 0) = { age: 30, salary: 1e+06 }

    怎么样,很有趣吧。但需要注意的是,这里的自定义类型Person必须和声明的类型CV_64F具有相同的长度。

    5. 更多用法?

    Mat还有更多神奇的用法等着我们去开发。现在我能想到的,比如long或double等数据转byte array可以用Mat作为中介。再比如,我们常常用boost或protobuf对数据序列化,很麻烦,特别是protobuf,还需要定义.proto原型文件。如果只是序列化基本数据类型或大小不超过8字节的自定义类型,我们可以用Mat保存这些数据,然后用imwrite将数据写入到图片即可。当然,熟悉OpenCV的同学可能知道imwrite只支持CV_8U类型的数据,但这难不倒我们。只要设计好容量,放心往里面存就行了。大家可以自己试试如何实现这个功能。

    最后温馨提示,如果读不懂Mat::at方法的源码的同学,建议先看文末的参考资料,再回来重读就可以了。

    参考资料

    展开全文
  • Java程序内存分析:使用mat工具分析内存占用 国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国内...
  • 从.mat文件中删除变量

    2021-04-24 14:35:20
    考虑将数据拆分并将每个变量保存到不同的MAT文件中,必要时使用组织目录。即使您有一个方便的函数来从MAT文件中删除变量,它也将是低效的。MAT文件中的变量是连续分层的,因此替换一个变量可能需要读取和写入其余的大...
  • OpenCV中Mat总结

    2020-12-23 13:26:10
    一、数字图像存储概述数字图像存储时,我们存储...2、从OpenCV2开始,开始使用Mat类存储图像,具有以下优势:(1)图像的内存分配和释放由Mat类自动管理(2)Mat类由两部分数据组成:矩阵头(包含矩阵尺寸、存储方法、存...
  • opencv MAT数据操作

    2016-01-14 14:48:00
    我这里测试了三种操作Mat数据的办法,套用流行词,普通青年,文艺青年,为啥第三种我不叫2b青年,大家慢慢往后看咯。 普通青年的操作的办法通常是M.at(i, j) 文艺青年一般会走路线M.ptr( i )[ j ] 暴力青年...
  • 原创 OpenCv2 学习笔记(1) Mat创建、复制、释放 ...
  • 1内存泄漏的排查方法Dalvik Debug Monitor Server (DDMS)是ADT插件的一部分,其中有两项功能可用于内存检查:·heap查看堆的分配情况·allocation ...Eclipse Memory Analysis Tools (MAT)是一个分析Java堆数据的专业...
  • OpenCV Mat基本操作总结

    千次阅读 2017-08-16 15:53:48
    (1)参与点乘的两个Mat矩阵的数据类型(type)只能是 CV_32F、 CV_64FC1、 CV_32FC2、 CV_64FC2 这4种类 型中的一种。若选用其他类型,比如CV_8UC1,编译器会报错。 如下列子会报错 #include #include #include...
  • C++ Opencv中Mat的操作

    2021-03-10 11:16:40
    Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。OpenCV使用引用计数机制。其思路是让...
  • 然而,MATLAB中的mat数据我们无法直接读取到OpenCV工程中去,OpenCV只能读取xml型的数据,所以我们呢需要将mat数据转换为xml型数据。假如你有一个data.mat(11行,2列)数据,要把其转换为data.xml文件 具体步骤...
  • xlswrite('a.xlsx',x,'A1:Z100')b=xlsread('a.xlsx')a=magic(5)xlswrite('a.xlsx',a)给你这个例子看看吧,能够解决你的问题使用了写入空格的方法进行清空如何将excel表格中大量数据导入matlab中并作图...
  • CHAN(2) TYPE C, "分销渠道 WHSE_NO(3) TYPE C, "仓库号 STGE_TYPE(3) TYPE C, "仓储类型 *&---------------------------------------------------------------------* *& 基本数据 *&-------------------...
  • 在opencv中,mat是一个多维的密集数据数组。可以用来处理向量和矩阵、图像、直方图等等常见的多维数据mat有3个重要的方法:1、mat mat = imread(const string* filename); 读取图像2、imshow(const string ...
  • Mat矩阵操作,C++

    千次阅读 2019-06-20 11:44:28
    本文章转自... 一、矩阵 Mat I,img,I1,I2,dst,A,B; double k,alpha; Scalar s; 1.加法 I=I1+I2;//等同add(I1,I2,I); add(I1,I2,dst,mask,dtype); scaleAdd(I1,scale,I2,d...
  • opencv删除Mat矩阵某些行或列

    千次阅读 2019-03-18 11:15:32
    在矩阵底部加数据Mat message=Mat::eye(3,2,CV_8UC1); Mat dst; int a=1; //需要删除的行 注意:需要删除的行要在message的范围内 for(int i=0;i&amp;lt;message3.rows;i++) { if(i!...
  • #include <opencv2/opencv.hpp> #include <iostream>... Mat scr = imread("C:/Users/dell/Desktop/图片变化/1024_699_3.jpg"); //此为你电脑上图片的路径 //窗口命名 namedWindow("林允
  • 首先,发现线上某分析应用出现异常,连续好几天,一直没有分析数据产出。故登陆到线上查看error.log日志,发现: 明显是 YCYX-Task 这个线程出现了内存溢出,导致程序假死。 同时查看当前应用内存占用已达到4G: 二...
  • Mat类是OpenCV中使用最频繁的类之一,用于储存矩阵数据及相关操作,也是程序中图像的主要形式。 Mat类主要由两部分组成:一个描述头(matrix header)及一个指向矩阵数据的指针。其中,描述头包含了矩阵的一些基本信息...
  • Opencv Mat类成员函数详解

    万次阅读 2018-04-26 16:15:24
    转载自:https://blog.csdn.net/holybin/article/details/17751063Mat::eye...C++: static MatExpr Mat::eye(int rows, int cols, inttype)C++: static MatExpr Mat::eye(Size size, int type)参数rows –的行数。...
  • 目的:在一个循环中,每一次循环结束都要清空这个vector容器以供下一次循环再利用这个vector 方法: vector<double>m1; vector<double>m2; m1.swap(m2); 这样就把m1中的元素转移到了m2中,下面我们来看一下结果...
  • cv::Mat 有两种拷贝方式,深拷贝和浅拷贝。直接a=b是浅拷贝,靠.clone()和copyTo()实现深拷贝。 那么当我们push_back(cv::Mat)时,是
  • MAT的其他像素操作

    2019-06-20 17:59:49
    OpenCV除了支持图像的算术操作意外,还支持图像的逻辑操作、平方、取LOG、归一化值...bitwise_not(Mat src, Mat dst) src:输入图像, dst:取反之后的图像 取反之后可以对图像进行更好的分析 与操作 bitw...
  • 三维中旋转矩阵可以用mat3或quat表示。 两者可以转换。在数学上,旋转和反射对应线代中的正交变换。每行(或每列)相互正交的矩阵且每行(或每列)模长为1,叫正交矩阵。 unigine中是右手坐标系。顺时针方向的角度...
  • Matlab中对文件内.mat文件遍历...现在要给这些mat文件打标签,依据每个mat文件中的数据的数量来打标签,因为mat文件代表不同的个体,所以所打标签的文件名存储也应该和训练数据的文件名相关联,而且还要显示出label...
  • cls:清空屏幕 session:查看当前会话信息 quit:退出arthas客户端 --- dashboard:当前进程的实时数据面板 thread:当前JVM的线程堆栈信息 jvm:查看当前JVM的信息 sysprop:查看JVM的系统属性 --- sc:查看JVM...
  • 关于Mat的类的总结

    2020-08-31 22:13:20
    Mat类和其他常用类小结Scalar 类Size类Rect类,矩形类cvtColor函数,其他看P100Mat类初始化如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,388
精华内容 1,755
关键字:

mat清空数据