• 第四章(上)


    第四章
    The cv::Mat Class: N-Dimensional Dense Arrays
    Mat n维 稠密阵列
    The cv::Mat class can be used for arrays of any number of dimensions. The data is                  mat可以作为任意维的数组。这些数据可以被认为以“光栅扫描”
    stored in the array in what can be thought of as an n-dimensional analog of “raster                   的形式进行了保存。也就是说,在一维数据中,数据是连续的。
    scan order.” This means that in a one-dimensional array, the elements are sequential.
    In  a  two-dimensional  array,  the  data  is  organized  into  rows,  and  each  row  appears       在二维数据中,数据分割成行,而且每一个行紧密排列。
    one after the other. For three-dimensional arrays, each plane is filled out row by row,               在三维数据中,每一个平面连续排列。
    and then the planes are packed one after the other.

    Each matrix contains a flags element signaling the contents of the array, a dims ele‐                   每一个矩阵包含一个flag,分别表明不同特性。dims 表明维度;rows cols表明 rows 
    ment  indicating  the  number  of  dimensions,  rows  and  cols  elements  indicating  the            columns大小,此外还包含一个指向数据保存位置的指针;还有一个ptr<>使用频率
    number  of  rows  and  columns  (these  are  not  valid  for  dims>2),  a  data  pointer  to          计数。ptr<>可以是Mat使用起来非常类似smart 的指针。
    where the array data is stored, and a refcount reference counter analogous to the ref‐
    erence counter used by cv::Ptr<>. This latter member allows cv::Mat to behave very
    much like a smart pointer for the data contained in data. The memory layout in data                 Mat的内存布局很大程度上由step[]来表示。内存结构为
    is described by the array step[]. The data array is laid out such that the address of an
    element whose indices are given by (i0, ii,  … , iN) is


    对于简单的2维矩阵,也就是图片
        
     
    Mat的多种定义方法
     
    从老版本的cvmat和iplimage中转换得到mat
        

    遍历图像的4种方式(来自 cnblogs ronny)

    一、at<typename>(i,j)

    Mat类提供了一个at的方法用于取得图像上的点,它是一个模板函数,可以取到任何类型的图像上的点。下面我们通过一个图像处理中的实际来说明它的用法。

    在实际应用中,我们很多时候需要对图像降色彩,因为256*256*256实在太多了,在图像颜色聚类或彩色直方图时,我们需要用一些代表性的颜色代替丰富的色彩空间,我们的思路是将每个通道的256种颜色用64种代替,即将原来256种颜色划分64个颜色段,每个颜色段取中间的颜色值作为代表色。

    void colorReduce(Mat & image, int div){  
      for( int i = 0;i <image.rows;i ++){     
       for( int j = 0;j <image.cols;j ++){          
      image.at <Vec3b >(i,j)[ 0] =image.at <Vec3b >(i,j)[ 0] /div *div +div / 2;           
      image.at <Vec3b >(i,j)[ 1] =image.at <Vec3b >(i,j)[ 1] /div *div +div / 2;           
      image.at <Vec3b >(i,j)[ 2] =image.at <Vec3b >(i,j)[ 2] /div *div +div / 2;
            }
        }
    }

    通过上面的例子我们可以看出,at方法取图像中的点的用法:

    image.at<uchar>(i,j):取出灰度图像中i行j列的点。

    image.at<Vec3b>(i,j)[k]:取出彩色图像中i行j列第k通道的颜色点。其中uchar,Vec3b都是图像像素值的类型,不要对Vec3b这种类型感觉害怕,其实在core里它是通过typedef Vec<T,N>来定义的,N代表元素的个数,T代表类型。

    二、高效一点:用指针来遍历图像

    上面的例程中可以看到,我们实际喜欢把原图传进函数内,但是在函数内我们对原图像进行了修改,而将原图作为一个结果输出,很多时候我们需要保留原图,这样我们需要一个原图的副本。

    void colorReduce( const Mat & image,Mat & outImage, int div)
    {    // 创建与原图像等尺寸的图像    
    outImage.create(image.size(),image.type());    
    int nr =image.rows;    // 将3通道转换为1通道  
      int nl =image.cols *image.channels();   
    for( int k = 0;k <nr;k ++)
        {        // 每一行图像的指针       
      const uchar * inData =image.ptr <uchar >(k);   
         uchar * outData =outImage.ptr <uchar >(k);     
       for( int i = 0;i <nl;i ++)
            {
                outData[i] =inData[i] /div *div +div / 2;
            }
        }
    }

    从上面的例子中可以看出,取出图像中第i行数据的指针:image.ptr<uchar>(i)

    值得说明的是:程序中将三通道的数据转换为1通道,在建立在每一行数据元素之间在内存里是连续存储的,每个像素三通道像素按顺序存储。也就是一幅图像数据最开始的三个值,是最左上角的那像素的三个通道的值。

    三、更高效的方法

    上面已经提到过了,一般来说图像行与行之间往往存储是不连续的,但是有些图像可以是连续的,Mat提供了一个检测图像是否连续的函数isContinuous()。当图像连通时,我们就可以把图像完全展开,看成是一行。

    void colorReduce( const Mat & image,Mat & outImage, int div)
    {   
      int nr =image.rows;    
      int nc =image.cols;  
         outImage.create(image.size(),image.type());   
        if(image.isContinuous() &&outImage.isContinuous())
        {
            nr = 1;
            nc =nc *image.rows *image.channels();
        }    
        for( int i = 0;i <nr;i ++)
        {       
           const uchar * inData =image.ptr <uchar >(i);      
           uchar * outData =outImage.ptr <uchar >(i);     
          for( int j = 0;j <nc;j ++)
            {
                *outData ++ = *inData ++ /div *div +div / 2;
            }
        }
    }

    用指针除了用上面的方法外,还可以用指针来索引固定位置的像素:

    image.step返回图像一行像素元素的个数(包括空白元素),image.elemSize()返回一个图像像素的大小。

    &image.at<uchar>(i,j)=image.data+i*image.step+j*image.elemSize();

    四、还有吗?用迭代器来遍历。

    下面的方法可以让我们来为图像中的像素声明一个迭代器:

    MatIterator_<Vec3b> it;

    Mat_<Vec3b>::iterator it;

    如果迭代器指向一个const图像,则可以用下面的声明:

    MatConstIterator<Vec3b> it;  

    Mat_<Vec3b>::const_iterator it;

    下面我们用迭代器来简化上面的colorReduce程序:

    void colorReduce( const Mat & image,Mat & outImage, int div)
    {   
     outImage.create(image.size(),image.type());    
     MatConstIterator_ <Vec3b > it_in =image.begin <Vec3b >();  
     MatConstIterator_ <Vec3b > itend_in =image.end <Vec3b >();  
     MatIterator_ <Vec3b > it_out =outImage.begin <Vec3b >();   
     MatIterator_ <Vec3b > itend_out =outImage.end <Vec3b >();    
    while(it_in !=itend_in)
        {
            ( *it_out)[ 0] =( *it_in)[ 0] /div *div +div / 2;
            ( *it_out)[ 1] =( *it_in)[ 1] /div *div +div / 2;
            ( *it_out)[ 2] =( *it_in)[ 2] /div *div +div / 2;
            it_in ++;
            it_out ++;
        }
    }

    如果你想从第二行开始,则可以从image.begin<Vec3b>()+image.rows开始。(

    tips:在opencv中,两种生成随机数的方法

    randu(src,-1.0f,1.0f);

    rng.fill(src,RNG::UNIFORM,0.f,1.f);





  • 相关阅读:
    yum安装Mysql
    在Centos上安装xtrabackup,对Mysql做备份
    Linux下使用yum安装Mysql之后,无法登陆mysql
    手动产生replication中的系统SP
    MySQL全面瓦解1:安装部署与准备
    开发笔记:PDF生成文字和图片水印
    调试与优化:一次数据中心看板 T+1 改 T+0 优化过程
    MySQL:SELECT COUNT 小结
    系统架构设计:平滑发布和ABTesting
    linux /dev/mapper/centos-root目录莫名其妙被占满
  • 原文地址:https://www.cnblogs.com/jsxyhelu/p/16948023.html
Copyright © 2020-2023  润新知