在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:用指针访问 */
//多通道访问法1
int 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); //多通道访问法2
Mat 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探索之路(十七):Mat和IplImage访问每个像素的方法总结的更多相关文章

  1. OpenCV探索之路(十七):Mat和IplImage访问像素的方法总结

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

  2. opencv学习笔记(八)IplImage* 访问图像像素的值

    opencv2.1版本之前使用IplImage*数据结构来表示图像,2.1之后的版本使用图像容器Mat来存储.IplImage结构体如下所示. typedef struct _IplImage { i ...

  3. OpenCV(2)-Mat数据结构及访问Mat中像素

    Mat数据结构 一开始OpenCV是基于C语言的,在比较早的教材例如<学习OpenCV>中,讲解的存储图像的数据结构还是IplImage,这样需要手动管理内存.现在存储图像的基本数据结构是 ...

  4. OpenCV探索之路(二十七):皮肤检测技术

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

  5. OpenCV之CvMat、Mat、IplImage之间相互转换实例(转)

    OpenCV学习之CvMat的用法详解及实例 CvMat是OpenCV比较基础的函数.初学者应该掌握并熟练应用.但是我认为计算机专业学习的方法是,不断的总结并且提炼,同时还要做大量的实践,如编码,才能 ...

  6. opencv中Mat与IplImage,CVMat类型之间转换

    opencv中对图像的处理是最基本的操作,一般的图像类型为IplImage类型,但是当我们对图像进行处理的时候,多数都是对像素矩阵进行处理,所以这三个类型之间的转换会对我们的工作带来便利. Mat类型 ...

  7. javaCV图像处理之Frame、Mat和IplImage三者相互转换(使用openCV进行Mat和IplImage转换)

    前言:本篇文章依赖四个jar包,其中javacv.jar,javacpp.jar和opencv.jar为固定jar包,opencv-系统环境.jar为选配(根据自己的系统平台,x64还是x86而定) ...

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

    自从OpenCV推出了Mat后越来越像是Matlab了,使用起来方便了很多,但是,在用at方法访问Mat时,如何选用合适的typename类型来访问相应的Mat元素是个头疼的问题. 比如: int H ...

  9. opencv 数据类型转换:CvArr, Mat, CvMat, IplImage, BYTE 转

    留着以后查询: http://blog.csdn.net/augusdi/article/details/8863820 一.Mat类型:矩阵类型,Matrix. 在openCV中,Mat是一个多维的 ...

随机推荐

  1. OC中Foundation框架之NSDictionary、NSMutableDictionary

    NSDictionary概述 NSDictionary的作用类似:通过一个key ,就能找到对应的value 同样 NSDictionary是不可变的,一旦初始化完毕,里面的内容就无法修改 NSDic ...

  2. vs项目和msql不兼容解决方案

    当vs的工程项目加载了libmysql.lib 即:附加包含目录,附加库目录,附加依赖项都设置好之后,如过编译出现如下: error LNK2019: 无法解析的外部符号 _mysql_real_co ...

  3. Java 程序员快速上手 Kotlin 11 招

    欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者:霍丙乾 近经常会收到一些 "用 Kotlin 怎么写" 的问题,作为有经验的程序员, ...

  4. Java源码学习 -- java.lang.String

    java.lang.String是使用频率非常高的类.要想更好的使用java.lang.String类,了解其源代码实现是非常有必要的.由java.lang.String,自然联想到java.lang ...

  5. 让xcode8支持7.0的设备

    升级到xcode8之后发现不能支持7.0设备 1 . 下载文件将文件覆盖到 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS. ...

  6. Java生成二维码--QRGen

    最近公司需求需要生成一个二维码 , 由于之前没有接触过 , 故此做个记录 . 在网上找到了不少二维码生成工具,都蛮好用的. 不过要集成二维码生成功能到应用开发中,就要选择最好用成熟的库了,最终决定采用 ...

  7. Java中的会话管理——HttpServlet,Cookies,URL Rewriting(译)

    参考谷歌翻译,关键字直接使用英文,原文地址:http://www.journaldev.com/1907/java-session-management-servlet-httpsession-url ...

  8. 一天搞定CSS:文本text--05

    1.文本体系 2.文本各属性取值 说明: 每一个属性后面的分支是属性值,以及对属性值的说明. 比如text-align- - - -有3个取值:left,center,right 3.空格大小 4.代 ...

  9. 使用Windows Server 2012+ 搭建VPN 简单 高效 稳定

    前几天,在机缘巧合之下,买到了一台性能配置一般的腾讯云服务器(香港的),因为性能比较差,没啥太大用途,就想着试试搭建一个VPN,后来,经过多次尝试和查资料,总结出了一套几乎100%成功的教程,现在拿来 ...

  10. Thrift总结(一)介绍

    这段时间,一直在整理公司的内部 rpc 服务接口,面临的一个问题就是:由于公司内部的系统由几个不同的语言编写的.C# ,java,node.js 等,如何实现这些内部系统之间的接口统一调用,确实是比较 ...