在opencv的编程中,遍历访问图像元素是经常遇到的操作,掌握其方法非常重要,无论是Mat类的像素访问,还是IplImage结构体的访问的方法,都必须扎实掌握,毕竟,图像处理本质上就是对像素的各种操作,访问元素就是各种图像处理算法的第一步。

首先先看看图像的是怎么存储的。

单通道图像

多通道图像

Mat访问图像元素方法汇总

1.用指针访问元素

在大多数图像处理任务中, 执行计算时你都需要对图像的所有像素进行扫描。 当需要访问的像素数量非常庞大, 你必须采用高效的方式来执行这个任务来提高效率。 如果你需要高效扫描大图片的数据,那么请使用指针方式。

#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>using namespace std;
using namespace cv;int main(int argc, char** argv)
{Mat img = imread("lena.jpg", 1); if (img.empty()){cout << "fail to read image" << endl;return -1;}Mat img1 = img.clone();int div = 64;/* 方法1:用指针访问 *///多通道访问法1int rows = img1.rows;int cols = img1.cols; for (int i = 0; i < rows; i++){//uchar* p = img1.ptr<uchar>(i);  //获取第i行的首地址for (int j = 0; j < cols; j++){//在这里操作具体元素uchar *p = img1.ptr<uchar>(i, j);p[0] = p[0] / div*div + div / 2;p[1] = p[1] / div*div + div / 2;p[2] = p[2] / div*div + div / 2;}}imshow("lean", img1);//多通道访问法2Mat img3 = img.clone();int channels = img3.channels(); //获取通道数int rows3 = img3.rows;int cols3 = img3.cols* channels; //注意,是列数*通道数for (int i = 0; i < rows3; i++){uchar* p = img3.ptr<uchar>(i);  //获取第i行的首地址for (int j = 0; j < cols3; j++){//在这里操作具体元素p[j] = p[j] / div*div + div / 2;p[j+1] = p[j+1] / div*div + div / 2;p[j+2] = p[j+2] / div*div + div / 2;}}imshow("lean3", img3);//单通道图像Mat img2 = img.clone();cvtColor(img2, img2, COLOR_BGR2GRAY);for (int i = 0; i < img2.rows; i++){uchar* p = img2.ptr<uchar>(i);  //获取第i行的首地址for (int j = 0; j < img2.cols; j++){//在这里操作具体元素p[j] = p[j] / div*div + div / 2;}}imshow("lean2", img2);waitKey(0);return 0;
}

2.用迭代器访问元素

在面向对象编程时, 我们通常用迭代器对数据集合进行循环遍历。 标准模板库(STL) 对每个集合类都定义了对应的迭代器类, OpenCV也提供了cv::Mat的迭代器类, 并且与C++ STL中的标准迭代器兼容。

#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>using namespace std;
using namespace cv;int main(int argc, char** argv)
{Mat img = imread("lena.jpg",1); //载入灰度图Mat img1 = img.clone();int div = 64;/* 方法2:用迭代器访问 *//******************多通道的可以这么写***************/Mat_<Vec3b>::iterator it = img1.begin<Vec3b>();  //获取起始迭代器Mat_<Vec3b>::iterator it_end = img1.end<Vec3b>();  //获取结束迭代器for (; it != it_end; it++){//在这里分别访问每个通道的元素(*it)[0] = (*it)[0] / div*div + div / 2;(*it)[1] = (*it)[1] / div*div + div / 2;(*it)[1] = (*it)[1] / div*div + div / 2;}imshow("lean", img1);/******************单通道的可以这么写***************/Mat img2;cvtColor(img, img2, COLOR_RGB2GRAY); //转化为单通道灰度图Mat_<uchar>::iterator it2 = img2.begin<uchar>();  //获取起始迭代器Mat_<uchar>::iterator it_end2 = img2.end<uchar>();  //获取结束迭代器for (; it2 != it_end2; it2++){//在这里分别访问每个通道的元素*it2 = *it2 / div*div + div / 2;}imshow("lena2", img2);waitKey(0);return 0;
}
}

若要从图像的第二行开始,程序该怎么修改? 我们可以用

image.begin<cv::Vec3b>()+image.cols

初始化cv::Mat迭代器。 获得集合结束位置的方法也类似, 只是改用end方法。 但是, 用end方法得到的迭代器已经超出了集合范围, 因此必须在结束位置停止迭代过程。 结束的迭代器也能使用数学计算, 例如, 如果你想在最后一行前就结束迭代, 可使用

image.end<cv::Vec3b>()-image.cols

3.动态地址+at()访问元素

#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>using namespace std;
using namespace cv;int main(int argc, char** argv)
{Mat img = imread("lena.jpg",1); Mat img1 = img.clone();int div = 64;/* 方法3:用at访问 *//****************访问多通道元素*********************/int rows = img1.rows;int cols = img1.cols;for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){//在这里访问每个通道的元素,注意,成员函数at(int y,int x)的参数img1.at<Vec3b>(i,j)[0] = img1.at<Vec3b>(i, j)[0] / div*div + div / 2;img1.at<Vec3b>(i, j)[1] = img1.at<Vec3b>(i, j)[1] / div*div + div / 2;img1.at<Vec3b>(i, j)[2] = img1.at<Vec3b>(i, j)[2] / div*div + div / 2;}}imshow("lena", img1);/****************访问单通道元素*********************/Mat img2;cvtColor(img, img2, COLOR_RGB2GRAY);for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){//在这里访问每个通道的元素,注意,成员函数at(int y,int x)的参数img2.at<uchar>(i, j) = img2.at<uchar>(i, j) / div*div + div / 2;}}imshow("lena2", img2);waitKey(0);return 0;
}

IplImage访问元素方法汇总

1.使用cvGet2D()函数访问

#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>using namespace std;
using namespace cv;int main(int argc, char** argv)
{/*访问单通道元素*/IplImage* img = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 1); //单通道图像CvScalar s;double tmp;for (int i = 0; i < img->height; i++){for (int j = 0; j < img->width; j++){//可以在这里访问元素tmp = cvGet2D(img, i, j).val[0];cvSet2D(img, i, j, 255);  //第三个参数是要设置的值}}cvShowImage("img", img);/*访问多通道元素*/IplImage* img2 = cvCreateImage(cvSize(640, 480), IPL_DEPTH_32F, 3);double tmpb, tmpg, tmpr;for (int i = 0; i < img->height; i++){for (int j = 0; j < img->width; j++){tmpb = cvGet2D(img, i, j).val[0];tmpg = cvGet2D(img, i, j).val[1];tmpr = cvGet2D(img, i, j).val[2];cvSet2D(img2, i, j, CvScalar(255,255,255));  //第三个参数是要设置的值,三个通道一起设置}}cvShowImage("img2", img2);waitKey(0);return 0;
}

2.指针方式直接访问

追求高效率地访问元素请使用该方法。

#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>using namespace std;
using namespace cv;int main(int argc, char** argv)
{/*访问多通道元素*/IplImage* img = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3);uchar* data = (uchar *)img->imageData;int step = img->widthStep / sizeof(uchar);int channels = img->nChannels;uchar b, g, r;for (int i = 0; i < img->height; i++){for (int j = 0; j < img->width; j++){//获得元素的值b = data[i*step + j*channels + 0];g = data[i*step + j*channels + 1];r = data[i*step + j*channels + 2];//修改元素的值data[i*step + j*channels + 0] = 255;}}cvShowImage("img", img);/*访问单通道元素*/IplImage* img2 = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 1);uchar* data2 = (uchar *)img2->imageData;int step2 = img2->widthStep / sizeof(uchar);uchar v;for (int i = 0; i < img2->height; i++){for (int j = 0; j < img2->width; j++){//获得元素的值v = data2[i*step2 + j];//修改元素的值data2[i*step2 + j] = 255;}}cvShowImage("img2", img2);waitKey(0);return 0;
}

OpenCV精进之路(零):core组件——Mat和IplImage访问像素的方法总结相关推荐

  1. OpenCV精进之路(十五):特征检测和特征匹配方法汇总

    一幅图像中总存在着其独特的像素点,这些点我们可以认为就是这幅图像的特征,成为特征点.计算机视觉领域中的很重要的图像特征匹配就是一特征点为基础而进行的,所以,如何定义和找出一幅图像中的特征点就非常重要. ...

  2. OpenCV精进之路(十六):图像分解和融合技术——图像拼接和图像融合技术

    图像拼接在实际的应用场景很广,比如无人机航拍,遥感图像等等,图像拼接是进一步做图像理解基础步骤,拼接效果的好坏直接影响接下来的工作,所以一个好的图像拼接算法非常重要. 再举一个身边的例子吧,你用你的手 ...

  3. 《Go语言精进之路,从新手到高手的编程思想、方法和技巧1》读书笔记和分享

    Go语言精进之路,从新手到高手的编程思想.方法和技巧 读书分享 1 本书定位 2 本书内容总览 3 选择本书的原因 4 小收获分享 第7-12条 真的不知道咋命名 第13-19条 能用--怎么用更好 ...

  4. OpenCV精进之路(零):访问图像中像素的三种方法

    访问像素的三种方法 指针访问:最快 迭代器iterator:较慢,非常安全,指针访问可能出现越界问题 动态地址计算:更慢,通过at()实现.适用于访问具体某个第i行,j列的像素,而不适用遍历像素 这里 ...

  5. 创建mat二值图 matlab,OpenCV学习之路(二)——Mat对象

    早期的 OpenCV 中,使用 IplImage 和 CvMat 数据结构来表示图像.IplImage和 CvMat 都是 C 语言的结构.使用这两个结构的问题是内存需要手动管理,开发者必须清楚的知道 ...

  6. python 图像无缝拼接,OpenCV Python 系列教程3 - Core 组件

    基本知识 灰度图像的存储方式: image 多通道图像存储方式 image OpenCV 中的通道存储为 BGR 像素值的存储方式 RGB 模式,显示设备采用这种模式 HSV.HLS 将颜色分解成色调 ...

  7. OpenCV精进之路(二十二):实例——皮肤检测技术

    好久没写博客了,因为最近都忙着赶项目和打比赛==| 好吧,今天我打算写一篇关于使用opencv做皮肤检测的技术总结.那首先列一些现在主流的皮肤检测的方法都有哪些: RGB color space Yc ...

  8. OpenCV精进之路(一):图像处理知识点串烧

    opencv图像初始化操作 #include<opencv2\opencv.hpp> #include<opencv2\highgui\highgui.hpp>using na ...

  9. OpenCV精进之路(零):core组件——绘制点、直线、几何图形

    绘制点和圆 void cvCircle( CvArr* img, CvPoint center, int radius, CvScalar color,int thickness=1, int lin ...

最新文章

  1. python字典popitem和pop_python 字典之pop() and popitem()
  2. OpenCV使用人脸界标检测进行人脸交换
  3. radio切换控制div显示_JavaScript连载31图片动态切换以及关闭图片案例
  4. Delphi 完整的Bug决议工具EurekaLog的使用
  5. WPF TreeView 绑定(demo 转)
  6. Linux单用户模式(修改密码、运行级别)方法详解
  7. 大数据之-hadoop知识体系架构---大数据之hadoop工作笔记0001
  8. php redis用途,redis可以做什么?
  9. 在线工具-程序员的工具箱-在线Cron表达式生成器
  10. 关于SQLServer2005的学习笔记——异常捕获及处理
  11. stm32f103+znfat+ch375+vs1003实现简单mp3播放器功能
  12. 计算机isas测试,SAS硬盘测试:15,000转对决10,000转
  13. background 与 background-image
  14. 使用vue-awesome-swiper制作H5动画页面
  15. linux发行版本号列举,查看Linux发行版的名称及其版本号
  16. java反射 enum参数_CookBook/3-Java反射.md at master · Byron4j/CookBook · GitHub
  17. 汉字区位码查询与算法——microsoft visual studio 2005系列
  18. 2019秋招海康测试一面
  19. (exynos4412)Tiny4412裸机开发-点亮LED灯
  20. kernel32 ntdll

热门文章

  1. .国内外主流前端开发框架对比
  2. tortoiseSVN svn+ssh
  3. php框架原理 php初识,初识PHP
  4. c语言extern_【零基础C语言】- static和extern关键字 - 对变量的作用!
  5. SFS2X 例子(java 扩展加as 客户端)
  6. Illegal mix of collations (utf8mb4_unicode_ci,IMPLICIT) and (utf8mb4_general_ci
  7. git bash here 找不到应用程序_git 简单命令
  8. android字节数转兆,ios – Swift – 如何计算字节数并将其转换为兆字节?
  9. JavaWeb——servlet介绍
  10. ArcGIS Maritime Server 开发教程(四)Maritime Service 开发实践