OPENCV_Mat类存取方法(元素访问)
opencv mat 用法

opencv mat 用法OpenCV是一个广泛使用的计算机视觉库,它提供了许多功能和工具,用于图像处理、视频处理、特征提取等任务。
在OpenCV中,Mat 是一个非常重要的数据结构,用于存储和操作图像数据。
在本篇文章中,我们将介绍Mat的基本用法,包括创建、读取、写入和操作图像数据。
一、Mat的创建在使用Mat之前,需要先创建它。
OpenCV提供了多种方法来创建Mat对象,可以根据需要选择合适的方法。
常用的创建Mat的方法包括:1.使用zeros()或ones()函数创建指定尺寸的零矩阵或全矩阵。
2.使用imread()函数从文件中加载图像,并将其存储为Mat对象。
3.使用随机数生成器创建具有一定分布的图像数据。
下面是一个简单的示例代码,演示如何使用imread()函数创建Mat对象:```pythonimportcv2#读取图像并创建Mat对象img=cv2.imread('image.jpg')#显示图像cv2.imshow('Image',img)cv2.waitKey(0)```二、Mat的读取和写入使用imread()函数可以从文件中加载图像数据并将其存储为Mat 对象。
同样地,使用imwrite()函数可以将Mat对象中的数据写入文件。
下面是一个简单的示例代码,演示如何使用imwrite()函数将Mat 对象中的数据写入文件:```pythonimportcv2importnumpyasnp#创建一个随机图像数据data=np.random.randint(0,256,(500,500,3),dtype=np.uint8) #创建Mat对象并设置数据mat=cv2.Mat(500,500,CV_8UC3,data)#显示Mat对象的内容cv2.imshow('Mat',mat)cv2.waitKey(0)#将Mat对象写入文件cv2.imwrite('output.jpg',mat)```三、Mat的数据类型和尺寸Mat对象可以存储不同类型的数据,包括单通道和多通道数据。
OpenCV:Mat元素访问方法、性能、代码复杂度以及安全性分析

OpenCV:Mat元素访问方法、性能、代码复杂度以及安全性分析欢迎转载,尊重原创,所以转载请注明出处:/bendanban/article/details/30527785本文讲述了OpenCV中几种访问矩阵元素的方法,在指定平台上给出性能比较,分析每种矩阵元素访问方法的代码复杂度,易用性。
一、预备设置本文假设你已经正确配置了OpenCV的环境,为方便大家实验,在文中也给出了编译源程序的Makefile,其内容如代码段1所示。
采用如代码段2所示的计时函数,这段代码你可以在我之前的博文中找到,abtic() 可以返回微秒(10^-6秒)级,而且兼容Windows和Linux系统。
本文使用彩色图像做实验,所以矩阵是2维的3通道的。
[plain]view plaincopy = g++2.CPPFLAGS = -O3 `pkg-config --cflags opencv`3.CPPLIB = `pkg-config --libs opencv`4.5.OBJS = test.o6.7.main.exe : $(OBJS)8. $(CC) $(CPPFLAGS) $^ -o $@ $(CPPLIB)9.10.test.o: test.cpp11. $(CC) -c $(CPPFLAGS) $^ -o $@12.13.clean:14. rm -rf *.out main.exe *.o15.16.run:17. ./main.exe文件的内容[cpp]view plaincopy1.#if defined(_WIN32) && defined(_MSC_VER)2.#include <windows.h>3.double abtic() {4.__int64 freq;5.__int64 clock;6. QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );7. QueryPerformanceCounter( (LARGE_INTEGER *)&clock );8.return (double)clock/freq*1000*1000;9.}10.#else11.#include <time.h>12.#include <sys/time.h>13.double abtic() {14.double result = 0.0;15.struct timeval tv;16. gettimeofday( &tv, NULL );17. result = _sec*1000*1000 + _usec;18.return result;19.}20.#endif /* _WIN32 */abtic()的定义二、测试算法文中用于测试的算法:将矩阵中每个元素乘以一个标量,写入一个新的矩阵,每个通道操作独立。
open cv中的Mat详解

通常比矩阵头的尺寸大数个数量级。因此,当在程序中传递图像并创建拷贝时,大的开销 是由矩阵造成的,而不是信息头。OpenCV 是一个图像处理库,囊括了大量的图像处理函数, 为了解决问题通常要使用库中的多个函数,因此在函数中传递图像是家常便饭。同时不要忘 了我们正在讨论的是计算量很大的图像处理算法,因此,除非万不得已,我们不应该拷 贝 大 的图像,因为这会降低程序速度。 二、Mat 的基本操作
如果想建立互不影响的 Mat,是真正的复制操作,需要使用函数 clone()或者 copyTo()。
说到数据的存储,这一直就是一个值得关注的问题,Mat_<uchar>对应的是 CV_8U, Mat_<uchar>对应的是 CV_8U,Mat_<char>对应的是 CV_8S,Mat_<int>对应的是 CV_32S, Mat_<float>对应的是 CV_32F,Mat_<double>对应的是 CV_64F,对应的数据深度如下:
需要注意的是,copy 这样的操作只是 copy 了矩阵的 matrix header 和那个指针,而不是矩 阵的本身,也就意味着两个矩阵的数据指针指向的是同一个地址,需要开发者格外注意。比 如上面这段程序,A、B、C 指向的是同一块数据,他们的 header 不同,但对于 A 的操作 同样也影响着 B、C 的结果。刚刚提高了内存自动释放的问题,那么当我不再使用 A 的时 候就把内存释放了,那时候再操作 B 和 C 岂不是很危险。不用担心,OpenCV 的大神为我 们已经考虑了这个问题,是在最后一个 Mat 不再使用的时候才会释放内存,咱们就放心用 就行了。
在 2001 年刚刚出现的时候,OpenCV 基于 C 语言接口而建。为了在内存(memory) 中存放图像,当时采用名为 IplImage 的 C 语言结构体,时至今日这仍出现在大多数的旧 版教程和教学材料。但这种方法必须接受 C 语言所有的不足,这其中最大的不足要数手动内 存管理,其依据是用户要为开辟和销毁内存负责。虽然对于小型的程序来说手动管理内 一、Mat 简介
opencv中Mat格式的数据访问.at

opencv中Mat格式的数据访问.atopencv3中图形存储基本为Mat格式,如果我们想获取像素点的灰度值或者RGB值,可以通过image.at<uchar>(i,j)的⽅式轻松获取。
Mat类中的at⽅法对于获取图像矩阵某点的RGB值或者改变某点的值很⽅便,对于单通道的图像,则可以使⽤:image.at<uchar>(i, j)其中有⼀个要注意的地⽅是i对应的是点的y坐标,j对应的是点的x坐标,⽽不是我们习惯的(x,y)来获取或改变该点的值,⽽RGB通道的则可以使⽤:image.at<Vec3b>(i, j)[0]image.at<Vec3b>(i, j)[1]image.at<Vec3b>(i, j)[2]来分别获取B、G、R三个通道的对应的值。
下边的代码实现对图像加椒盐噪声:// created by ning zhang 2018/4/25// The function of this program is to add noise to the image#include <opencv2/opencv.hpp>#include <iostream>using namespace std;using namespace cv;void salt_noise( Mat image, int time );int main ( int argc, char** argv ){Mat image = imread("../lena.jpg",0); //input the gray imageif ( image.empty() ){cout << "Load image error" << endl;return -1;}salt_noise(image, 3000);namedWindow("image", 1);imshow("image", image);waitKey();return 0;}void salt_noise ( Mat image, int time ){for (int k = 0; k < time; k++ ) //time is the number of noise you add{int i = rand() % image.rows;int j = rand() % image.cols;if (image.channels() == 1) //single channel{image.at<uchar>(i,j) = rand() % 255;}else if (image.channels() == 3) //RGB channel{image.at<Vec3b>(i, j)[0] = rand() % 255;image.at<Vec3b>(i, j)[1] = rand() % 255;image.at<Vec3b>(i, j)[2] = rand() % 255;}}}效果图如下所⽰,可以为图⽚增加噪点还有⽐较省时的⽅法使⽤Mat的模板⼦类Mat_<T>,,对于单通道的具体使⽤:Mat_<uchar> img = image;img(i, j) = rand() % 255;对于RGB通道的使⽤:Mat_<Vec3b> img = image;img(i, j)[0] = rand() % 255;img(i, j)[1] = rand() % 255;mg(i, j)[2] = rand() % 255;还可以⽤指针的⽅法遍历每⼀像素:(耗时较⼩)void colorReduce(Mat image, int div = 64){int nrow = image.rows;int ncol = image.cols*image.channels();for (int i = 0; i < nrow; i++){uchar* data = image.ptr<uchar>(i);//get the address of row i;for (int j = 0; j < ncol; j++){data[i] = (data[i] / div)*div ;}}}我们要尤其注意OpenCV坐标系与row&col的关系 (Mat::at(x,y)和Mat::at(Point(x, y))的区别)直接给出对应关系吧row == heigh == Point.ycol == width == Point.xMat::at(Point(x, y)) == Mat::at(y,x)因为还有点的坐标,所以建议在访问时都⽤Mat::at(Point(x, y))这种形式吧,免去了点坐标和⾏列的转换详细说明:1. 坐标体系中的零点坐标为图⽚的左上⾓,X轴为图像矩形的上⾯那条⽔平线;Y轴为图像矩形左边的那条垂直线。
OPENCV对于Mat的理解和操作

OPENCV对于Mat的理解和操作1,Mat 是⽤来存储图⽚的数据他会把图⽚变成矩阵Mat src;int main(int argc, char** argv){src = imread("F:\\视觉\\opencv\\pic\\MatTest.png");//读图⽚cout << "灰度化后" << endl;cout << src << endl;}矩阵的格式如下图⽚时这样的:⽤dos显⽰是这样的灰度化之后是这样的怎么样是不是看上去有点熟悉没错,灰度化后直接把每个位置的像素的值,组成⼀个矩阵,⽽没有灰度化时是如图⼀所⽰。
2,Mat获取某⼀点坐标的值cout << (int)src.ptr<uchar>(1)[1] << endl;锐化的案例:int cols = (src.cols-1)*src.channels();int rows = src.rows;int channels = src.channels();int offsetx = src.channels();Mat dst1 = Mat::zeros(src.size(), src.type());for (int row = 1; row < (rows - 1); row++){const uchar* previous = src.ptr<uchar>(row - 1);const uchar* current = src.ptr<uchar>(row);const uchar* next = src.ptr<uchar>(row + 1);uchar* output = dst1.ptr<uchar>(row);for (int col = offsetx; col < cols; col++) {output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col])); }}imshow("锐化转化后", dst1);src.ptr<uchar>(row);是获取第⼏⾏的指针src.ptr<uchar>(1)[1];默认是char类型,所以要转成int类型输出才能看得到,不然会输出Hex码表对于的字符信息。
open cv中的Mat详解

分类: OpenCV2011-12-28 10:33 26348 人阅读 评论(16) 收藏 举报 数据结构 matrixheadernumbers 存储 matlab
我记得开始接触 OpenCV 就是因为一个算法里面需要 2 维动态数组,那时候看 core 这部分 也算是走马观花吧,随着使用的增多,对 Mat 这个结构越来越喜爱,也觉得有必要温故而 知新,于是这次再看看 Mat。
在 2001 年刚刚出现的时候,OpenCV 基于 C 语言接口而建。为了在内存(memory) 中存放图像,当时采用名为 IplImage 的 C 语言结构体,时至今日这仍出现在大多数的旧 版教程和教学材料。但这种方法必须接受 C 语言所有的不足,这其中最大的不足要数手动内 存管理,其依据是用户要为开辟和销毁内存负责。虽然对于小型的程序来说手动管理内 一、Mat 简介
亲,有木有很简单!!!
还有一种快速初始化数据的办法,如下:
[cpp] view plaincopy
1.double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}}; 2.Mat M = Mat(3, 3, CV_64F, m).inv();
也可以把原来的 IplImage 格式的图片直接用 Mat(IplImage)的方式转成 Mat 结构,也可 以像 Matlab 一样调用 zeros()、ones()、eye()这样的函数进行初始化。
幸运的是,C++出现了,并且带来类的概念,这给用户带来另外一个选择:自动的内存 管理(不严谨地说)。这是一个好消息,如果 C++完全兼容 C 的话,这个变化不会带来兼容 性问题。为此,OpenCV 在 2.0 版本中引入了一个新的 C++接口,利用自动内存管理给出了解 决问题的新方法。使用这个方法,你不需要纠结在管理内存上,而且你的代码会变得简洁(少 写多得)。但 C++接口唯一的不足是当前许多嵌入式开发系统只支持 C 语言。所以,当目标 不是这种开发平台时,没有必要使用 旧 方法(除非你是自找麻烦的受虐狂码农)。
opencv-访问Mat中每个像素的值

opencv-访问Mat中每个像素的值参考:膜拜⼤佬以下例⼦代码均针对8位单通道灰度图。
1 .ptr和[]操作符Mat最直接的访问⽅法是通过.ptr<>函数得到⼀⾏的指针,并⽤[]操作符访问某⼀列的像素值。
Mat image(rows,cols,CV_8UC1);for (int j=0; j<image.rows; j++){uchar* pdata= image.ptr<uchar>(j);for (int i=0; i<image.cols; i++){uchar data=pdata[i];}}2 .ptr和指针操作除了[]操作符,我们可以使⽤移动指针*++的组合⽅法访问某⼀⾏中所有像素的值。
Mat image(rows,cols,CV_8UC1);for (int j=0; j<image.rows; j++){uchar* pdata= image.ptr<uchar>(j);for (int i=0; i<image.cols; i++){uchar data=*pdata++;}}3 Mat _iterator⽤Mat提供的迭代器代替前⾯的[]操作符或指针,⾎统纯正的官⽅⽅法~1 Mat image(rows,cols,CV_8UC1);23 Mat_<uchar>::iterator it=image.begin<uchar>();4 Mat_<uchar>::iterator itend=image.end<uchar>();56for (;it != itend;++it)7 {8 uchar data=*it;9 }4 图像坐标 atMat image(rows,cols,CV_8UC1);for (int j=0; j<image.rows; j++){for (int i=0; i<image.cols; i++){uchar data=image.at<uchar>(j,i);}}其中,指针*++访问是最快的⽅法;另外迭代器访问虽然安全,但性能远低于指针运算;通过图像坐标(j,i)访问是最慢的。
OpenCV中对Mat的遍历访问与赋值

OpenCV中对Mat的遍历访问与赋值⼀、访问对于Mat的访问有两种⽅式第⼀种,利⽤Mat::at进⾏访问//读取3通道彩⾊图像Mat img = imread("图⽚地址");int px;//读取图像中第⼀⾏第⼀列,Blue通道数据int px = img.at<Vec3b>(0, 0)[0];第⼆种,利⽤Mat的成员ptr指针进⾏访问//读取3通道彩⾊图像Mat img = imread("图⽚地址");//将Mat中的第⼀⾏地址赋予pxVecuchar* pxVec=img.ptr<uchar>(0);//遍历访问Mat中各个像素值int i, j;int px;for (i = 0; i < img.rows; i++){pxvec = img.ptr<uchar>(i);//三通道数据都在第⼀⾏依次排列,按照BGR顺序//依次赋值为1for (j = 0; j < img.cols*img.channels(); j++){px=pxvec[j];//do anything}}⼆、赋值不能⽤Mat::at进⾏赋值,只能⽤ptr对Mat中的像素点进⾏赋值⼀个完整的例⼦如下:#include "stdafx.h"#include <opencv2\core\core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2\imgproc\imgproc.hpp>#include <vector>int main(){//对Mat进⾏遍历赋值//初始化Mat数据结构,256*256,三通道8位(256⾊)图像Mat myimg(256,256,CV_8UC3);//取像素数据⾸地址uchar* pxvec = myimg.ptr<uchar>(0);int i, j;for (i = 0; i < myimg.rows; i++){pxvec = myimg.ptr<uchar>(i);//三通道数据都在第⼀⾏依次排列,按照BGR顺序//依次赋值为1for (j = 0; j < myimg.cols*myimg.channels(); j++){pxvec[j] = 1;}}//展⽰图像imshow("abc", myimg); waitKey(10000);}结果如下:。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Opencv----Mat类∙cv::Mat∙depth/dims/channels/step/data/elemSizeMat矩阵中数据元素的地址计算公式:addr(M i0,i1,…i m-1) = M.data + M.step[0] * i0 + M.step[1] * i1+ … + M.step[m-1] * i m-1。
其中m = M.dims 是指M的维度i.data:Mat对象中的一个指针,指向内存中存放矩阵数据的一块内存(uchar*data).ii.row: 行;col:列;rows:行数;cols:列数。
iii.dims :Mat所代表的矩阵的维度,如3 * 4 的矩阵为2 维,3 * 4 * 5 的为3维. iv.channels:通道,矩阵中的每一个矩阵元素拥有的值的个数,比如说3 * 4 矩阵中一共12 个元素,如果每个元素有三个值,那么就说这个矩阵是3 通道的,即channels = 3。
常见的是一张彩色图片有红、绿、蓝三个通道。
但是opencv用imread(opencv读图的函数)读进来的图像,三通道存放顺序为B、G、R。
v.depth:深度,即每一个像素的位数(bits),在opencv的Mat.depth()中得到的是一个0 –6 的数字,分别代表不同的位数:enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };可见0和1都代表8位,2和3都代表16位,4和5代表32位,6代表64位;vi.step:是一个数组,定义了矩阵的布局,具体见下面图片分析,另外注意step1(step / elemSize1),M.step[m-1] 总是等于elemSize,M.step1(i)返回的是第i 维的步长,因此M.step1(m-1)总是等于channels,m是M的维度;这里是解释步长step[k]的,步长也可以看作是与第k维的存储单位,在2维的矩阵中,因为存储是按照行的顺序存储的,整个矩阵存储为一个平面,所以第k=0维的步长也就是单位肯定就是一行所占的字节数;如果是3维的话,第0维是按照面为单位来存储的,第1维是按照行为单位来存储的,第2维是按照元素类型为单位存储的,每个元素类型是基本类型(即uchar,float,short等等)与通道数的乘积...;也就是基本数据类型与通道数组成元素,多个元素组成了行,多行组成了面,多个面组成了3维体,多个3维体组成4维超体。
以此类推,如此看来某一维的步长应该等于高一维的步长step*低一维的大小size 。
vii.elemSize : 矩阵中每一个元素的数据大小,如果是n通道,就是(n*数据类型)。
如果Mat中的数据的数据类型是CV_8U 那么elemSize = 1,CV_8UC3 那么elemSize = 3,CV_16UC2 那么elemSize = 4;记住另外有个elemSize1 表示的是矩阵中数据类型的大小,即elemSize / channels 的大小。
图片分析1:考虑二维情况(stored row by row)按行存储上面是一个3 X 4 的矩阵,假设其数据类型为CV_8U,也就是单通道的uchar 类型∙这是一个二维矩阵,那么维度为2 (M.dims == 2);∙M.rows == 3; M.cols == 4;∙sizeof(uchar) = 1,那么每一个数据元素大小为1 (M.elemSize() == 1, M.elemSize1() == 1);∙CV_8U 得到M.depth() == 0, M.channels() == 1;∙因为是二维矩阵,那么step 数组只有两个值,step[0] 和step[1] 分别代表一行的数据大小和一个元素的数据大小,则M.step[0] == 4, M.step[1] == 1;∙M.step1(0) == M.cols = 4; M.step1(1) == 1;假设上面的矩阵数据类型是CV_8UC3,也就是三通道∙M.dims == 2;M.channels() == 3;M.depth() == 0;∙M.elemSize() == 3 (每一个元素包含3个uchar值)M.elemSize1() == 1 (elemSize / channels)∙M.step[0] == M.cols * M.elemSize() == 12, M.step[1] == M.channels() *M.elemSize1() == M.elemSize() == 3;∙M.step(0) == M.cols * M.channels() == 12 ; M.step(1) == M.channels() == 3;图片分析2:考虑三维情况(stored plane by plane)按面存储上面是一个3 X 4 X 6 的矩阵,假设其数据类型为CV_16SC4,也就是short 类型∙M.dims == 3 ; M.channels() == 4 ; M.elemSize1() == sizeof(short) == 2 ;∙M.rows == M.cols == –1;∙M.elemSize() == M.elemSize1() * M.channels() == M.step[M.dims-1] == M.step[2] == 2 * 4 == 8;∙M.step[0] == 4 * 6 * M.elemSize() == 192;∙M.step[1] == 6 * M.elemSize() == 48;∙M.step[2] == M.elemSize() == 8;∙M.step1(0) == M.step[0] / M.elemSize() == 48 / 2 == 96 (第一维度(即面的元素个数) * 通道数);∙M.step1(1) == M.step[1] / M.elemSize() == 12 / 2 == 24(第二维度(即行的元素个数/列宽) * 通道数);∙M.step1(2) == M.step[2] / M.elemSize() == M.channels() == 4(第三维度(即元素) * 通道数);End以上为Mat的存放形式以下为Mat的一些操作方法具体使用方法Fn 1 :利用step。
Code 1:int main(){//新建一个uchar类型的单通道矩阵(grayscale image 灰度图)Mat m(400, 400, CV_8U, Scalar(0));for (int col = 0; col < 400; col++){for (int row = 195; row < 205; row++){//获取第[row,col]个像素点的地址并用 * 符号解析*(m.data + m.step[0] * row + m.step[1] * col) = 255;}}imshow("canvas", m);cvWaitKey();return 0;}Output 1 :Code1只是演示了单通道的情况,对于多通道的例子,请看Code2 然后再看Code3。
Fn 2 :使用Mat::at 函数∙原型template<typename _Tp> inline _Tp& Mat::at(…) //其中参数有多个,也就是说at 函数有多个重载∙返回值为Mat 类型, Mat 有个索引的重载,也就是[] 符号的重载,用这个重载可以定位多通道数据,具体示例可以看下面代码。
下面的代码把红色通道值大于128的颜色的置为白色,左边为原图,右边为处理过后的图。
Code 2 :int main(){Mat img = imread("lena.jpg");imshow("Lena Original", img);for (int row = 0; row < img.rows; row++){for (int col = 0; col < img.cols; col++){/* 注意 Mat::at 函数是个模板函数, 需要指明参数类型, 因为这张图是具有红蓝绿三通道的图,所以它的参数类型可以传递一个 Vec3b, 这是一个存放 3 个 uchar 数据的Vec(向量). 这里提供了索引重载, [2]表示的是返回第三个通道, 在这里是 Red 通道, 第一个通道(Blue)用[0]返回 */if(img.at<Vec3b>(row, col)[2] > 128)img.at<Vec3b>(row, col) = Vec3b(255, 255, 255);}}imshow("Lena Modified", img);cvWaitKey();return 0;}Output 2 :Code 3 :这段代码用的是Fn1 的方式,效果和Code 2 等价,不过是处理三通道数据而已:int main(){Mat img = imread("lena.jpg");imshow("Lena Original", img);for (int row = 0; row < img.rows; row++){for (int col = 0; col < img.cols; col++){//主要是这里的代码if(*(img.data + img.step[0] * row + img.step[1] * col + img.elemSize1() * 2) > 128){//[row, col]像素的第 1 通道地址被 * 解析(blue通道)*(img.data + img.step[0] * row + img.step[1] * col) = 255;//[row, col]像素的第 2 通道地址被 * 解析(green通道), 关于elemSize1函数的更多描述请见 Fn1 里所列的博文链接*(img.data + img.step[0] * row + img.step[1] * col +img.elemSize1()) = 255;//[row, col]像素的第 3 通道地址被 * 解析(red通道)*(img.data + img.step[0] * row + img.step[1] * col +img.elemSize1() * 2) = 255;}}}imshow("Lena Modified", img);cvWaitKey();return 0;}Output 3 = Output 2Fn 3 :使用Mat 的一个模板子类Mat_<typename _Tp> 的( ) 符号重载定位一个像素Code 4 :int main(){Mat m(400, 400, CV_8UC3, Scalar(255, 255, 255));// m2 是 Mat_<Vec3b> 类型的, 因为 m 中元素的类型是 CV_8UC3, 可以用 Vec3b 存储 3 个通道的值// 注意 Mat_<CV_8UC3> 这种写法是错误的, 因为 CV_8UC3 只是一个宏定义// #define CV_8UC3 CV_MAKETYPE(CV_8U, 3)Mat_<Vec3b> m2 = m;// for 循环画一个红色的实心圆for (int y = 0; y < m.rows; y++){for (int x = 0; x < m.rows; x++){if (pow(double(x-200), 2) + pow(double(y-200), 2) - 10000.0 < 0.00000000001){// Mat_ 模板类实现了对()的重载, 可以定位到一个像素m2(x, y) = Vec3b(0, 0, 255);}}}imshow("Image", m);cvWaitKey();return 0;}Output 4 :[ 看上去怎么有点不爽]Fn 4 :使用Mat::ptr 模板函数Code 5 :int main(){Mat m(400, 400, CV_8UC3, Scalar(226, 46, 166)); imshow("Before", m);for (int row = 0; row < m.rows; row++){if (row % 5 == 0){// data 是 uchar* 类型的, m.ptr<uchar>(row) 返回第 row 行数据的首地址// 需要注意的是该行数据是按顺序存放的,也就是对于一个 3 通道的 Mat, 一个像素有// 有 3 个通道值, [B,G,R][B,G,R][B,G,R]... 所以一行长度为:// sizeof(uchar) * m.cols * m.channels() 个字节uchar* data = m.ptr<uchar>(row);for (int col = 0; col < m.cols; col++){data[col * 3] = 102; //第row行的第col个像素点的第一个通道值 Blue data[col * 3 + 1] = 217; // Greendata[col * 3 + 2] = 239; // Red}}}imshow("After", m);cout << (int)m.at<Vec3b>(0, 0)[0] << ','; //利用 Fn 1 介绍的方法输出一下像素值到控制台cout << (int)m.at<Vec3b>(0, 0)[1] << ',';cout << (int)m.at<Vec3b>(0, 0)[2] << endl;cvWaitKey();return 0;}Output 5 :End :Author : Ggicci谢谢阅读,有误希望指正!--OpenCV初学者。