cv::Mat使用笔记

本文详细介绍了OpenCV中cv::Mat类的使用,包括不同构造方法、初始化技巧、图像操作以及与Eigen矩阵的转换。强调了cv::Mat在创建、赋值时的注意事项,如浅拷贝问题,并提供了读取和保存图像的示例。同时,讨论了cv::Mat的潜在问题,如弱类型和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文深入探索OpenCV库中cv::Mat类的使用方法和技巧。cv::Mat作为OpenCV中用于存储图像数据的基本数据结构,其使用范围广泛且功能强大。通过本文,你将了解cv::Mat的创建、访问和修改数据的基本操作,以及其在图像处理任务中的具体应用。此外,我还会分享一些在使用cv::Mat时可能遇到的常见问题及其解决方案,帮助你更好地掌握这一工具。无论你是OpenCV的新手还是资深用户,相信这篇博客都能为你提供有价值的参考和启示。

1. 构造

  • 无参数构造方法
Mat::Mat()
  • 创建行数为 rows,列数为 col,类型为 type 的图像
Mat::Mat(int rows, int cols, int type)
  • 创建大小为 size,类型为 type 的图像
Mat::Mat(Size size, int type)
  • 创建行数为 rows,列数为 col,类型为 type 的图像,并将所有元素初始化为值 s
Mat::Mat(int rows, int cols, int type, const Scalar& s)
  • 创建大小为 size,类型为 type 的图像,并将所有元素初始化为值 s
Mat::Mat(Size size, int type, const Scalar& s)
  • 将m赋值给新创建的对象,此处不会对图像数据进行复制,m和新对象共用图像数据,属于浅拷贝
Mat::Mat(const Mat& m)
  • 创建行数为rows,列数为col,类型为type的图像,此构造函数不创建图像数据所需内存,而是直接使用data所指内存,图像的行步长由 step指定
Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
  • 创建大小为size,类型为type的图像,此构造函数不创建图像数据所需内存,而是直接使用data所指内存,图像的行步长由step指定
Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)
  • 创建的新图像为m的一部分,具体的范围由rowRange和colRange指定,此构造函数也不进行图像数据的复制操作,新图像与m共用图像数据
Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
  • 创建的新图像为m的一部分,具体的范围roi指定,此构造函数也不进行图像数据的复制操作,新图像与m共用图像数据
Mat::Mat(const Mat& m, const Rect& roi)

2. 初始化

  • 使用函数初始化
cv::Mat a = cv::Mat::eye(4, 4, CV_64FC1); // 单通道double类型
cv::Mat b = cv::Mat::eye(4, 4, CV_8UC1); // 单通道char类型
  • 使用cv::Point3f和cv::Mat_初始化;
cv::Point3f v1(34.0f, 21.34f, 32.0f);
cv::Mat m{ cv::Mat_<cv::Point3f>(v1) };
//得到1行1列3通道的矩阵 
  • 使用cv::Point3f初始化
cv::Point3f point(34.0f, 21.34f, 32.0f);
cv::Mat m(point);
//得到3行1列1通道的矩阵 
  • 使用vector初始化
std::vector<double> vec{ 21.3, -10, 34.0, 3.2, 3.4 };
cv::Mat m{ vec }; 
//得到5行1列1通道的矩阵 
  • 使用std::vector<cv::Point2f>初始化 
//得到2行1列2通道的矩阵 
std::vector<cv::Point2f> vecpts{ cv::Point2f(2.3, 3.1), cv::Point2f(9.3, -10.0) };
cv::Mat m{ vecpts };
  • 使用cv::Mat_初始化
//得到3行3列1通道的矩阵
cv::Mat C = (cv::Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);

3. 对一部分进行赋值 

这些方式看似正确,但实际不行

cv::Mat matrix = cv::Mat::zeros(4, 4, CV_64FC1);
cv::Mat calibration = cv::Mat::eye(3, 3, CV_64FC1);

// 方法一
cv::Mat a = matrix.rowRange(0, 3).colRange(0, 3); // 共享内存
a = calibration; 

// 方法二
cv::Mat matrix = cv::Mat::zeros(4, 4, CV_64FC1);
matrix.rowRange(0, 3).colRange(0, 3) = calibration.clone();

// 方法三
calibration.copyTo(matrix.rowRange(0, 3).colRange(0, 3)); // 编译失败

正确的方式

cv::Mat matrix = cv::Mat::zeros(4, 4, CV_64FC1);
cv::Mat a = matrix.rowRange(0, 3).colRange(0, 3); // 共享内存
xa.copyTo(a);
cv::Mat b = matrix.rowRange(0, 3).col(3); // 共享内存
xb.copyTo(b);

4. 与Eigen矩阵的相互转化

注意:只支持double类型的转换,不支持float类型

#include <opencv2/core/eigen.hpp>

cv::cv2eigen(cv_matrix, eigen_matrx);

cv::eigen2cv(eigen_matrx, cv_matrix);

5. 指针

cv::Mat matrix = cv::Mat::zeros(4, 4, CV_64FC1);

// 方法一
const double *data = matrix.ptr<double>(0);

// 方法二
// img.data的默认类型是unsigned char* 
double* data = (matrix*)img.data;

6. cv::Mat的缺点

  • 弱类型

C++本来是强类型语言,但cv::Mat却是弱类型的,即当你拿到一个cv::Mat的时候你并不知道它里面存储的数据类型,很容易用错;

  • 不安全

当你把你的cv::Mat对象传给某函数时,即使函数的形参加了const关键字,但它依然可能会被修改,这是因为cv::Mat有共享内存机制,它的拷贝是浅拷贝;

  • 构造时间长

cv::Mat构造时间很长,如果非必要不建议使用,构造过程尽量写在循环外面;

7. 图像操作

  • 读入图像
cv::Mat A = imread(“Imgpath”, CV_LOAD_IMAGE_COLOR);

A.at<Vec3b>(row, col)[2] // 访问图像数据

注意 Mat::at 函数是个模板函数,需要指明参数类型,因为这张图是具有红蓝绿三通道的图,所以它的参数类型可以传递一个 Vec3b,这是一个存放 3 个 uchar 数据的 Vec(向量)。这里提供了索引重载,[2]表示的是返回第三个通道,在这里是 Red 通道,第一个通道(Blue)用[0]返回

  • 保存图像
imwrite(image_path, A);
  •  将彩色图片转为灰度图片
Mat src(m, n CV_8UC3);
Mat dst;
cvtColor(src,dst,CV_BGR2GRAY);

参考文献

Mat 的几种初始化和赋值方法 - 骏腾 - 博客园

浅谈Opencv Mat类(常用构造函数和成员函数整理)_古天九等一缕的博客-CSDN博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值