OpenCV第二章 数据载入、显示与保存

第二章 数据载入、显示与保存

2.1 图像存储容器

2.1.1 Mat类介绍

Mat分为矩阵头和指向存储数据的矩阵指针两部分。

代码清单2-1 创建Mat类
cv::Mat a; //创建一个名为a的矩阵头
a = cv::imread("test.jpd"); //向a中赋值图像数据,矩阵指针指向像素数据
cv::Mat b = a; //复制矩阵头,并命名为b
代码清单2-2 声明一个指定类型的Mat类
cv::Mat A = Mat_<double>(3,3); //创建一个3*3的矩阵用于存放double类型数据
代码清单2-3 通过OpenCV数据类型创建Mat类
cv::Mat a(640,480,CV_8UC3); //创建一个640*480的3通道矩阵用于存放彩色图像
cv::Mat a(3,3,CV_8UC1); //创建一个3*3的8位无符号整数的单通道矩阵
cv::Mat a(3,3,CV_8U); //创建单通道矩阵,c1标识可以省略

2.1.2 Mat类构造与赋值

1.Mat类的构造

代码清单2-4 默认构造函数使用方式
cv::Mat::Mat();
代码清单2-5 利用矩阵尺寸和类型参数构造Mat类
cv::Mat::Mat(int rows,
            int cols,
            int type
            )
  • rows:构造矩阵的行数
  • cols:矩阵的列数
  • type:矩阵中存储的数据类型
代码清单2-6 用Size()结构构造Mat
cv::Mat(Size size(),
       int type
       )
  • size:二维数组变量尺寸,通过Size(cols,rows)进行赋值
  • type:与代码清单2-5中的参数一致
代码清单2-7 用Size()结构构造Mat示例
cv::Mat a(Size(480,640),CV_8UC1); //构造一个行为640、列为480的单通道矩阵
cv::Mat b(Size(480,640),CV_32FC3); //构造一个行为640、列为480的3通道矩阵
代码清单2-8 利用已有矩阵构造Mat类
cv::Mat::Mat(const Mat & m);
  • m:是已经构建完成的Mat类矩阵数据

提示:如果希望复制两个一模一样的Mat类而彼此之间不会受影响,那么可以使用m=a.clone()实现

代码清单2-9 构造已有Mat类的子类
cv::Mat::Mat(const Mat & m,
            const Range & rowRange,
            const Range & rowRange = Rang::all()
            )
  • m:是已经构建完成的Mat类矩阵数据
  • rowRange:在已有矩阵中需要截取的行数范围,是一个Rang变量,例如从第2行到第5行可以表示位Rang(2,5)
  • rowRange:在已有矩阵中需要截取的列数范围,是一个Rang变量,例如从第2列到第5列可以表示位Rang(2,5),默认所有列都会截取。
代码清单2-10 在原Mat中截取子Mat类
cv::Mat b(a, Rang(2,5), Rang(2,5)); //从a中截取部分数据构造b
cv::Mat c(a, Rang(2,5)); //默认最后一个参数构成c

2.3 视频加载与摄像头调用

#include <opencv2\opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	system("color F0");  //更改输出界面颜色
	VideoCapture video("cup.mp4");
	if (video.isOpened())
	{
		cout << "视频中图像的宽度=" << video.get(CAP_PROP_FRAME_WIDTH) << endl;
		cout << "视频中图像的高度=" << video.get(CAP_PROP_FRAME_HEIGHT) << endl;
		cout << "视频帧率=" << video.get(CAP_PROP_FPS) << endl;
		cout << "视频的总帧数=" << video.get(CAP_PROP_FRAME_COUNT);
	}
	else
	{
		cout << "请确认视频文件名称是否正确" << endl;
		return -1;
	}
	while (1)
	{
		Mat frame;
		video >> frame;
		if (frame.empty())
		{
			break;
		}
		imshow("video", frame);
		waitKey(1000 / video.get(CAP_PROP_FPS));
	}
	waitKey();
	return 0;
}

2.4 数据保存

2.4.1 图像的保存

#include <iostream>
#include <opencv2\opencv.hpp>

using	namespace std;
using	namespace cv;

void AlphaMat(Mat &mat)
{
	CV_Assert(mat.channels() == 4);
	for (int i = 0; i < mat.rows; ++i)
		{
			for (int j = 0; j < mat.cols; ++j)
			{
				Vec4b& bgra = mat.at<Vec4b>(i, j);
				bgra[0] = UCHAR_MAX;  // 蓝色通道
				bgra[1] = saturate_cast<uchar>((float(mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX);  // 绿色通道
				bgra[2] = saturate_cast<uchar>((float(mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX);  // 红色通道
				bgra[3] = saturate_cast<uchar>(0.5 * (bgra[1] + bgra[2]));  // Alpha通道
			}
		}
}
int main(int agrc, char** agrv)
{
	// Create mat with alpha channel
	Mat mat(480, 640, CV_8UC4);
	AlphaMat(mat);
	vector<int> compression_params;
	compression_params.push_back(IMWRITE_PNG_COMPRESSION);  //PNG格式图像压缩标志
	compression_params.push_back(9);  //设置最高压缩质量		
	bool result = imwrite("alpha.png", mat, compression_params);
	if (!result)
	{
		cout << "保存成PNG格式图像失败" << endl;
		return -1;
	}
	cout << "保存成功" << endl;
	return 0;
}

2.4.2 视频的保存

#include <opencv2\opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	Mat img;
	VideoCapture video(0);  //使用某个摄像头

	//读取视频
	//VideoCapture video;
	//video.open("cup.mp4");  

	if (!video.isOpened())  // 判断是否调用成功
	{
		cout << "打开摄像头失败,请确实摄像头是否安装成功";
		return -1;
	}

	video >> img;  //获取图像
	//检测是否成功获取图像
	if (img.empty())   //判断有没有读取图像成功
	{
		cout << "没有获取到图像" << endl;
		return -1;
	}
	bool isColor = (img.type() == CV_8UC3);  //判断相机(视频)类型是否为彩色

	VideoWriter writer;
	int codec = VideoWriter::fourcc('M', 'J', 'P', 'G');  // 选择编码格式
	//OpenCV 4.0版本设置编码格式
	//int codec = CV_FOURCC('M', 'J', 'P', 'G'); 

	double fps = 25.0;  //设置视频帧率 
	string filename = "live.avi";  //保存的视频文件名称
	writer.open(filename, codec, fps, img.size(), isColor);  //创建保存视频文件的视频流

	if (!writer.isOpened())   //判断视频流是否创建成功
	{
		cout << "打开视频文件失败,请确实是否为合法输入" << endl;
		return -1;
	}

	while (1)
	{
		//检测是否执行完毕
		if (!video.read(img))   //判断能都继续从摄像头或者视频文件中读出一帧图像
		{
			cout << "摄像头断开连接或者视频读取完成" << endl;
			break;
		}
		writer.write(img);  //把图像写入视频流
		//writer << img;
		imshow("Live", img);  //显示图像
		char c = waitKey(50);
		if (c == 27)  //按ESC案件退出视频保存
		{
			break;
		}
	}
	// 退出程序时刻自动关闭视频流
	//video.release();
	//writer.release();	
	return 0;
}

2.4.3 保存和读取XML和YMAL文件

#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	system("color F0");  //修改运行程序背景和文字颜色
	//string fileName = "datas.xml";  //文件的名称
	string fileName = "datas.yaml";  //文件的名称
	//以写入的模式打开文件
	cv::FileStorage fwrite(fileName, cv::FileStorage::WRITE);
	
	//存入矩阵Mat类型的数据
	Mat mat = Mat::eye(3, 3, CV_8U);
	fwrite.write("mat", mat);  //使用write()函数写入数据
	//存入浮点型数据,节点名称为x
	float x = 100;
	fwrite << "x" << x;
	//存入字符串型数据,节点名称为str
	String str = "Learn OpenCV 4";
	fwrite << "str" << str;
	//存入数组,节点名称为number_array
	fwrite << "number_array" << "[" <<4<<5<<6<< "]";
	//存入多node节点数据,主名称为multi_nodes
	fwrite << "multi_nodes" << "{" << "month" << 8 << "day" << 28 << "year"
		<< 2019 << "time" << "[" << 0 << 1 << 2 << 3 << "]" << "}";

	//关闭文件
	fwrite.release();

	//以读取的模式打开文件
	cv::FileStorage fread(fileName, cv::FileStorage::READ);
	//判断是否成功打开文件
	if (!fread.isOpened())
	{
		cout << "打开文件失败,请确认文件名称是否正确!" << endl;
		return -1;
	}

	//读取文件中的数据
	float xRead;
	fread["x"] >> xRead;  //读取浮点型数据
	cout << "x=" << xRead << endl;

	//读取字符串数据
	string strRead;
	fread["str"] >> strRead;
	cout << "str=" << strRead << endl;

	//读取含多个数据的number_array节点
	FileNode fileNode = fread["number_array"];
	cout << "number_array=[";
	//循环遍历每个数据
	for (FileNodeIterator i = fileNode.begin(); i != fileNode.end(); i++)
	{
		float a;
		*i >> a;
		cout << a<<" ";
	}
	cout << "]" << endl;

	//读取Mat类型数据
	Mat matRead;
	fread["mat="] >> matRead;
	cout << "mat=" << mat << endl;

	//读取含有多个子节点的节点数据,不使用FileNode和迭代器进行读取
	FileNode fileNode1 = fread["multi_nodes"];
	int month = (int)fileNode1["month"];
	int day = (int)fileNode1["day"];
	int year = (int)fileNode1["year"];
	cout << "multi_nodes:" << endl 
		<< "  month=" << month << "  day=" << day << "  year=" << year;
	cout << "  time=[";
	for (int i = 0; i < 4; i++)
	{
		int a = (int)fileNode1["time"][i];
		cout << a << " ";
	}
	cout << "]" << endl;
	
	//关闭文件
	fread.release();
	return 0;
}
posted @ 2021-08-02 09:41  Rich9999999  阅读(269)  评论(0)    收藏  举报