前言
Mat 类是OpenCV中的一个基本数据类型,它是一个n维密集数组类
Mat 类表示一个 n 维密集数值单通道或多通道数组。它可用于存储实数或复值向量和矩阵、灰度或彩色图像、体素体积、向量场、点云、张量、直方图。本文将总结几种遍历像素的不同方法,在需要处理大量图片的场景,不同的遍历方法,速度上会有显著差异。
一、Mat数据类型
Mat包含两个数据部分的类:矩阵头(包含诸如矩阵大小,用于存储的方法,存储的矩阵地址等信息)和指向包含像素值矩阵(根据选择的存储方法而有不同的维度)的指针.矩阵头大小是个常量,不同大小的图像的矩阵大小各不相同,通常矩阵大小要比图像大小大几个数量级。
Mat的数据类型及取值范围
当Mat为单通道灰度图时,其在内存中的排布如下:
当Mat为多通道图像时,以3通道为例,其在内存中的排布方式如下:
通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。OpenCV中提供了 isContinuous()函数来判断图像数组是否为连续的。
二、Mat数据的遍历方法
1.数组遍历法
代码如下:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src = imread("./2.png",0);
int width = src.cols;
int height = src.rows;
//单通道
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
src.data[i * width + j]+=50;
}
}
//三通道
/*for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int index = i * width + j;
src.data[3 * index + 0]+=50;
src.data[3 * index + 1]+= 50;;
src.data[3 * index + 2]+=50;
}
}
*/
imwrite("test.png", src);
return 0;
}
原图
结果图
2. at(i,j)
Mat类提供了一个at的方法用于取得图像上的点,它是一个模板函数,可以取到任何类型的图像上的点。此typename的定义如下:
测试代码如下:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src = imread("./2.png", -1);
//灰度图
if (1 == src.channels())
{
for (int y = 0; y < src.rows; y++)
{
for (int x = 0; x < src.cols; x++)
{
src.at<uchar>(y, x) = 255 - src.at<uchar>(y, x);
}
}
}
else if(3 == src.channels())
{
//彩色图
for (int y = 0; y < src.rows; y++)
{
for (int x = 0; x < src.cols; x++)
{
cv::Vec3b bgr = src.at<cv::Vec3b>(y, x);
bgr[0] = 255 - bgr[0];
bgr[1] = 255 - bgr[1];
bgr[2] = 255 - bgr[2];
src.at<cv::Vec3b>(y, x) = bgr;
}
}
}
imwrite("test.png",src);
}
原图
结果图
3、指针遍历法
利用.ptr和数组下标进行图像像素遍历,这种图像遍历方法相比“数组遍历法”更高效。
示例代码:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;