首页 > 学院 > 开发设计 > 正文

【OpenCV学习笔记】二、深入了解 cv::Mat

2019-11-08 03:17:48
字体:
来源:转载
供稿:网友

最近在系统地学习OpenCV,将学习的过程在此做一个记录,主要以代码+注释的方式

记录学习过程。

cv::Mat有两个必不可少的组成部分:一个头部和一个数据块。头部包含了矩阵的所有相关信息(大小、通道数量、数据类型等);数据块包含了图像中所有像素的值。头部有一个指向数据块的指针,即data属性。cv::Mat有一个很重要的属性,即只有在明确要求时,内存块才会被复制。实际上,大多数操作仅仅复制了cv::Mat的头部,因此多个对象会同时指向同一个数据块。 

下面的程序可用来测试cv::Mat数据结构的不同属性(代码+注释):

#include <iostream>#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>// 测试函数, 它创建一个图像cv::Mat function() {	// 创建图像	cv::Mat ima(500, 500, CV_8U, 50);	// 返回图像	return ima;} int main() {	// 定义图像窗口	cv::namedWindow("Image 1");	cv::namedWindow("Image 2");	cv::namedWindow("Image 3");	cv::namedWindow("Image 4");	cv::namedWindow("Image 5");	cv::namedWindow("Image");	/*我们需要指定每个矩阵元素的类型,这里我们用CV_8U表示每个像素	对应1字节,用字母U表示无符号,你也可用字母S表示有符号。对于	彩色图像,你应该用三通道类型(CV_8UC3),也可以定义16位和	32位的整数(有符号或无符号),例如CV_16SC3。我们甚至可以使	用32位和64位的浮点数(例如CV_32F)。*/	// 创建一个240行 × 320列的新图像	cv::Mat image1(240, 320, CV_8U, 100);	cv::imshow("Image", image1); // 显示图像	cv::waitKey(0); // 等待按键	/*我们可以随时用create方法分配或重新分配图像的数据块,如果图	像已经分配,首先其原来的内容会被释放。*/	// 重新分配一个新的图像	image1.create(200, 200, CV_8U);	image1 = 200;	cv::imshow("Image", image1); // 显示图像	cv::waitKey(0); // 等待按键	/*图像(或矩阵)的每个元素都可以包含多个值(例如彩色图像中的三	个通道),因此OpenCV引入了一个简单的数据结构cv::Scalar,	用于在调用函数时传递像素值。该结构通常包含一个或三个值。*/	// 创建一个红色的图像	// 通道次序为BGR	cv::Mat image2(240, 320, CV_8UC3, cv::Scalar(0, 0, 255));	// 或者:	// cv::Mat image2(cv::Size(320,240),CV_8UC3);	// image2= cv::Scalar(0,0,255);	cv::imshow("Image", image2); // 显示图像	cv::waitKey(0); // 等待按键	// 读入一个图像	cv::Mat image3 = cv::imread("puppy.bmp");	/*一旦没有了指向cv::Mat对象的引用, 分配的内存就会被自动释		放。 这一点非常方便, 因为它避免了C++动态内存分配中经常发生的		内存泄漏问题。 这是OpenCV 2中一个关键的机制, 它的实现方法是		通过cv::Mat实现计数引用和浅复制。 因此, 当在两个图像之间赋		值时, 图像数据( 即像素) 并不会被复制, 此时两个图像都指向同一		个内存块。 这同样适用于图像间的值传递或值返回。 由于维护了一个		引用计数器, 因此只有当图像的所有引用都将释放或赋值给另一个图		像时, 内存才会被释放;*/	// 所有这些图像都指向同一个数据块。	//下面的两个图像,对其中的任何一个做转换都会影响到其他图像。	cv::Mat image4(image3);	image1 = image3;	/*如果要对图像内容做一个深复制, 你可以使用copyTo方法, 在此情况下	目标图像会调用create方法。 另一个生成图像副本的方法是clone, 即创建	一个完全相同的新图像*/	// 这些图像是源图像的副本图像	image3.copyTo(image2);	cv::Mat image5 = image3.clone();	// 转换图像用来测试	cv::flip(image3, image3, 1);	// 检查哪些图像在处理过程中受到了影响	cv::imshow("Image 3", image3);	cv::imshow("Image 1", image1);	cv::imshow("Image 2", image2);	cv::imshow("Image 4", image4);	cv::imshow("Image 5", image5);	cv::waitKey(0); // 等待按键	// 从函数中获取一个灰度图像	cv::Mat gray = function();	cv::imshow("Image", gray); // 显示图像	cv::waitKey(0); // 等待按键	// 作为灰度图像读入	image1 = cv::imread("puppy.bmp", CV_LOAD_IMAGE_GRAYSCALE);	/*如果你需要把一个图像复制到另一个图像中, 而两者的数据类型不一	定相同, 那就要使用convertTo方法.需要注意的是, 这两个图像的通道数量	必须相同。*/	image1.convertTo(image2, CV_32F, 1 / 255.0, 0.0);	cv::imshow("Image", image2); // 显示图像	cv::waitKey(0); // 等待按键	return 0;}程序运行结果:从左往下,image1至image5。


上一篇:

下一篇:shader学习心得

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表