opencv-cv::Mat
如果使用Mat类,我们得到的好处是:
不需要手动申请一块内存;
在不需要时不用再手动释放内存;
可以通过类的封装,方便的获取到数据的相关信息
Mat类分为两个部分:矩阵头和矩阵数据。如果我们在操作一副图像的数据量时,矩阵数据的大小很大(一般约有1M的数据量),那么拷贝和赋值函数所作的操作如果的深拷贝的话,效率会大大的降低。所以,Opencv的做法是只复制其矩阵头信息,而矩阵数据采用引用的方式,即多个Mat对象共享同一个矩阵数据,这里使用的原理类似c++11中的共享指针
cv::Mat A = cv::imread("D:/bb/tu/ma.jpg"); cv::Mat B(A); cv::Mat C = A; printf("A.data = %p\nB.data = %p\nC.data = %p\n", A.data, B.data, C.data);
输出结果如下:
如上我们可以看到,三个Mat类对象的矩阵数据的地址是一样的。那么释放内存的原则是怎样的呢。这个也是内部使用了引用计数的方法,类似共享指针,当引用计数变为0的时候才会真正的释放内存
Mat对象的创建
方法一:读入图片
看 https://www.cnblogs.com/liming19680104/p/15345051.html
方法二:使用行、列
cv::Mat M1(5, 4, CV_8UC4, cv::Scalar(0, 0, 0, 255));//创建2维矩阵对象 /* 参数1和参数2:行数和列数 参数3:图像属性8UC4: 第一位8:比特数 代表8bite,16bites,32bites,64bites,每一个像素点在内存空间所占的空间大小 第二位U:S--代表---signed int---有符号整形 U--代表--unsigned int--无符号整形 F--代表--float-------单精度浮点型 最后两位c4:通道数:1--灰度图片---是--单通道图像 2--RGB彩色图像---------是--3通道图像 3--带Alph通道的RGB图像--是--4通道图像 参数4:每个像素点的颜色 */ std::cout << M1 << std::endl; //显示数据 int r=M1.rows; //返回行数 int c=M1.cols; //返回列数 qDebug()<<r<<c;
cv::Mat M1(5, 4, CV_8UC3); std::cerr<<M1<<std::endl; M1=cv::Scalar(10, 20, 30);//赋值 std::cerr<<M1<<std::endl;
cv::Mat M; M.create(5, 4, CV_8UC4);//创建2维矩阵对象 //注意:这种方法好像不能有第四个颜色参数,每个点的颜色随机 std::cout << M << std::endl;
方法三:使用维数、大小
int sz[2]={5,4}; cv::Mat M(2, sz, CV_8UC4, cv::Scalar(0, 0, 0, 255));//创建n维矩阵对象 /* 参数1:矩阵的维数 参数2:是个数组,表示行数和列数 */ std::cout << M << std::endl;
方法四:使用大小
cv::Mat m = cv::Mat(cv::Size(4, 4), CV_8UC3);
方法五:利用矩阵
cv::Mat src(6, 6, CV_8UC3, cv::Scalar(10, 20, 30)); cv::Rect r(1, 1, 3, 3); cv::Mat dst(src, r);//创建新矩阵 //为src的一部分,具体范围由r指定,此构造函数也不进行图像数据的复制操作,dst与src共用图像数据 std::cerr << src << std::endl << std::endl; std::cerr << dst << std::endl << std::endl; dst.at<cv::Vec3b>(1, 1)[1] = 99; std::cerr << src << std::endl << std::endl; std::cerr << dst << std::endl << std::endl; cv::Mat dst1 = cv::Mat_<float>(src); //创建新矩阵并修改数据类型
方法六 :利用数组
#include<opencv2/opencv.hpp> #include<iostream> #include <vector> int main(int argc, char** argv) { float RawData[2][3] = { {4.0,1.0,3.0},{8.0,7.0,9.0} }; cv::Mat RawDataMat(2, 3, CV_32FC1, RawData); std::cout << RawDataMat << std::endl; cv::waitKey(0); return 0; }
单位矩阵
cv::Mat M = cv::Mat::eye(4, 4, CV_32F); //创建单位矩阵 std::cout << M << std::endl;
创建全1矩阵
cv::Mat M = cv::Mat::ones(4, 4, CV_32F); //创建全是1的矩阵 std::cout << M << std::endl;
全0矩阵
cv::Mat M = cv::Mat::zeros(4, 4, CV_32F); //创建全是0的矩阵 std::cout << M << std::endl;
自定义数据矩阵
cv::Mat M = (cv::Mat_<double>(3, 3) << 0, -10, 0, -11, 0, 0, 0, 88, 1); //创建自定义数据的矩阵 std::cout << M << std::endl;
cv::Mat M = (cv::Mat_<double>(3, 3) << 0, -10, 0, -11, 0, 0, 0, 88, 1); cv::Mat M5 = M.row(1).clone(); //M5中的数据就是M的第二行数据 //通过克隆函数clone获取我们需要的某一行或列的数据,这里构建出来的矩阵是深拷贝出来的Mat类对象 std::cout << M5 << std::endl;
矩阵数组
cv::Mat src(10, 10, CV_8UC1,cv::Scalar(155)); cv::Mat src1(10, 10, CV_32FC1,cv::Scalar(1)); cv::Mat src2(10, 10, CV_32FC1,cv::Scalar(2)); cv::Mat planes[] = { cv::Mat_<float>(src), src1,src2 };//创建Mat数组 std::cerr<<planes[0].type()<<std::endl;//返回数据类型 //5=CV_32FC1 std::cerr<<src<<std::endl<<std::endl; std::cerr<<planes[0]<<std::endl<<std::endl; std::cerr<<planes[1]<<std::endl<<std::endl; std::cerr<<planes[2]<<std::endl<<std::endl;
Mat基本属性
cv::Mat A = cv::imread("D:/bb/tu/ma.jpg",1); int i = A.type();//返回图像属性 //具体对应值见下表 std::cout<< i; cv::namedWindow("显示"); imshow("显示",A);
cv::Mat A = cv::imread("D:/bb/tu/ma.jpg",1); int i = A.channels(); //返回通道数 int w=A.cols; //返回列数,即宽 int h=A.rows; //返回行数,即高 cv::namedWindow("显示"); imshow("显示",A); qDebug()<<i<<w<<h;
cv::Mat sm(6, 5, CV_8UC3); int d=sm.depth();//获取矩阵元素深度,其返回的其类型和Mat一致 /* 返回值对应的元素深度 CV_8U = 0 - 8-bit unsigned integers ( 0..255 ) CV_8S = 1 - 8-bit signed integers ( -128..127 ) CV_16U = 2 - 16-bit unsigned integers ( 0..65535 ) CV_16S = 3 - 16-bit signed integers ( -32768..32767 ) CV_32S = 4 - 32-bit signed integers ( -2147483648..2147483647 ) CV_32F = 5 - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN ) CV_64F = 6 - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN ) CV_USRTYPE1=7 */ int c=sm.channels(); //返回矩阵通道数目 int dim=sm.dims; //返回矩阵维度 int e=sm.elemSize();//返回每个元素占用的字节数大小(带通道) int e1=sm.elemSize1();//返回单个元素值占用的字节数大小 int w=sm.step[0]; //第一级在矩阵内存中占据的字节的数量 //step[i]就是第i+1级在矩阵内存中占据的字节的数量 //资料看:https://blog.csdn.net/lanmeng_smile/article/details/47864615 int h=sm.step1(1); //一个元素所占的字节数 std::cerr<<d<<std::endl;
cv::Mat src(5, 4, CV_8UC3, cv::Scalar(0, 0, 255)); size_t d = src.total(); //返回矩阵中的像素总数 //20 std::cerr << d << std::endl;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)