OpenCV4的Mat类详解,创建,赋值,元素的读取,运算

图像在计算机中是如何存储的,在计算机中保存图像的流行格式-灰度和RGB格式,图像的最小单位是像素,描述一张图我们通常所说的x*y,意味着图像的尺寸就是图像的高度(x)和宽度(y)上的像素数,所以计算机中每个图像都以 数字矩阵 的形式保存;

1、什么是 Mat类:
Mat类 结构:Mat类可以分为两个部分,矩阵头 和 数据;

Mat类

|—— 矩阵头

| |——尺寸

| |——行数

| |—— 列数

| |—— 数据类型

| |—— 通道数

| |—— 引用次数

|—— 数据

请添加图片描述

2、Mat 类中能存储什么类型的数据:
(1) cv::Mat_< _TP >		可以存储,自定义数据类型
(2) cv::Mat_< double >		可以存储,double 类型数据
(3) cv::Mat_< float >		可以存储,float 类型数据
(4) cv::Mat_< uchar >		可以存储,uchar 类型数据
(5) cv::Mat_< unsigned char >	可以存储,unsigned char 类型数据
opencv 中规定的数据类型:
数据类型具体类型取值范围
CV_8U8位无符号整数0 ~ 255
CV_8S8位符号整数-128 ~ 127
CV_16U16位无符号整数0 ~ 65535
CV_16S16位符号整数-32768 ~ 32767
CV_32S32位符号整数-2147483648 ~ 2147483647
CV_32F32位浮点整数-FLT_MAX ~ FLT_MAX,INF,NAN
CV_64F64位浮点整数-DBL_MAX ~ DBL_MAX,INF,NAN
3、Mat类 的创建
(1)使用默认构造函数 Mat() 创建Mat 类:
  • 构造函数原型:Mat()
  • 示例:实例化一个Mat矩阵
    Mat img;					// 声明一个保存图像的类
    img = imread("C:\\cpp\\vs\\suzy.jpg");		// 读取图像
    
(2)利用矩阵 宽,高,和数据类型,创建Mat 类:
  • 构造函数原型:Mat(int rows, int cols, int type)

    rows:构造矩阵的行数;
    cols:构造矩阵的列数;
    type:矩阵中存储的数据类型,CV_8U定义通道1~4,可以写成CV_8UC1 ~ CV_8UC4,通道数大于4,要这样写CV_8UC(n),n最大值512;
    
  • 示例:实例化一个,3行3列,单通道的Mat矩阵

    Mat a(3, 3, CV_8UC1);
    
    
(3)利用矩阵 Size()结构,和数据类型,创建Mat 类:
  • 构造函数原型:Mat(Size size, int type)
    size:2D数组变量尺寸,通过Size(rows, cols)赋值,rows:构造矩阵的行数,cols:构造矩阵的列数;
    type:矩阵中存储的数据类型,CV_8U定义通道1~4,可以写成CV_8UC1 ~ CV_8UC4,通道数大于4,要这样写CV_8UC(n),n最大值512;
    
    
  • 示例:实例化一个,4行4列,单通道的Mat矩阵
    Mat b(Size(4, 4), CV_8UC1);
    
(4)利用已有Mat类,创建新的Mat 类:
  • 构造函数原型:Mat ( const Mat &m, const Range &rowRange, const Range &colRange=Range::all() )

    m:已经构造完成的Mat类矩阵数据;
    rowRange:在已有矩阵 m 中,需要截取的行数范围,是一个Range变量,例如从第2行到第5行可以表示为Range(2, 5);
    colRange:在已有矩阵 m 中,需要截取的列数范围,是一个Range变量,例如从第2列到第5列可以表示为Range(2, 5),当不输入任何值时表示所有列都会被截取;
    
    
  • 示例:创建一个2行4列的,单通道的Mat矩阵

    // 创建一个6行6列,单通道的Mat矩阵
    Mat a(6, 6, CV_8UC1);
    // 利用已有m矩阵,创建新的n矩阵
    Mat n = Mat(m, Range(2, 4), Range(2, 4));
    
    
4、Mat类 的赋值
(1)使用默认构造函数 Mat() 创建Mat 类:
  • 构造函数原型:Mat()
  • 示例:实例化一个Mat矩阵,并赋值
    Mat img = imread("C:\\cpp\\vs\\suzy.jpg");
    
    
(2)利用矩阵 宽,高,和数据类型,创建Mat 类,并赋值:
  • 构造函数原型:Mat(int rows, int cols, int type, const Scalar &s)

    rows:构造矩阵的行数;
    cols:构造矩阵的列数;
    type:矩阵中存储的数据类型;
    s:给矩阵中每个像素赋值的参数变量,例如Scalar(0, 0, 255)
    
  • 示例:

    Mat c0(5, 5, CV_8UC1, Scalar(4, 5, 6));
    Mat c1(5, 5, CV_8UC2, Scalar(4, 5, 6));
    Mat c2(5, 5, CV_8UC3, Scalar(4, 5, 6));
    
(3)Mat类在创建时可以直接调用Mat类自己的内置方法进行赋值:
  • eye:单位矩阵;
  • diag:对角矩阵;
  • ones:相当于每个像素的第一个通道为1,其余两个通道为0,Scalar(1,0,0)
  • zeros:相当于创建一张黑色的图,每个像素的每个通道都为0,Scalar(0,0,0)
  • 示例:创建一个对角矩阵
    // 下面的定义默认省略了Scalar(1, 0, 0),Mat::ones(2, 2, CV_8UC3, Scalar(1, 0, 0) );
    Mat m5 = Mat::ones(2, 2, CV_8UC3);
    
    // 创建空白图像
    // // 下面的定义默认省略了Scalar(0, 0, 0),Mat::zeros(Size(200, 200), CV_8UC3, Scalar(0, 0, 0) );
    Mat m3 = Mat::zeros(Size(200, 200), CV_8UC3); 
    
    // 赋值红色
    m3 = Scalar(0, 0, 255);
    
    Mat m4 = Mat::zeros(Size(400, 400), CV_8UC3);
    // 赋值蓝色
    m3 = Scalar(255, 0, 0);
    
    imshow("红色图像", m3);
    imshow("蓝色图像", m4);
    
(4)枚举法赋值:

枚举赋值方式:cv::Mat a = ( cv::Mat_<c语言基本数据类型>(rows, cols) << 枚举值 );

  • c语言基本数据类型:int,double 等;

  • rows:构造矩阵的行数;

  • cols:构造矩阵的列数;

  • 枚举值:填充值;

  • 示例:

    Mat d = (cv::Mat_<int>(1,5) << 1,2,3,4,5);
    cv::Mat a = ( cv::Mat_<int>(3,3) << 1,2,3,4,5,6,7,8,9 );
    cv::Mat b = ( cv::Mat_<double>(2,3) << 1.0, 2.1, 3.2, 4.0, 5.1, 6.2 );
    
    
5、Mat类 元素的读取,图像像素的读写操作:
(1)Mat类矩阵的常用属性函数
属性作用
cols矩阵的列数
rows矩阵的行数
step以字节为单位的矩阵的有效宽度
elemSize()每个元素的字节数
total()矩阵中元素的个数
channels()矩阵的通道数
(2)读取图像像素常用函数

读取函数:at( int row, int col )

  • 单通道
  读取单通道第一个元素的值
  int value = (int)a.at<uchar>(0, 0);
  • 多通道
双通道元素值读取:
cv::Vec2b, vc2 = b.at<cv::Vec2b>(0, 0);
int first = (int)vc2.val[0];
三通道元素值读取:
cv::Vec3b, vc3 = b.at<cv::Vec3b>(0, 0);
int first = (int)vc3.val[0];

矩阵元素地址定位方式,访问元素值

  • 即可以读取单通道元素值,也可以读取多通道元素值
(int)( *( b.data + b.step[0] * row + b.step[1] * col + channel ) )

row:行数
col:列数
channel:通道数
b.step[0]:x轴
b.step[1]:y轴
channel:z轴

(3)图像像素的读写操作方法
  • 方法一:数组遍历方式,读写图像像素
    // Mat类 元素的读取,图像像素的读写操作
    void pixel_visit(Mat &image) {
    	// 获取行数
    	int h = image.rows;
    	// 获取列数
    	int w = image.cols;
    	// 获取通道数
    	int dims = image.channels();
    
    	std::cout << h << std::endl;
    	std::cout << w << std::endl;
    	std::cout << dims << std::endl;
    
    	// 数组遍历方式,读取图像像素
    	for (int row = 0; row < h; row++) {	// 遍历行
    
    		for (int col = 0; col < w; col++) {	//遍历列
    			// 通道数=1,灰度图像
    			if (dims==1) {
    				int pv = image.at<uchar>(row, col);		// 读取像素值
    				image.at<uchar>(row, col)=255-pv;		// 给像素值重新赋值
    			}
    			if (dims == 3) {
    				// 通道数=3,RGB图像即彩色图像
    				Vec3b bgr = image.at<Vec3b>(row, col);		// 读取像素值,读取出来的bgr是个数组,数组内有3个元素
    				image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
    				image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
    				image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
    			}
    		}
    	}
    	// 显示图像
    	imshow("像素读写演示", image);
    }
    
  • 方法二:指针方式遍历,读写图像像素

    opencv Mat数据类型,指针ptr()函数的使用:uchar a = a1.ptr <uchar>(row)[column],指向a1的第row+1行的第column+1个数据,数据类型为无符号整型;
    (1)单通道,是一个二维数组,读取的像素值,是一个包含1个值的一维数组:
    cv::Mat image = cv::Mat(3, 6, CV_8UC1); // 定义一个3行6列单通道的Mat变量,image
    uchar *data00 = image.ptr <uchar>(0); // 创建一个指针data00,指向images的第1行的第1个元素
    uchar *data10 = image.ptr <uchar>(1); // 创建一个指针data10,指向images的第2行的第1个元素
    uchar *data01 = image.ptr <uchar>(0)[1]; // 创建一个指针data01,指向images的第1行的第2个元素
    (2)多通道,也是一个二维数组,读取的像素值,是一个包含3个值的一维数组:
    cv::Mat image = cv::Mat(6, 9, CV_8UC3); // 定义一个6行9列3通道的Mat变量,image,3通道彩色图片
    cv::Vec3b *data00 = image.ptrcv::Vec3b(0); // 创建一个指针data00,指向images的第1行的第1个元素
    cv::Vec3b *data10 = image.ptrcv::Vec3b(1); // 创建一个指针data10,指向images的第2行的第1个元素
    cv::Vec3b *data01 = image.ptrcv::Vec3b(0)[1]; // 创建一个指针data01,指向images的第1行的第2个元素

    
    // Mat类 元素的读取,图像像素的读写操作
    void QuickDemo::pixel_visit(Mat &image) {
    	// 获取行数
    	int h = image.rows;
    	// 获取列数
    	int w = image.cols;
    	// 获取通道数
    	int dims = image.channels();
    
    	std::cout << h << std::endl;
    	std::cout << w << std::endl;
    	std::cout << dims << std::endl;
    
    	// 指针方式遍历,读写图像像素
    	for (int row = 0; row < h; row++) {	// 遍历行
    		// 获取当前行的指针
    		uchar *currentRow = image.ptr<uchar>(row);
    		for (int col = 0; col < w; col++) {	//遍历列
    											// 单通道,是一个二维数组,读取的像素值,是一个包含1个值的一维数组,array1():
    			if (dims == 1) {
    				int pv = *currentRow;			// 通过指针获取像素值
    				*currentRow++ = 255 - pv;		// 给像素值重新赋值
    			}
    			if (dims == 3) {	//3通道,也是一个二维数组,读取的像素值,是一个包含3个值的一维数组,array2();
    				*currentRow++ = 255 - *currentRow;	// 指针currentRow指向数组元素array2[0]的地址
    				*currentRow++ = 255 - *currentRow;	// 指针currentRow指向数组元素array2[1]的地址
    				*currentRow++ = 255 - *currentRow;	// 指针currentRow指向数组元素array2[2]的地址
    			}
    		}
    	}
    
    	// 显示图像
    	imshow("像素读写演示", image);
    }
    
    
6、Mat类的运算,图像像素的算术操作:

图像的算数运算是对图像进行加减乘除运算,过算术运算可以让图像来达到图像增强的效果;

(1)加减乘除运算

图像和标量:

Mat out;
//加
out = image1 + Scalar(50, 50, 50);
imshow("加法", out);
//减
out = image1 - Scalar(50, 50, 50);
imshow("减法", out);
//乘
//out = image1 * Scalar(2, 2, 2); 直接乘法会出错
//imshow("乘法", out);
//除
out = image1 / Scalar(0.5, 0.5, 0.5);
imshow("除法", out);

图像和图像:

opencv为 Mat类 提供的一些运算函数

函数名作用
add()矩阵求和
subtract()矩阵减法
multiply矩阵乘法
divide()矩阵除法
max()/min()两个矩阵计算最大值 / 最小值

示例:操作可使图像亮度变化

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
 
int main(int argc, char** argv) {
	Mat image1 = imread("C:\\Users\\Pictures\\suzy.jpg");
	Mat image2 = Mat::zeros(image1.size(), image1.type());
	image2 = Scalar(2, 2, 2);
	Mat out;
	//加
	add(image1, image2, out);
	imshow("加法", out);
	//减
	subtract(image1, image2, out);
	imshow("减法", out);
	//乘
	multiply(image1, image2, out);
	imshow("乘法", out);
	//除
	divide(image1, image2, out);
	imshow("除法", out);
 
	waitKey(0);
	destroyAllWindows();
	return 0;
}
(2)两个矩阵相乘
  • 矩阵乘积:* cij = ai1b1i + ai2b2j + ai3b3j
  • 向量内积:.dot() f=d1e1 + d2e2 + d3e3
  • 对应位元素乘积:.mul() cij = aij bij

7、Mat类的运算,图像像素的逻辑运算(与、或、非、异或):

图像的逻辑运算是对图像进行与、或、非、异或等逻辑运算,通过逻辑运算对图像进行分割、图像增强、图像识别、图像复原等操作(图像的逻辑运算严格意义上来说 叫 位运算bitwise)

(1)逻辑运算基础知识:

逻辑运算只有两个布尔值:

  • 0 -> 表示假 False
  • 1 -> 表示真 True
运算数学符号运算规则OpenCV内置函数
AND两个操作数都为真时,结果才为真,其他情况均为假bitwise_and()
OR有一个操作数为真则结果为真,两个操作数都为假时结果才为假bitwise_or()
NOT进行非运算,真变假,假变真bitwise_not()
异或XOR两个操作数相同为假,相异为真bitwise_xor()

(2)opencv 的位操作内置函数:

  • 与 bitwise_and()
  • 或 bitwise_or()
  • 非 bitwise_not()
  • 异或 bitwise_xor()

示例代码:

// Mat类的运算,图像像素的逻辑运算
void QuickDemo::bitwise(Mat &image) {
	// 声明两个图像
	Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
	Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
	// 填充两个实心矩形
	rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
	rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
	imshow("m1", m1);
	imshow("m2", m2);
	// 图像像素的位运算
	// 与
	Mat dst;
	bitwise_and(m1, m2, dst);
	imshow("and", dst);
	bitwise_or(m1, m2, dst);
	imshow("or", dst);
	bitwise_not(m1, dst);
	imshow("not", dst);
	bitwise_xor(m1, m2, dst);
	imshow("xor", dst);
};

在这里插入图片描述

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值