OpenCV C++教程目录
1.在Windows Visual Studio中安装OpenCV C++版本
2.图像的基本操作
3.颜色空间转换
4.阈值分割
5.图像变换(缩放、裁剪、仿射变换)
6.图像滤波
7.Canny边缘检测
8.轮廓检测
9.透视变换(perspective transform)
10.光流
今天我们来学习一下在OpenCV中图像的一些基本操作。内容如下:
- 加载、显示、保存图片
- 用Mat来表示一张图片
- Mat基本运算
1.加载、显示、保存图片
在OpenCV中,我们使用imread(), imshow(), imwrite()函数分别进行图像的读取,显示和保存。下面我们通过一个简单的例子来看一下如何使用这三个函数。示例的代码分别进行了如下操作
1.读取原始图片
2.显示原始图片
3.设置ROI(Region Of Interest)区域,即根据感兴趣的区域对图像进行裁剪
4.显示裁剪后的ROI区域
5.保存裁剪后的ROI区域
Mat img = imread("D:/projects/opencv/Lena.jpg"); //读取本地图片
imshow("Lena", img); //显示图片
Rect roi(10, 20, 100, 50); //设置ROI区域,4个参数分别对应裁剪区域的x, y坐标,以及裁剪的长方形的长和宽。
Mat img_roi = img(roi); //根据设置的区域进行裁剪
imshow("Lena", img); //显示裁剪后的ROI区域
waitKey(0); //等待键盘输入后退出显示
imwrite("D:/projects/opencv/Lena_roi.jpg", img_roi); //保存裁剪后的ROI图片
2.用Mat来表示一张图片
数字图像在计算机中通常是以矩阵形式存储的。如下图所示,矩阵中的元素代表着图像信息。在OpenCV中,我们一般使用Mat这种数据结构来表示图像。Mat类分为头和指向图像数据的指针两部分。矩阵头主要包含:矩阵尺寸、存储方式、存储地址、引用计数等。
要注意的是Mat类利用了类似C++中智能指针的思想,Mat类对象在其引用计数为0时自动销毁,用户无需手动释放Mat对象。这使得OpenCV的内存管理变得简单。每个Mat对象拥有属于自己的头信息,但是图像数据信息则是可以是共享的。
Mat A, C; //声明A,C两个Mat类型变量,同时只创建了矩阵头
A = imread("test.jpg", IMREAD_COLOR); //将图片读取到A中
Mat B(A); //拷贝构造函数。只拷贝矩阵头,数据共享,同时A reference+1
C = A; //赋值构造函数。同样的,只有矩阵头信息从A拷贝到了C,数据是共享的, 同时A reference+1
当你需要拷贝数据信息,从而实现对图像进行不同的操作,而互不影响时,可以使用clone()和copyTo()这两个函数。
Mat F = A.clone(); //拷贝A的头信息和数据信息到F
Mat G;
A.copyTo(G); //拷贝A的头信息和数据信息到F
3.Mat基本运算
1. Create() 方法
用于创建指定format的矩阵。
Mat img;
img.create (8, 8, CV_8UC3); //创建一个8行8列有3个通道的矩阵,数据类型为8bit unsigned char型:
2.矩阵初始化并赋值
Mat m = (Mat_(3,3) << 6,4,-2,2,1,0,2,3,-1);
3.创建特殊矩阵
cv::Mat o = cv::Mat::ones (3, 3, CV_8C); //3行3列的单位矩阵
cv::Mat e = cv::Mat::eye (3, 3, CV_8C); //3行3列的对角矩阵
cv::Mat z = cv::Mat::zeros (3, 3, CV_8C); //3行3列的零矩阵
4.矩阵加减法
- 相同大小的矩阵才能进行加减法。矩阵加减法两个矩阵对应位置的数值相加减,使用Mat类重载的 “+” 和 “-” 运算符
cv::Mat a = Mat::eye(Size(3,3), CV_8C);
cv::Mat b = Mat::ones(Size(3,3), CV_8C);
cv::Mat c= a + b;
cv::Mat d= a - b;
- Mat对象也可以和常数相加, 同样使用”+"运算符, 果是矩阵中的每个元素都与这个数值相加
int C = 100;
Mat b = a + C;
4.矩阵乘法
- 普通乘法。和线性代数中矩阵乘法类似,矩阵A和B相乘时,要求A的列数等于B的行数,才能进行运算。如A是MxN矩阵,B是NxL矩阵,它们的乘积AB是一个MxL矩阵。矩阵也可以和一个标量相乘,结果是矩阵的每一位和标量的乘积。
Mat a = Mat::ones(2,3,CV_32FC1);
Mat b = Mat::ones(3,2,CV_32FC1);
Mat m1 = a * b; //矩阵相乘
/********************************/
int C = 10;
Mat m2 = C * a; //矩阵与标量相乘
- 点乘
对两个矩阵执行点乘,就是对这两个矩阵对应位相乘之后再求和,因此点乘的结果是一个数值(标量)。
Mat a = Mat::ones(3,3,CV_8UC1);
Mat b = Mat::ones(3,3,CV_8UC1);
int dot = a.dot(b);
- 对应位相乘
要求相乘矩阵的行和列数相同,并且数据类型相同。如果保存结果的矩阵没有定义类型,则默认和相乘矩阵的类型相同。此时要注意可能发生的计算结果溢出问题。
Mat a = Mat::ones(3,3,CV_8UC1);
Mat a = Mat::ones(3,3,CV_8UC1);
Mat multiple = a.mul(b);
5.矩阵的转置
Mat a = Mat::eye(4, 6, CV_8C1);
Mat ta = a.t();
6.矩阵的逆
Mat a = Mat::eye(8, 8, CV_8C1);
Mat ia = a.inv();
以上就是OpenCV中Mat的常用运算。更多Mat运算可以参考OpenCV官方文档(基于4.5.2版本): OpenCV Mat Class reference