image.at(rows,cols)
image.at<T>(rows,cols)
是个模板函数[1],T代表数据类型,比如常用[4]的是image.at<Vec3b>(rows,cols)
;而查看Vec3b的定义可知Vec3b就是uchar的数组,长度为3:
typedef Vec<uchar, 3> Vec3b;
函数的输入参数rows,cols是像素坐标,以Vec3b为例,相当于在(rows,cols)
像素坐标处以Vec3b格式读取数据,其顺序为BGR,函数的返回值为uchar类型,使用以下代码可以分别读取第0行第1列的B、G、R值
uchar i00 = image.at<Vec3b>(0, 1)[0]; //B
uchar i01 = image.at<Vec3b>(0, 1)[1]; //G
uchar i02 = image.at<Vec3b>(0, 1)[2]; //R
那么如果是灰度图[2]的话,只有一个通道,就可以用image.at<uchar>(rows,cols)
来访问
mat像素值的连续存储
对于下面这句代码
uchar i03 = image.at<Vec3b>(0, 1)[5]; //
Vec3b长度为3,[5]已经越界,调试运行()遇到错误提示后,点击继续还能看到i3被赋值,是因为OpenCV内部存储每一行像素数据以及像素内部通道数据都是连续存储的[3],实际读取的为image.at(0, 2)[2]。
但是行与行的数据并不一定是连续存储的,所以不能应用在行与行之间。
实例
代码如下
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
Mat image = imread(".\\images\\000.png");
uchar i00 = image.at<Vec3b>(0, 1)[0]; //B
uchar i01 = image.at<Vec3b>(0, 1)[1]; //G
uchar i02 = image.at<Vec3b>(0, 1)[2]; //R
uchar i03 = image.at<Vec3b>(0, 1)[5]; //
uchar i10 = image.at<Vec3b>(0, 2)[0]; //B
uchar i11 = image.at<Vec3b>(0, 2)[1]; //G
uchar i12 = image.at<Vec3b>(0, 2)[2]; //R
Mat image2;
cv::cvtColor(image, image2, cv::COLOR_BGR2GRAY);
uchar gray00 = image2.at<uchar>(0, 0); //
uchar gray01 = image2.at<uchar>(0, 1); //
uchar gray02 = image2.at<uchar>(0, 2); //
system("pause");
return 0;
}
在system(“pause”);这里加个断点,调试运行遇到异常点击继续
可以看到image.at<Vec3b>(0, 1)[5];
其实读取的是image.at<Vec3b>(0, 2)[2];
的值
,证明了RGB像素值的连续存储
用image.at<uchar>(rows,cols)
来访问灰度图的单通道
参考
[1]. Opencv之Vec3b是什么东东
[2]. OpenCV图像处理入门即巅峰:Mat的使用(灰度转换)
[3]. OpenCV之imread解析
[4]. opencv像素基本操作及图像遍历at
完
如有错漏,敬请指正
--------------------------------------------------------------------------------------------诺有缸的高飞鸟202104