opencv-图像遍历

利用at

单通道

     cv::Mat M(5, 4, CV_8UC1);  //单通道矩阵--灰度
     int ch=M.channels();
     std::cerr<<M<<std::endl;
     int r=M.rows;
     int c=M.cols;
     qDebug()<<"行数:"<<r<<";"<<"列数:"<<c<<Qt::endl;
    for(int i=0;i<r;i++){  //i是行号
        for(int j=0;j<c;j++){  //j是列号
            int t=M.at<uchar>(i,j); //返回指点坐标的数据
            //无符号数据用uchar;float数据用float
            std::cout<<t<<";";
        }
        std::cout<<std::endl;
    }

    M.at<uchar>(3,2)=99; //修改指点坐标的值
    std::cout<<M<<std::endl;

    qDebug()<<"通道数:"<<ch<<Qt::endl;

 3通道

     cv::Mat M(5, 4, CV_8UC3);  //3通道矩阵
     int ch=M.channels();
     std::cerr<<M<<std::endl;
     int r=M.rows;
     int c=M.cols;
     qDebug()<<"行数:"<<r<<";"<<"列数:"<<c<<Qt::endl;
    for(int i=0;i<r;i++){  //i是行号
        for(int j=0;j<c;j++){  //j是列号
            int t=M.at<cv::Vec3b>(i,j)[0]; //返回指点坐标的B值
            //注意:用cv::Vec3b;i和j确定像素点;[]里确定哪个通道
            int t1=M.at<cv::Vec3b>(i,j)[1]; //返回指点坐标的G值
            int t2=M.at<cv::Vec3b>(i,j)[2]; //返回指点坐标的R值

            std::cout<<t<<","<<t1<<","<<t2<<";";
        }
        std::cout<<std::endl;
    }

    M.at<cv::Vec3b>(3,2)[1]=99; //修改指点坐标的G值
    std::cout<<M<<std::endl;

    qDebug()<<"通道数:"<<ch<<Qt::endl;

 

利用指针:优点效率高点 

     cv::Mat M(5, 4, CV_8UC3);  //3通道矩阵
int ch=M.channels();
     int nr=M.rows;
     int c=M.cols;
     int nl=c*ch;  //nl是数据列数
     //注意:M.cols是像素点列数,而每个像素点分成RGB三个数据,所以数据列数=像素点列数*通道数

     std::cerr<<M<<std::endl;

     uchar p01 = M.ptr<uchar>(0)[2];  //返回指定行指定数据列的数值
     //()里是行号,[]里是列号
     uchar* p0 = M.ptr<uchar>(0);  //返回指定行的首地址
     uchar pp01=p0[2];   //返回指针指定行的指定数据列的数值

     M.ptr<uchar>(0)[2]=99;  //修改指定行指定数据列的数值
     p0[1]=88;       //修改指针指定行的指定数据列的数值

    std::cerr<<M<<std::endl;

    qDebug()<<"通道数:"<<ch<<Qt::endl;
    qDebug()<<p01<<Qt::endl;
    qDebug()<<pp01<<Qt::endl;

 连续矩阵

一行数据肯定是连续的,但是行与行之间不一定是连续的
一般用Mat::creat()创建的矩阵都是连续的,但是也不绝对,依然需要判断才可以进行连续性操作。而从图像中截取的图像通常是不连续的,如果想将其转换为连续存储,可以用clone进行拷贝一份
m*n的数据就是需要判断连续性的。如果数据存储是连续的,可以将图像看出一个一维数组。否则只能用二维数据方式进行访问

     cv::Mat M(5, 4, CV_8UC3);
    bool b=M.isContinuous();  //判断行与行之间的储存是否连续
    
    std::cerr<<M<<std::endl;

    int nl=M.rows*M.cols*M.channels();  //连续矩阵可以看做一行;总列数=行数*像素点列数*通道
    if(b==true){
        for(int j=0;j<nl;j++){
            uchar t = M.ptr<uchar>(0)[j]; //返回指定位置的数据
            //连续矩阵看做一行,所以行号是0
            qDebug()<<t;
        }
        qDebug()<<Qt::endl;
    }
    M.ptr<uchar>(0)[1]=99;  //修改指定位置的值
    std::cerr<<M<<std::endl;

    qDebug()<<b<<Qt::endl;

利用迭代器 

     cv::Mat M(5, 4, CV_8UC3);
     std::cerr<<M<<std::endl;
     cv::Mat MM(5, 4, CV_8UC3);
     std::cerr<<MM<<std::endl;

   //非常量迭代器--通过迭代器可以修改数据
     cv::Mat_<cv::Vec3b>::iterator it1 = M.begin<cv::Vec3b>(); //图像左上角位置的迭代器--方式一

     cv::MatIterator_<cv::Vec3b> it = M.begin<cv::Vec3b>();   //图像左上角位置的迭代器--方式二
     cv::MatIterator_<cv::Vec3b> itend = M.end<cv::Vec3b>();   //图像末尾位置的迭代器

     //常量迭代器--通过迭代器不能修改数据
      cv::Mat_<cv::Vec3b>::const_iterator itt1=MM.begin<cv::Vec3b>();//方式一
      cv::MatConstIterator_<cv::Vec3b> itt = MM.begin<cv::Vec3b>();   //方式二
      cv::MatConstIterator_<cv::Vec3b> ittend=MM.end<cv::Vec3b>();



     int i=0,i1=0,i2=0;
     for (; it != itend; it++,itt++){
         i=(*it)[0]; //返回迭代器所指像素点的B值
         //*it 表示迭代器所指的像素点
         i1=(*it)[1]; //返回迭代器所指像素点的G值
         i2=(*it)[2]; //返回迭代器所指像素点的R值
         std::printf("%u,%u,%u;",i,i1,i2);
         //修改M的值;把MM的值给M
         (*it)[0]=(*itt)[0];
         (*it)[1]=(*itt)[1];
         (*it)[2]=(*itt)[2];
        }
        std::cerr<<M<<std::endl;

 块操作

行列操作

cv::Mat M(5, 4, CV_8UC3);
     std::cerr<<M<<std::endl;

     cv::Mat mRow=M.row(0);  //创建一个矩阵头(浅拷贝,数据共享),指向指定行的数据
     //mRow是1行M.cols*M.channels()列的矩阵
     cv::Mat mCol=M.col(0);  //创建一个矩阵头(浅拷贝,数据共享),指向指定像素列的数据
     //mCol是M.rows行M.channels()列的矩阵

    cv::Mat mR = M.rowRange(1,3).clone();  //参数是前闭后开;上面参数指向的是第二行和第三行的数据,不包括第四行
    //M.rowRange(1,3)    创建一个矩阵头(浅拷贝,数据共享),指向指定所有行的数据
cv::Mat mC = M.colRange(1,3); //创建一个矩阵头(浅拷贝,数据共享),指向指定所有像素列的数据 //参数是前闭后开;上面参数指向的是第二像素列和第三像素列的数据,不包括第四像素列  mRow.ptr<uchar>(0)[1]=99; std::cerr<<mRow<<std::endl; std::cerr<<M<<std::endl;

区域操作

     cv::Mat M(10, 9, CV_8UC3);
     std::cerr<<M<<std::endl;

     cv::Mat MM=M(cv::Rect(1,2,3,5));//创建一个矩阵头(浅拷贝,数据共享),指向指定区域的数据
     /*参数1:起始像素点列号--从0开始
       参数2:起始像素点行号
       参数3:总像素点列数
       参数4:总像素点行数
*/
     std::cerr<<MM<<std::endl;

     MM.at<cv::Vec3b>(3,1)[1]=99;

     std::cerr<<MM<<std::endl;
     std::cerr<<M<<std::endl;

 

 

 

 

指向对角线像素点 

     cv::Mat M(5, 4, CV_8UC3);
     std::cerr<<M<<std::endl;

     cv::Mat mD=M.diag(0);  //创建一个矩阵头(浅拷贝,数据共享),指向M对角线像素点
     //参数=0  表示主对角线

     std::cerr<<mD<<std::endl;

    mD.ptr<uchar>(0)[1]=99;

     std::cerr<<M<<std::endl;
     std::cerr<<mD<<std::endl;

 

 

     cv::Mat M(5, 4, CV_8UC3);
     std::cerr<<M<<std::endl;

     cv::Mat mD=M.diag(1);
     //参数n>0  表示对角线向右移动n像素点

     std::cerr<<mD<<std::endl;

 

 

     cv::Mat M(5, 4, CV_8UC3);
     std::cerr<<M<<std::endl;

     cv::Mat mD=M.diag(-1);
     //参数n<0  表示对角线向下移动n像素点

     std::cerr<<mD<<std::endl;

 

 

 



 

 

 

 

 

 

 

 

 

posted @ 2021-10-06 10:41  天子骄龙  阅读(130)  评论(0编辑  收藏  举报