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;