千家信息网

OpenCV通过Mat遍历图像的方法有哪些

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,本文小编为大家详细介绍"OpenCV通过Mat遍历图像的方法有哪些",内容详细,步骤清晰,细节处理妥当,希望这篇"OpenCV通过Mat遍历图像的方法有哪些"文章能帮助大家解决疑惑,下面跟着小编的思路
千家信息网最后更新 2025年02月02日OpenCV通过Mat遍历图像的方法有哪些

本文小编为大家详细介绍"OpenCV通过Mat遍历图像的方法有哪些",内容详细,步骤清晰,细节处理妥当,希望这篇"OpenCV通过Mat遍历图像的方法有哪些"文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

我们在实际应用中对图像进行的操作,往往并不是将图像作为一个整体进行操作,而是对图像中的所有点或特殊点进行运算,所以遍历图像就显得很重要,如何高效的遍历图像是一个很值得探讨的问题。

Color Reduce
还是使用经典的Reduce Color的例子,即对图像中的像素表达进行量化。如常见的RGB24图像有256×256×256中颜色,通过Reduce Color将每个通道的像素减少8倍至256/8=32种,则图像只有32×32×32种颜色。假设量化减少的倍数是N,则代码实现时就是简单的value/N*N,通常我们会再加上N/2以得到相邻的N的倍数的中间值,最后图像被量化为(256/N)×(256/N)×(256/N)种颜色。

并对图像降色彩后的彩色直方图进行统计。

方法一、直接对图像像素修改.at(i,j)

Mat类提供了一个at的方法用于取得图像上的点,它是一个模板函数,可以取到任何类型的图像上的点。

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

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

image.at(i,j):取出灰度图像中i行j列的点。
image.at(i,j)[k]:取出彩色图像中i行j列第k通道的颜色点,k=[0,1,2],分别代表B,G,R。

其中uchar,Vec3b都是图像像素值的类型,不要对Vec3b这种类型感觉害怕,其实在core里它是通过typedef Vec来定义的,N代表元素的个数,T代表类型。

更简单一些的方法:OpenCV定义了一个Mat的模板子类为Mat_,它重载了operator()让我们可以更方便的取图像上的点。

Mat_ im=image;im(i,j)=im(i,j)/div*div+div/2;

二、用指针.ptr(k)来遍历输入图像,数组[]生成输出图像

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

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(k);        uchar* outData=outImage.ptr(k);        for(int i=0;i

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

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

但是这种用法不能用在行与行之间,因为图像在OpenCV里的存储机制问题,行与行之间可能有空白单元。这些空白单元对图像来说是没有意思的,只是为了在某些架构上能够更有效率,比如intel MMX可以更有效的处理那种个数是4或8倍数的行。但是我们可以申明一个连续的空间来存储图像,这个话题引入下面最为高效的遍历图像的机制。

三、用指针.ptr(k)来遍历输入图像,指针方式生成输出图像

与上述方法二遍历图像的方法相同,而生成输出图像的方式从数组换成了指针的方式。因此只需改动一句话。

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(k);        uchar* outData=outImage.ptr(k);        for(int i=0;i

四、用指针.ptr(k)来遍历输入图像,指针方式结合位运算生成输出图像

与上述方法遍历图像的方法相同,而生成输出图像的方式从加减乘除基本四则运算的方式换成了位运算的方式。

这里特别需要注意的是,位运算的优先级是低于乘除加减的,所以一定要在位运算加括号。

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();    //对数换底公式log a(b) = log b/log a    int n = static_cast(log(static_cast(div)) / log(2.0));    // mask used to round the pixel value  e.g. for div=16, mask= 0xF0    uchar mask = 0xFF << n;    for (int k = 0; k(k);        uchar* outData = outImage.ptr(k);        for (int i = 0; i

五、用指针.ptr(k)来遍历输入图像,指针方式结合取模运算生成输出图像

与上述方法遍历图像的方法相同,而生成输出图像的方式从位运算的方式换成了取模运算的方式。

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();    int n = static_cast(log(static_cast(div)) / log(2.0));    // mask used to round the pixel value  e.g. for div=16, mask= 0xF0    uchar mask = 0xFF << n;    for (int k = 0; k(k);        uchar* outData = outImage.ptr(k);        for (int i = 0; i

六、连续图像isContinuous()函数方法。

上面已经提到过了,一般来说图像行与行之间往往存储是不连续的,但是有些图像可以是连续的,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(i);        uchar* outData=outImage.ptr(i);        for(int j=0;j

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

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

image.at(i,j)=image.data+i*image.step+j*image.elemSize();

七、迭代器Mat_iterator方法。

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

MatIterator_ it; Mat_::iterator it;

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

MatConstIterator it;或者Mat_::const_iterator it;

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

void colorReduce(const Mat& image,Mat& outImage,int div){    outImage.create(image.size(),image.type());    MatConstIterator_ it_in=image.begin();    MatConstIterator_ itend_in=image.end();    MatIterator_ it_out=outImage.begin();    MatIterator_ itend_out=outImage.end();    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()+image.rows

读到这里,这篇"OpenCV通过Mat遍历图像的方法有哪些"文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注行业资讯频道。

图像 方法 指针 通道 像素 方式 运算 原图 输出 一行 面的 生成 函数 存储 之间 元素 尺寸 数据 类型 颜色 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 oa软件开发公司和 扬州专业led大屏服务器 昆明市网络安全为人民视频 传奇数据库 looks 服务器管理器适配网络 怎么用服务器挂京东脚本 火山软件开发制作注册窗口 东莞网警提示网络安全无小事 数据库规范化理论中的等价 网络安全内容留言 电脑登录英雄联盟服务器异常 无线网络技术调研报告怎么写 事业单位网络技术岗笔试题 宣城点餐系统软件开发需要多少钱 qq服务器怎么用 css什么定义服务器字体 广州什么时候兴起软件开发 六年级网络安全征文500 银行软件开发岗上班有压力吗 计算机网络安全 百度文库 前置服务器名词解释 重庆双线服务器托管口碑云主机 上千台服务器防火墙管理员 武清区项目网络技术诚信合作 腾讯游戏服务器ip显示在内蒙古 h5与数据库怎么交互 近年来有名的网络安全事件 工业网络技术考研 龙游图腾服务器机柜价格 对新一代网络技术的看法
0