OpenCV2:Mat

OpenCV2 Mat详解

OpenCV2:Mat

1.Mat基础

在计算机内存中,数字图像是已矩阵的形式保存的。OpenCV2中,数据结构Mat是保存图像像素信息的矩阵,它主要包含两部分:矩阵头和一个指向像素数据的矩阵指针。
矩阵头主要包含,矩阵尺寸、存储方法、存储地址和引用次数等。
矩阵头的大小是一个常数,不会随着图像的大小而改变,但是保存图像像素数据的矩阵则会随着图像的大小而改变,通常数据量会很大,比矩阵头大几个数量级。这样,在图像复制和传递过程中,主要的开销是由存放图像像素的矩阵而引起的。因此,OpenCV使用了引用次数,当进行图像复制和传递时,不再复制整个Mat数据,而只是复制矩阵头和指向像素矩阵的指针。例如:
1
2
3
cv::Mat a ;//创建矩阵头
a = cv::imread(“f:\psb.jpg”);//读入图像
cv::Mat b = a ;//复制 
上面的a,b有各自的矩阵头,但是其矩阵指针指向同一个矩阵,也就是其中任何一个改变了矩阵数据都会影响另外一个。
那么,多个Mat共用一个矩阵数据,最后谁来释放矩阵数据呢?
这就是引用计数的作用,当Mat对象每被复制一次时,就会将引用计数加1,而每销毁一个Mat对象(共用同一个矩阵数据)时引用计数会被减1,当引用计数为0时,矩阵数据会被清理。

上图是Mat对象a,b共用一个矩阵,故其引用计数refcount为2.
但是有些时候仍然会需要复制矩阵数据本身(不只是矩阵头和矩阵指针),这时候可以使用clone 和copyTo方法。
cv::Mat c = a.clone();
cv::Mat d ;
a.copyTo(d);
上面代码中的c,d各自拥有自己的矩阵,改变自己的矩阵数据不会相互影响。
在使用Mat中,需要记住:
OpenCV中的内存分配是自动完成的(不是特别指定的话)
使用OpenCV的C++ 接口时不需要考虑内存释放问题
Mat的赋值运算和拷贝构造函数只会拷贝矩阵头,仍然共同同一个矩阵
如果要复制矩阵数据,可以使用clone和copyTo函数
2.Mat存储方法

Mat中矩阵的每个元素可以使用不同的数据类型,最小的数据类型是char,占用一个字节或者8位,可以是有符号的(0到255)或者是无符号的(-127到127)。在RGB颜色空间中,使用三个char类型可以表示1600万中颜色,但在图像处理的过程中有可能会使用到float或者double来表示图像的像素。
Mat的创建

构造函数

cv::Mat img(2,2,CV_8UC3,cv::Scalar(0,0,255));
上述代码创建了一个2行2列的矩阵,矩阵元素使用8位无符号char类型保存,具有3通道,每个像素的初始值是(0,0,255)
构造函数的前两个参数指定了矩阵的行和列
第三个参数指定矩阵元素的数据类型以及通道数,其指定规则如下:
CV_[The number of bits per item][Signed or Unsigned][TypePrefix]C[The channel number]
四部分分别指定:元素的大小,是有符号还是无符号,数据类型以及通道数
最后一个参数,Scalar是short型的vector,提供矩阵的初始化。
Create方法

该方法不能为矩阵设置初始值,只是在改变尺寸时为矩阵数据重新分配内存。使用方法:
img.create(4,4,CV_8UC(2));
创建了一个4行4列有2个通道的矩阵
MATLAB形式的初始化

cv::Mat e = cv::Mat::eye(4,4,CV_64F);
cv::Mat z = cv::Mat::ones(2,2,CV_32F);
cv::Mat o = cv::Mat::zeros(3,3,CV_8UC1);
Mat e是4行4列的对角矩阵
Mat z是2行2列的单位矩阵
Mat o是3行3列的零矩阵
小矩阵的初始化

对于小矩阵可以使用逗号分割的初始化函数
Mat c =(Mat_(3,3)<<1,2,3,0,-1,0,4,5,6);
在对图像进行模板运算时,定义模板使用这种方法是很方便的。
3.Mat的输入输出

使用imread函数,向Mat对象中写入一个图像。

a = cv::imread(“f:\psb.jpg”);//读入图像
imread的原型如下
cv::Mat imread(const string& filename,int flags=1)
filename指定要读取图像的位置
flags指定图像的颜色空间
flags > 0 3通道的彩色图像
flags = 0 灰度图像
flags < 0 不作改变
也可以有以下的枚举值
CV_LOAD_IMAGE_ANYDEPTH、CV_LOAD_IMAGE_COLOR、CV_LOAD_IMAGE_GRAYSCALE

使用imwrite函数,将Mat对象保存到指定的文件中。

imwrite的函数原型如下:
bool imwrite(const string& filename,InputArray img,constvector& params=vector())
filename,指定的文件
img 要保存的Mat对象
params 用来指定图像的保存编码方式。
使用filename的扩展名来指定图像的保存格式(.jpg .png .bmp),对于不同的图像保存类型,params是不同的值
JPEG,params用来指定图像的质量(0到100),默认的是95. CV_IMWRITE_JPEG_QUALITY
PNG,params用来指定图像的压缩级别(0到9),压缩级别越高图像占用的空间越小,保存图像所用的时间越久。默认值是3. CV_IMWRITE_PNG_COMPRESSION
PPM,PGM,PBM,params是一个标记(0或者1),默认的是1.CV_IMWRITE_PXM_BINARY
imwrite只能保存8位(或者是16位无符号(CV_16UC)的PNG,JPEG200或者TIFF图像)单通道或者三通道的图像,如果要保存的不是这样的图片,可以使用convertTo或者cvtColor来进行转变。
下面代码展示了如果使用imwrite向文件中写入一个4通道的png图像
复制代码
void createAlphaMat(Mat &mat)
{
for(int i = 0 ; i < mat.rows ; i ++) {
for(int j = 0 ; j < mat.cols ; j ++) {
Vec4b &rgba = mat.at(i,j);
rgba[0] = UCHAR_MAX ;
rgba[1] = saturate_cast((float (mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX);
rgba[2] = saturate_cast((float (mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX);
rgba[3] = saturate_cast(0.5 * (rgba[1] + rgba[2]));
}
}
}
int main()
{
Mat mat(480,640,CV_8UC4);
createAlphaMat(mat);

vector<int> compression_params ;
compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
compression_params.push_back(9);

imwrite("alpha.png",mat,compression_params);

return 0;

}
复制代码

4.Mat的显示

OpenCV提供了用以窗口的形式显示图片的方法,代码如下:
Mat img = imread(“f:\psb.jpg”);
const string name =”Hu”;
namedWindow(name);
imshow(name,img);
waitKey();

转自:http://www.cnblogs.com/wangguchangqing/p/3841271.html

<think> 我们正在讨论的是C++ OpenCV中的语句:`cv::Mat mat1 = cv::Mat();` 根据OpenCV的文档,`cv::Mat`是一个用于表示多维密集数组的类,常用于存储图像数据、矩阵等。 语句`cv::Mat mat1 = cv::Mat();`的作用是创建一个空的`cv::Mat`对象`mat1`。具体来说: 1. 调用默认构造函数`cv::Mat()`,它会创建一个没有数据的矩阵(即矩阵头为空,没有分配数据缓冲区)。 2. 然后将这个空矩阵赋值给`mat1`(这里实际上会调用拷贝构造函数,但由于默认构造函数创建的是空矩阵,所以拷贝后`mat1`也是空的)。 因此,这行代码等价于: ```cpp cv::Mat mat1; // 直接默认构造 ``` 在OpenCV中,默认构造的`cv::Mat`对象具有以下特性: - 行数(rows)为0 - 列数(cols)为0 - 空的数据指针(data为NULL) - 引用计数(refcount)为NULL(表示没有引用计数,因为没有数据) 我们可以通过以下代码验证: ```cpp #include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat mat1 = cv::Mat(); // 或者直接 cv::Mat mat1; std::cout << "Rows: " << mat1.rows << ", Cols: " << mat1.cols << std::endl; std::cout << "Empty? " << (mat1.empty() ? "true" : "false") << std::endl; return 0; } ``` 输出将是: ``` Rows: 0, Cols: 0 Empty? true ``` 因此,这个语句就是创建了一个空的矩阵对象,通常我们在后面会通过其他方式(如读取图像、创建矩阵等)来给它赋值。 注意:在OpenCV中,`cv::Mat`对象使用引用计数机制,但空矩阵不包含任何数据,因此不会涉及引用计数。 引用说明: - 引用[1]提到Mat是一个类,它创建的对象类似于numpy数据结构,是一个存放矩阵的容器。默认构造的Mat对象就是一个空的容器。 - 引用[2]中提到了使用`create`函数来创建矩阵,但这里没有使用,所以是空的。 - 引用[3]中的类型表,对于空矩阵,它的`type()`方法返回的值也是0(即CV_8UC1,但因为没有数据,所以类型信息也是无效的)。实际上,空矩阵的`type()`返回-1(CV_8UC1对应的0在空矩阵中并不表示类型,而是表示无效)。我们可以通过代码验证:空矩阵的`type()`返回-1(在OpenCV中,常量`CV_8U`等有定义,但空矩阵的类型是未设置的)。 因此,总结:`cv::Mat mat1 = cv::Mat();` 就是创建了一个空的矩阵对象,它在被赋值(例如读取图像、显式创建矩阵)之前都是空的。 </think>在 C++ OpenCV 中,语句 `cv::Mat mat1 = cv::Mat();` 的含义是创建一个空的 `cv::Mat` 对象。具体来说: 1. **创建空矩阵**: - `cv::Mat()` 调用默认构造函数 - 创建一个**没有分配数据**的矩阵对象 - 行数(`rows`)和列数(`cols`)均为 0 - 数据类型(`type()`)为 -1(表示未定义类型) - 使用 `mat1.empty()` 会返回 `true`[^1] 2. **内存特性**: ```cpp cv::Mat mat1 = cv::Mat(); // 创建空矩阵 std::cout << "Size: " << mat1.size() << std::endl; // 输出 [0 x 0] std::cout << "Empty? " << mat1.empty() << std::endl; // 输出 1 (true) ``` 3. **与显式创建的区别**: 不同于 `cv::Mat(3,3,CV_32F)` 这种显式创建: ```cpp // 显式创建 3x3 浮点矩阵 cv::Mat mat2 = cv::Mat(3, 3, CV_32F); ``` - `mat2.rows=3`, `mat2.cols=3` - `mat2.type()=5` (对应 `CV_32F`)[^3] - `mat2.empty()=false` 4. **典型用途**: - 作为**占位符**,稍后通过其他操作赋值 ```cpp cv::Mat mat1 = cv::Mat(); // 先声明空矩阵 cv::imread("image.jpg").copyTo(mat1); // 后续赋值 ``` - 作为函数**返回值**的默认空对象 - 在循环中**复用**矩阵内存 5. **内存管理**: - 空矩阵不占用数据内存 - 仅包含矩阵头信息(约 96 字节) - 赋值操作(如 `mat1 = image.clone()`)会自动分配新内存[^2]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值