构造函数
Mat m(3, 2, CV_8UC3, Scalar(0, 0, 255));
std::cout << m << std::endl;
创建一个行数为3,列数为2,图像元素是8位无符号整型,且有3个通道,图像所有像素值被初始化为(0,0,255)
opencv中默认的颜色顺序为BGR。使用cout输出上述m变量:
通过构造函数来创建Mat对象的方式有很多,可自行查看源代码。
matlab风格创建
Mat z = Mat::zeros(2, 3, CV_8UC1);
Mat z = Mat::ones(2, 3, CV_8UC1);
Mat z = Mat::eye(2, 3, CV_8UC1);
zeros和ones分别创建一个值为0,1的矩阵
eye创建一个单位矩阵。
对于单通道图像,矩阵的元素是基本数据类型,对于多通道图像,矩阵元素不再是一个值,可以用向量来表示:
例如8U类型的RGB彩色图像可以使用Vec3b,3通道float类型的矩阵可以使用Vec3f。
Vec3b color; //使用color变量来描述RGB颜色color[0] = 0; //B分量color[1] = 0; //G分量color[2] = 255; //R分量
像素值读写
cv::Mat img = cv::imread("C:/Users/Administrator/Desktop/fapiao.jpg");
int channel = img.channels();
Vec3b value = img.at<Vec3b>(10, 20);
Vec3b tmp(255, 255, 255);
img.at<Vec3b>(10, 20)= tmp;
通过at函数可以读取和设置图片的像素值
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{cv::Mat img = cv::imread("C:/Users/Administrator/Desktop/fapiao.jpg");for (int i = 0; i < img.rows; i++){for (int j = 0; j < img.cols; j++){Vec3b pixel;pixel[0] = i % 255; //Bluepixel[1] = j % 255; //Greenpixel[2] = 0; //Redimg.at<Vec3b>(i, j) = pixel;}}cv::imshow("image", img);cv::waitKey(0);return 0;
}
遍历图像,不推荐使用at函数,该函数效率较低。
for (MatIterator_<Vec3b> it = img.begin<Vec3b>(); it != img.end<Vec3b>(); it++){it[0] = 255;it[1] = 255;it[2] = 222;}
上述为通过迭代器进行遍历修改。
for (int i = 0; i < img.rows; i++){//获取第 i 行首像素指针Vec3b* p = img.ptr<Vec3b>(i);for (int j = 0; j < img.cols; j++){p[j][0] = 222;//bp[j][1] = 222;//gp[j][2] = 222;//r}}
上述为通过指针对图片进行读取修改,该种方式效率较高
选取图像部分区域
Mat类提供了很多方法来选取图像的部分区域,需要注意的是,这些方法并不申请新的内存空间,而是与原对象共享内存空间,因此执行效率高。
Mat mat = Mat::eye(6, 6, CV_32S);
Mat matr = mat.row(1);
Mat matc = mat.col(2);
row或者col获取Mat的某一行或者某一列
Mat mat = Mat::eye(6, 6, CV_32S);
Mat matb = mat(Range::all(),Range(0,3));
使用range获取行或者列某个范围,Range::all()表示所有
Mat mat = Mat::eye(6, 6, CV_32S);
Mat mata = mat.diag(1);
diag用于获取对角线元素
0:获取主对角线
大于0:主对角线下方元素
小于0:主对角线上方元素
Mat_
Mat_类继承自Mat类,可以用于简化Mat类读写像素值时每次都需要写模板类型。
Mat m = Mat::eye(3, 3, CV_8UC1);
Mat_<uchar> m_ = (Mat_<uchar>)m;
for (int i = 0; i < m.rows; i++)
{uchar* p = m_.ptr(i);for (int j = 0; j < m.cols; j++){double tmp = (i + j) % 255;m_(i, j) = tmp;}
}
Mat内存管理
mat类实际用于存放矩阵数据的是一个uchar类型的data指针,为了节约内存,data采用引用计数的方式进行管理,就类似于智能指针。
Mat a(100, 100, CV_8UC1);
Mat b = a;
Mat c = a(Rect(50, 60, 40, 40));
矩阵头存储Mat类基本信息,包括行数,列数,通道数等,上面abc三个mat对象有各自的矩阵头,但是共享矩阵数据内存。