opencv遍历像素的方式

【OpenCV】OpenCV中遍历图像像素的几种方式对比 Mat 类是OpenCV中的一个基本数据类型,它是一个n维密集数组类Mat 类表示一个 n 维密集数值单通道或多通道数组。它可用于存储实数或复值向量和矩阵、灰度或彩色图像、体素体积、向量场、点云、张量、直方图。本文将总结几种遍历像素的不同方法,在需要处理大量图片的场景,不同的遍历方法,速度上会有显著差异。用指针法遍历图像是最高效的,用迭代器遍历图像则是比较安全的。 阅读详情

OpenCV优化:图像的遍历4种方式

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

一、遍历图像的4种方式:at<typename>(i,j)

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

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

复制代码
 1 void colorReduce(Mat& image,int div)
 2 {
 3     for(int i=0;i<image.rows;i++)
 4     {
 5         for(int j=0;j<image.cols;j++)
 6         {
 7             image.at<Vec3b>(i,j)[0]=image.at<Vec3b>(i,j)[0]/div*div+div/2;
 8             image.at<Vec3b>(i,j)[1]=image.at<Vec3b>(i,j)[1]/div*div+div/2;
 9             image.at<Vec3b>(i,j)[2]=image.at<Vec3b>(i,j)[2]/div*div+div/2;
10         }
11     }
12 }
复制代码

image

通过上面的例子我们可以看出,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代表类型。

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

Mat_<uchar> im=image;

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

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

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

复制代码
 1 void colorReduce(const Mat& image,Mat& outImage,int div)
 2 {
 3     // 创建与原图像等尺寸的图像
 4     outImage.create(image.size(),image.type());
 5     int nr=image.rows;
 6     // 将3通道转换为1通道
 7     int nl=image.cols*image.channels();
 8     for(int k=0;k<nr;k++)
 9     {
10         // 每一行图像的指针
11         const uchar* inData=image.ptr<uchar>(k);
12         uchar* outData=outImage.ptr<uchar>(k);
13         for(int i=0;i<nl;i++)
14         {
15             outData[i]=inData[i]/div*div+div/2;
16         }
17     }
18 }
复制代码

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

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

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

三、更高效的方法

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

复制代码
 1 void colorReduce(const Mat& image,Mat& outImage,int div)
 2 {
 3     int nr=image.rows;
 4     int nc=image.cols;
 5     outImage.create(image.size(),image.type());
 6     if(image.isContinuous()&&outImage.isContinuous())
 7     {
 8         nr=1;
 9         nc=nc*image.rows*image.channels();
10     }
11     for(int i=0;i<nr;i++)
12     {
13         const uchar* inData=image.ptr<uchar>(i);
14         uchar* outData=outImage.ptr<uchar>(i);
15         for(int j=0;j<nc;j++)
16         {
17             *outData++=*inData++/div*div+div/2;
18         }
19     }
20 }
复制代码

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

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程序:

复制代码
 1 void colorReduce(const Mat& image,Mat& outImage,int div)
 2 {
 3     outImage.create(image.size(),image.type());
 4     MatConstIterator_<Vec3b> it_in=image.begin<Vec3b>();
 5     MatConstIterator_<Vec3b> itend_in=image.end<Vec3b>();
 6     MatIterator_<Vec3b> it_out=outImage.begin<Vec3b>();
 7     MatIterator_<Vec3b> itend_out=outImage.end<Vec3b>();
 8     while(it_in!=itend_in)
 9     {
10         (*it_out)[0]=(*it_in)[0]/div*div+div/2;
11         (*it_out)[1]=(*it_in)[1]/div*div+div/2;
12         (*it_out)[2]=(*it_in)[2]/div*div+div/2;
13         it_in++;
14         it_out++;
15     }
16 }
复制代码

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

上面4种方法中,第3种方法的效率最高!

五、图像的邻域操作

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

下面我们进行一个简单的滤波操作,滤波算子为[0 –1 0;-1 5 –1;0 –1 0]。

它可以让图像变得尖锐,而边缘更加突出。核心公式即:sharp(i.j)=5*image(i,j)-image(i-1,j)-image(i+1,j

)-image(i,j-1)-image(i,j+1)。

复制代码
 1 void ImgFilter2d(const Mat &image,Mat& result)
 2 {
 3     result.create(image.size(),image.type());
 4     int nr=image.rows;
 5     int nc=image.cols*image.channels();
 6     for(int i=1;i<nr-1;i++)
 7     {
 8         const uchar* up_line=image.ptr<uchar>(i-1);//指向上一行
 9         const uchar* mid_line=image.ptr<uchar>(i);//当前行
10         const uchar* down_line=image.ptr<uchar>(i+1);//下一行
11         uchar* cur_line=result.ptr<uchar>(i);
12         for(int j=1;j<nc-1;j++)
13         {
14             cur_line[j]=saturate_cast<uchar>(5*mid_line[j]-mid_line[j-1]-mid_line[j+1]-
15                 up_line[j]-down_line[j]);
16         }
17     }
18     // 把图像边缘像素设置为0
19     result.row(0).setTo(Scalar(0));
20     result.row(result.rows-1).setTo(Scalar(0));
21     result.col(0).setTo(Scalar(0));
22     result.col(result.cols-1).setTo(Scalar(0));
23 }
复制代码

image

上面的程序有以下几点需要说明:

1,staturate_cast<typename>是一个类型转换函数,程序里是为了确保运算结果还在uchar范围内。

2,row和col方法返回图像中的某些行或列,返回值是一个Mat。

3,setTo方法将Mat对像中的点设置为一个值,Scalar(n)为一个灰度值,Scalar(a,b,c)为一个彩色值。

六、图像的算术运算

Mat类把很多算数操作符都进行了重载,让它们来符合矩阵的一些运算,如果+、-、点乘等。

下面我们来看看用位操作和基本算术运算来完成本文中的colorReduce程序,它更简单,更高效。

将256种灰度阶降到64位其实是抛弃了二进制最后面的4位,所以我们可以用位操作来做这一步处理。

首先我们计算2^8降到2^n中的n:int n=static_cast<int>(log(static_cast<double>(div))/log(2.0));

然后可以得到mask,mask=0xFF<<n;

用下面简直的语句就可以得到我们想要的结果:

result=(image&Scalar(mask,mask,mask))+Scalar(div/2,div/2,div/2);

很多时候我们需要对图像的一个通信单独进行操作,比如在HSV色彩模式下,我们就经常把3个通道分开考虑。

1 vector<Mat> planes;
2 // 将image分为三个通道图像存储在planes中
3 split(image,planes);
4 planes[0]+=image2;
5 // 将planes中三幅图像合为一个三通道图像
6 merge(planes,result);

作者:☆Ronny丶

出处:http://www.cnblogs.com/ronny/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


OpenCV重复图像检测(用于筛除不同来源下载的重复图像) 最近做深度学习需要从网上批量下载一些图像,遇到一个现实的问题就是不同关键字爬取下来的图像可能完全一样,这样的样本如果不加以清除势必影响模型的学习效果。 写的也比较简单,装有tensorflow的直接可以用,没装的用os实现遍历文件名也可,写的比较仓促就没改,日后有空补上新版 注意:因为这里是用0-255的像素采样(采了10个点)作为信息指纹,所以只能检测出完全一样的图,相似图像或者剪裁过的样本无法检测,网上有一些类似功能的脚本,大家各取所需。 权当练手,不喜勿喷哈哈哈 下面放代码: import 阅读详情

相关推荐

Opencv 中 Mat中元素的值读取方法总结

1、利用 at 函数读取 (1)单通道图像读取方式 Mat img1 = imread(filename,IMREAD_GRAYSCALE);      for( size_t nrow = 0; nrow     {          for(size_t ncol = 0; ncol         {              uchar val = mat_CV_

chenkent888的专栏 1万+

OpenCV成长之路(2):图像的遍历

我们在实际应用中对图像进行的操作,往往并不是将图像作为一个整体进行操作,而是对图像中的所有点或特殊点进行运算,所以遍历图像就显得很重要,如何高效的遍历图像是一个很值得探讨的问题。 一、遍历图像的4种方式:at&lt;typename&gt;(i,j) Mat类提供了一个at的方法用于取得图像上的点,它是一个模板函数,可以取到任何类型的图像上的点。下面我们通过一个图像处理中的实际来说明它的用法。...

weixin_34195546的博客 1893

openCV遍历图片像素方式的时间效率对比

方式1.采用at函数获取像素值 for (int i = 0; i < img.rows; i++) { for (int j = 0; j < img.cols; j++) { img.at(i, j) = 255 - img.at(i, j); } } 方式2.采用.data指针获取像素 uchar * pImg = img.data; for (int i

小丑X1的博客 1187

opencv 几种不同遍历图像像素的方法详解

简述 我们在图像处理时经常会用到遍历图像像素点的方式,同样是遍历图像像素点,共有很多中方法可以做到;在这些方法中,有相对高效的,也有低效的;不是说低效的方法就不好,不同场景使用不同方法。 方法 下面将一一介绍这些遍历图像像素点的方法: 方法一:数组遍历法1 图像Mat中每个像素点,其实就是一个值(int、float、double、uchar等类型),而Mat是一个二维数组。 1、单通道...

qq_27278957的博客 1万+

Cursor集成Claude 4.6免费版:本地IDE合规调用指南

大语言模型编程助手(LLM Copilot)已成为现代开发标配,其核心能力依赖于上下文理解、代码推理与结构化输出等关键技术原理。Anthropic官方提供的Claude系列模型,尤其Claude 4.6,凭借200K超长上下文、tool use函数调用和严格可控的API设计,在工程实践中展现出显著技术价值。该能力可无缝嵌入本地IDE环境,支撑代码解释、跨文件分析、单元测试生成等高频开发场景。本文聚焦Cursor这一开源可审计IDE,详解如何合规复用Anthropic免费tier接口(/v1/messages

weixin_34095889的博客 537

深入剖析STM32F103 I2C总线死锁问题及高效应对策略

本文深入剖析了STM32F103硬件I2C总线在轮询模式下发生死锁的根本原因,即硬件状态机的预取机制与软件响应速度不匹配。文章提供了高效的解决方案,包括在轮询模式下提前发送NACK/STOP信号、降低总线速度,以及治本的中断与DMA应用策略,帮助开发者根据项目需求选择最合适的方案,彻底解决这一经典硬件缺陷问题。

weixin_29184371的博客 206

opencv学习(四)之像素遍历三种方式

在上一篇文章中介绍了图像颜色空间缩减、查找表等内容。在对图像像素进行遍历时共有三种方法: (1). C操作符[] (指针方式访问) (2). 迭代器iterator (3). 动态地址计算 这三种像素遍历方式在速度上有所不同,上一篇文章介绍过用C操作符[]是最快的访问方式。下面会通过对同一幅图像进行处理来直观的比较三种访问方式的速度差异。首先介绍一下opencv中提供的计时函数 1.计时

烟雨博客 1万+

AVM环视算法实战:从3D碗型投影到多场景模式切换的实现与优化

本文深入探讨了AVM环视算法在3D碗型投影和多场景模式切换中的实现与优化。通过分析3D碗型投影的核心原理和动态视角调节技术,展示了如何实现从超广角模式到转向模式的无缝切换。文章还分享了性能优化实战经验,包括实时性提升和图像拼接质量优化,为开发者提供了宝贵的AVM系统开发指南。

weixin_42573113的博客 171

opencv学习(五)之像素遍历三种方式耗时分析

前面用两篇介绍了像素的颜色空间缩减、查找表、遍历像素的三种方式、程序计时等,也说了一下每种方法的优缺点,现在用一个综合型的程序进行对比。方式是用三种方式对lena图像(220x220)进行处理,使其颜色种类从256中变成64种。在颜色空间缩减方法中讲过这种方式,即每个像素值除以4向下取整然后再乘以4即可将其颜色种类缩减到64种。#include <iostream> #include <opencv

烟雨博客 9003

【机器学习】实验2,基于回归分析的大学综合得分预测(完整代码实现+分析)

大学排名是一个非常重要同时也极富挑战性与争议性的问题,一所大学的综合实力涉及科研、师资、学生等方方面面。目前全球有上百家评估机构会评估大学的综合得分进行排序,而这些机构的打分也往往并不一致。在这些评分机构中,世界大学排名中心(Center for World University Rankings,缩写CWUR)以评估教育质量、校友就业、研究成果和引用,而非依赖于调查和大学所提交的数据著称,是非常有影响力的一个。

高丽大学人工智能硕士在读|专注大模型、RAG、OCR与AI工程实践 1976

基于微博API与Scrapy-Redis的城市情绪地图数据爬取实战

本文详细介绍了如何利用Python爬虫技术从微博平台获取用户发布内容,用于构建城市情绪地图的毕业设计项目。文章涵盖了微博API的调用、Scrapy-Redis分布式爬虫架构、数据清洗与存储、反爬虫策略应对以及情绪分析预处理等关键技术,提供了完整的代码实现和实战经验。python复制下载# items.py"""清洗文本数据"""if text:# 移除HTML标签# 移除多余空白字符"""解析微博日期格式"""

2201_76125261的博客 446

【见微知著】OpenCV中C++11 lambda方式急速像素遍历

必须知道的最快速的两种OpenCV像素遍历方法....

关注微信公众号【OpenCV学堂】 860

YOLO模型从10MB瘦到2MB!剪枝+INT8量化双方案(精度损失<1%,附部署代码)

摘要:本文介绍了一种针对边缘设备的YOLO模型轻量化方案,通过"结构化剪枝+INT8量化"组合技术,将YOLOv8n模型从6.4MB压缩至2MB,体积减少68.75%,推理速度提升80%,同时保持精度损失小于1%。文章详细讲解了剪枝工具选择、通道剪枝实现、量化校准等关键步骤,并提供了完整的代码示例。特别强调了剪枝保留率、校准集使用、微调必要性等实践要点,帮助开发者在树莓派等资源受限设备上实现高效目标检测。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 756

OpenCV图像处理——遍历图像像素的几种方式比对

在 OpenCV 中,访问图像像素有好几种,如:.at、.ptr、ptr()、.data、MatIterator_ 等,不同的像素访问方式的处理时间都不相同。对于实时性要求比较高的应用场景来说,处理的时间极为重要。

知来者逆的博客 1226

【反封禁策略】集成 Undetected-Chromedriver:让 Browser-Use 绕过 Cloudflare 五秒盾

摘要:AI Agent如何突破Cloudflare检测的实战指南 本文针对AI Agent在Cloudflare检测下频繁受阻的问题,深入分析了undetected-chromedriver的工作原理与局限性。文章指出,Cloudflare 2026年的检测体系已升级为"浏览器指纹+IP信誉+协议指纹+行为模式"的多维交叉验证,单一伪装方案难以奏效。 核心内容包括: undetected-chromedriver的三层补丁体系解析 v2与v3版本的适用场景对比 两种Browser-Use集成方案:Selen

ZDQ58818的博客 284

鸿宇多用户商城user.php RCE漏洞复现

鸿宇多用户商城 user.php 存在任意命令执行漏洞,攻击者可通过该漏洞在服务器端任意执行代码,写入后门,获取服务器权限,进而控制整个web服务器。

0xSec 1622

OpenCV使用forEach的方式来遍历像素值

opencv 4.x新增了forEach的方式遍历像素值,比传统方式略快一些。写了一个测试用例,把它用起来。包括单通道,三通道,浮点型等Mat的遍历。

$firecat利白的代码足迹$ 977

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

opencv学习-004-图像像素的读写操作(Mat.at方法,案例实现图像的颜色反转(数组遍历和指针方式遍历))

opencv学习-004-图像像素的读写操作和一些算术运算(案例实现图像的颜色反转(数组遍历和指针方式遍历))1. 通道2. Vec3b类型3. 指针方式遍历中的要点 #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int artc, char** argv) { Mat src = imread("E:/Desktop/y.j

kuanyew的博客 1830

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

OpenCV:OpenCV 4.5遍历像素的常见方式及效率对比

cv::Mat imageTest; imageTest = cv::imread("F:/test.png"); for (int row = 0; row < imageTest.rows; row++) { for (int col = 0; col < imageTest.cols; col++) { cv::Vec3b bgr = imageTest.at<c...

累了就要打游戏 829

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

OpenCV 图像的翻转 flip实现 与遍历像素的方式实现

在OpenCV中有内置的函数flip可以实现图像的垂直、水平以及同时垂直水平变换

会意的博客 4321

OpenCV操作像素:图像的遍历4种方式、访问相邻像素的方法和图像重映射

OpenCV优化:图像的遍历4种方式 我们在实际应用中对图像进行的操作,往往并不是将图像作为一个整体进行操作,而是对图像中的所有点或特殊点进行运算,所以遍历图像就显得很重要,如何高效的遍历图像是一个很值得探讨的问题。 一、遍历图像的4种方式:at&lt;typename&gt;(i,j) Mat类提供了一个at的方法用于取得图像上的点,它是一个模板函数,可以取到任何类型的图像上的点。下面我们...

律己且好学,才能保证不坠入愤世嫉俗之列。 821

opencv3_note2:使用三种方式遍历像素

1.什么是一幅图像———(摘自《数字图像处理疑难解析》) 1.就单色图像而言,是一个二维的光强函数f(x,y),其中的x和y是空间坐标,f(x,y)正比于图像在该点的亮度值;若是一幅彩色图,则f 是一个向量,每一个分量代表着一个颜色分量 2.数字图像在空间坐标和亮度值都离散化的图像f(x,y)中,它可以用一个或者若干个数组来表示数组的每一个元素称为像素(pixel) 2.颜色空间缩减算法 ...

Lzinner的博客 399

Opencv遍历图像像素的两种方式(以调整图像亮度与对比度为例)

Opencv遍历图像像素的两种方式(以调整图像亮度与对比度为例)

人工智能领域专家 4118

002-OpenCV4(C++)认识图像对象-Mat并以六种方式创建Mat,以及获取图像宽 高 通道 深度 类型,运用数组和指针遍历与访问像素

OpenCV4(C++)认识图像对象-Mat并以六种方式创建Mat,以及获取图像宽 高 通道 深度 类型,运用数组和指针遍历与访问像素

AlexanderMiao的博客 6259

像素遍历

像素遍历 要使用opencv进行图片像素遍历,首先,我们要明确像素在内存空间中的存储方式,存储方式如下图所示: 遍历图片的示例代码如下: Mat& ScanImageAndReduceC(Mat& I) { CV_Assert(I.depth() != sizeof(uchar)); int channels = I.channels(); int nRows = I.rows; int nCols = I.cols * channels; qDebug() <&

Dramer 318
上一篇: OpenCV+OpenGL 双目立体视觉三维重建
下一篇: OpenCV单应变换模型拼接两幅图像
Cecilia_YS
博客等级 码龄9年 170粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值