重新学习2.0以上OPENCV(基于MAT类型)2

转载 2017年01月03日 15:53:52

图像中像素点的遍历:

1.用模板函数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;
         }
     }
 }

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

更简单一些的方法:OpenCV定义了一个Mat的模板子类为Mat_,它重载了operator()让我们可以更方便的取图像上的点:
Mat_<uchar> im=Image;
im(i,j)=im(i,j)/div*div+div/2;

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

 void colorReduce(const Mat& Image,Mat& outImage,int div)
 {
     // 创建与原图像等尺寸的图像
     outImage.create(Image.size(),Image.type());
     int nr=Image.rows;
     // 将3通道转换为1通道
     int nr=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<nr;i++)
         {
             outData[i]=inData[i]/div*div+div/2;
             //*outData++=*inData++/div*div+div/2;
         }
     }
 }

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

但是这种用法不能用在行与行之间,因为图像在OpenCV里的存储机制问题,行与行之间可能有空白单元。这些空白单元对图像来说是没有意思的,只是为了在某些架构上能够更有效率,比如intel MMX可以更有效的处理那种个数是4或8倍数的行。一般来说图像行与行之间往往存储是不连续的,但是有些图像可以是连续的,Mat提供了一个检测图像是否连续的函数isContinuous()。当图像连通时,我们就可以把图像完全展开,看成是一行。

 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();

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

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++;
     }
 }

4.图像的领域操作:
很多时候,我们对图像处理时,要考虑它的邻域,比如3*3是我们常用的,这在图像滤波、去噪中最为常见,下面我们介绍如果在一次图像遍历过程中进行邻域的运算。

下面我们进行一个简单的滤波操作,拉普拉斯算子:[-1 –1 -1;-1 8 –1;-1 –1 -1]。(能使图像变的尖锐)

void Laplacian(const Mat& Image,Mat& newImage)
{
    newImage.create(Image.size(),Image.type());
    int nr=Image.rows;
    int nc=Image.cols;
    for(int i=1;i<nr-1;i++)
    {
        const uchar* line1=Image.ptr<uchar>(i-1);
        const uchar* line2=Image.ptr<uchar>(i);
        const uchar* line3=Image.ptr<uchar>(i+1);
        uchar* outData=newImage.ptr<uchar>(i);
        for(int j=1;j<nc-1;j++)
        {
            outData[j]=saturate_cast<uchar>(8*line2[j]-(line1[j-1]+line1[j]+line1[j+1]+line2[j-1]+line2[j+1]+line3[j-1]+line3[j]+line3[j+1]));
//staturate_cast<typename>是一个类型转换函数,程序里是为了确保运算结果还在uchar范围内
        }
    }
    newImage.row(0).setTo(Scalar(0));
    newImage.row(newImage.rows-1).setTo(Scalar(0));
    newImage.col(0).setTo(Scalar(0));
    newImage.col(newImage.cols-1).setTo(Scalar(0));
}

原图像
原图像
先cvtColor函数转换成灰度图,在用拉普拉斯算子2进行边缘提取的结果
用cvtColor函数变为灰度图后进一步用拉普拉斯算子提取边缘的输出图像
补充:当形参不是引用的时候发生错误。

重新学习2.0以上OPENCV(基于MAT类型)3

图像直方图是反映一个图像像素分布的统计表,其实横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的。纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比。 图像是由像素构成,因为反...
  • qq_27208177
  • qq_27208177
  • 2017年03月08日 10:21
  • 61

重新学习2.0以上OPENCV(基于MAT类型)1

一直没有好好系统的做编程的学习工作,现在才发现,做好笔记是多么重要。。。 参考手册地址:http://docs.opencv.org/2.4.13.2/(中文的虽然看起来简单,但存在很多问题。。。)...
  • qq_27208177
  • qq_27208177
  • 2017年01月02日 21:46
  • 184

OpenCv2 学习笔记(5) Mat类详解

Mat的内容非常多,大致可以分类 构造函数、成员函数2个大板块。 1、Mat构造函数 Mat::Mat C++: Mat::Mat() C++: Mat::...
  • wanggao_1990
  • wanggao_1990
  • 2016年11月21日 21:37
  • 1424

Opencv定义和输出基于Mat的vector

#include #include #include using namespace std; using namespace cv; int main() { vector v; v.pus...
  • qq_23880193
  • qq_23880193
  • 2015年08月23日 10:16
  • 1406

opencv 3.0 Mat 数据类型转换

opencv 3.0将 Mat 向 CvMat CvMatND IplImage 的转化,都去除了 关于 *buf -> Mat 转换 我们不禁想问,那如何实现从 缓存到矩阵的转换呢? 自己...
  • billbliss
  • billbliss
  • 2015年02月28日 15:09
  • 3525

确定 OpenCV 矩阵元素的数据类型

转自:http://www.jianshu.com/p/204f292937bb 在以下两个场景中使用 OpenCV 时,我们必须事先知道矩阵元素的数据类型: 使用 at 方法访问数据...
  • u013021895
  • u013021895
  • 2016年07月27日 14:47
  • 3983

OpenCV程序内存泄露的预防与检测

I. 内存泄露     首先我们要搞清楚什么是内存泄露。一个应用程序在运行时占用内存区域可以分为五个:栈区、堆区、自由存储区、静态区、常量区(不讨论代码区)。栈(Stack)区存放局部变量,也就是在一...
  • doramin
  • doramin
  • 2014年01月01日 17:23
  • 1599

OpenCV不同类型Mat的at方法访问元素时该如何确定模板函数的typename

自从OpenCV推出了Mat后越来越像是Matlab了,使用起来方便了很多,但是,在用at方法访问Mat时,如何选用合适的typename类型来访问相应的Mat元素是个头疼的问题。 比如: int...
  • xxyhjy
  • xxyhjy
  • 2015年05月04日 20:38
  • 1737

OpenCV中Mat 类型学习笔记

主要学学习了 如何查看 Mat类型的变量大小  printf("img.size()函数返回值: \n");//   cout   printf("size[0]:%d\n", img.size...
  • qing101hua
  • qing101hua
  • 2016年10月12日 13:55
  • 296

OpenCV Mat数据类型像素操作

转自:http://blog.csdn.net/skeeee/article/details/13297457  OpenCV图像像素操作及效率分析         在计算机视...
  • jyl1999xxxx
  • jyl1999xxxx
  • 2016年11月07日 19:50
  • 4769
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:重新学习2.0以上OPENCV(基于MAT类型)2
举报原因:
原因补充:

(最多只允许输入30个字)