首页 > 其他分享 >OpenCV Mat和IplImage访问像素的方法总结

OpenCV Mat和IplImage访问像素的方法总结

时间:2024-08-28 11:24:15浏览次数:13  
标签:Mat img int ++ OpenCV img2 div IplImage

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

标签:Mat,img,int,++,OpenCV,img2,div,IplImage
From: https://blog.csdn.net/m0_37302966/article/details/141636064

相关文章

  • Day09_0.1基础学习MATLAB学习小技巧总结(9)——数组运算
    利用空闲时间把碎片化的MATLAB知识重新系统的学习一遍,为了在这个过程中加深印象,也为了能够有所足迹,我会把自己的学习总结发在专栏中,以便学习交流。素材来源“数学建模清风”特此说明:本博客的内容只在于总结在使用matlab中的一些小技巧,并非教程,若想系统的学习MATLAB,也可以移步......
  • Day07_0.1基础学习MATLAB学习小技巧总结(7)——矩阵算数运算
    利用暑假的时间把碎片化的MATLAB知识重新系统的学习一遍,为了在这个过程中加深印象,也为了能够有所足迹,我会把自己的学习总结发在专栏中,以便学习交流。素材来源“数学建模清风”特此说明:本博客的内容只在于总结在使用matlab中的一些小技巧,并非教程,若想系统的学习MATLAB,也可以移......
  • SciTech-Mathmatics-Probability+Statistics: How to Read and Interpret a Regressio
    HowtoReadandInterpretaRegressionTableBYZACHBOBBITTPOSTEDONMARCH20,2019https://www.statology.org/read-interpret-regression-table/Instatistics,regressionisatechniquethatcanbeusedtoanalyzetherelationshipbetweenpredictorvariabl......
  • Yololov5+Pyqt5+Opencv 实时城市积水报警系统
    在现代城市生活中,积水问题不仅影响交通和人们的日常生活,还可能对城市基础设施造成潜在的威胁。为了快速、准确地识别和应对积水问题,使用计算机视觉技术进行智能积水检测成为一个重要的解决方案。在这篇博客中,我将带你一步步实现一个基于YOLOv5的积水检测系统,帮助你轻松应对城市......
  • OpenCV(cv::circle())
    目录1.函数2.示例3.说明4.使用场景cv::circle()是OpenCV提供的一个函数,用于在图像上绘制圆形。它非常适用于在图像处理任务中标记特定的点或区域。这个函数具有多种参数,允许你根据需要控制圆的颜色、位置、半径和边界厚度。1.函数voidcv::circle(InputOutputArrayi......
  • 【表面肌电信号SEMG】带通滤波时域和频域特征分析【含Matlab源码 7348期】
    ✅博主简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,Matlab项目合作可私信或扫描文章底部QQ二维码。......
  • 【图像分割】复合粒子群算法CPSOGSA图像多级阈值分割【含Matlab源码 7349期】
    ✅博主简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,Matlab项目合作可私信或扫描文章底部QQ二维码。......
  • C# BinaryFormatter Serialize and Deserialize
    usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Linq;usingSystem.Runtime.Serialization.Formatters.Binary;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Windows;usingSystem.Windows.Controls;usingSystem.Wi......
  • Journal of Information and Computing 编委会邀请函
    各位计算机领域的老师,我谨代表出版商郑重邀请您成为学术期刊JournalofInformationandComputing编委会成员。编委会福利:1.提供正式的聘书,以便确认、感谢您的学术贡献。2.免费提供在本刊发表论文、评论或出版特刊的机会,更好展现学术影响力。3.编委来稿优先进入评议和审......
  • [QT]QSharedMemory读写cv::Mat
    1.写入共享内存voidWriteMat(constchar*section,constcv::Mat&img){QSharedMemory*mem=newQSharedMemory();mem->setKey(section);intsize=img.cols*img.rows*img.channels();//cols+rows+channels+data//ifexistreturn......