c++ opencv 将视频转化成字符串

直接贴代码,我在这个大佬(https://www.bilibili.com/video/BV1f5411t7oD)的代码基础上进行了修改

这是他的代码:(方便你们更好的理解)

#include
#include
#include
#include
#include

using namespace cv;
using namespace std;

int main()
{
	VideoCapture video;
	Mat frame, gray;
	video.open("E:/黑人抬棺.mp4");
	int cols = video.get(CAP_PROP_FRAME_WIDTH);
	int rows = video.get(CAP_PROP_FRAME_HEIGHT);
	int framecount = video.get(CAP_PROP_FRAME_COUNT);
	int fps = video.get(CAP_PROP_FPS);
	int delty = 10;
	int deltx = 5;
	int value;
	int n = 0;
	char c[] = " .,-'`:!1&@#$";
	vector<string> v;
	HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { 0,0 };
	while (n < framecount)
	{
		n++;
		video.read(frame);
		cvtColor(frame, gray, COLOR_BGR2GRAY);
		string s = "";
		for (int row = 0; row < rows - delty; row = row + delty)
		{
			for (int col = 0; col < cols - deltx; col = col + deltx)
			{
				value = gray.at<uchar>(row, col);
				s = s + c[int(value / 20)];
			}
			s = s + '\n';
		}
		v.push_back(s);
		system("cls");//建议不要在这里用,在下面输出循环之前用,不然会很慢,请参考我的代码
		printf("正在读取:%d/%d", n, framecount);
	}
	for (int i = 0; i < v.size(); i++)
	{
		SetConsoleCursorPosition(h, pos);
		cout << v[i];
		waitKey(1000 / fps);
	}
	return 0;
}

我在原有基础上,

  1. 增加读文件操作,方便那些不懂c++的人放自己喜欢的视频,以及更改显示的字符串和修改每秒显示的帧数;并且可以自行设定字符串之间的间隔
  2. 增加写文件操作,将输出字符串存到对应的文本文件中。(因为这样的文本文件打开很大,并且可能打开时会卡住,所以请根据需要将这个文件留住或者删除,不影响进程)
  3. 将在栈区的数据都改成了堆区,强制类型转换和指针用c++11的格式
  4. 修复了导入某些视频出bug的问题,即增加了通道判断
  5. 增加了注释
  6. 把代码的所有警告都进行了修正(除了opencv的警告我不懂改不了以外)
  7. 这个是没有声音的,声音只能用其他库去加,或者自己用视频合成软件去添加
  8. 针对容器进行了优化,提前扩容,增加效率
  9. 哪怕没人看,我也要认真搞好><
#include
#include
#include
#include
#include
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgproc/types_c.h"

using namespace cv;
using namespace std;

/*如果在opencv源代码有警告,那就是opencv库的原因,不影响具体效果,可以自行用最新的库看看有没有警告*/
int main()
{
	//=================视频路径====================//
	cout << "注意要将视频的路径的\\改成/" << endl<<endl;
	ifstream ifs;
	ifs.open("MyVideo.txt", ios::in);
	if (!ifs.is_open()) {
		cout << "视频文件没有打开" << endl;
		return 0;//失败就返回
	}
	char filePath[1024];
	ifs.getline(filePath, sizeof(filePath));
	ifs.close();
	unique_ptr<VideoCapture> video = make_unique<VideoCapture>(filePath);

	//=================更改信息====================//
	ifstream ifs3;
	ifs3.open("MyInfo.txt", ios::in);
	if (!ifs3.is_open()) {
		cout << "MyInfo文件没有打开" << endl;
		return 0;//失败就返回
	}
	vector<string> myInfoVector;
	myInfoVector.reserve(6);
	string myInfoString;
	while (ifs3 >> myInfoString) {//一个个单词读取数据//可以优化到只读整数
		myInfoVector.push_back(myInfoString);
	}
	ifs3.close();

	//=================读取视频文件的数据====================//

	int cols = static_cast<int>(video->get(CAP_PROP_FRAME_WIDTH));
	int rows = static_cast<int>(video->get(CAP_PROP_FRAME_HEIGHT));
	//总帧数-1,最后一帧不要,否则可能报错
	_int64 framecount = static_cast<_int64>(video->get(CAP_PROP_FRAME_COUNT))-1;
	HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { 0,0 };//起始位置
	int fps = static_cast<int>(video->get(CAP_PROP_FPS));
	int delty = atoi(myInfoVector[4].c_str());//每个字符间的高度
	int deltx = atoi(myInfoVector[5].c_str());//每个字符间的宽度
	int value;//灰度值
	_int64 n = 0;

	//=================字符串路径====================//

	cout << "你可以在MyChar.txt文件中修改展现的字符串" << endl << endl;
	ifstream ifs2;
	ifs2.open("MyChar.txt", ios::in);
	if (!ifs2.is_open()) {
		cout << "字符串文件没有打开" << endl;
		return 0;//失败就返回
	}
	char filePath2[1024];
	ifs2.getline(filePath2, sizeof(filePath2));
	ifs2.close();
	string myChar(filePath2);//字符串路径
	int myCharSize = static_cast<int>(myChar.size());

	//=================储存对应的字符串====================//

	ofstream ofs;
	ifstream ifs_out_test;
	ifs_out_test.open("MyOut.txt", ios::in);
	if (!ifs_out_test.is_open()) {
		cout << "MyOut文件没有打开" << endl << endl;
		ifs_out_test.close();
	}
	else {
		ifs_out_test.close();
		ofs.open("MyOut.txt", ios::out);
	}

	//=================存储灰度值====================//

	//===========对象创建放在循环外面,防止过多调用构造析构=====//
	//用来存放输出的字符
	unique_ptr<vector<string>> v = make_unique<vector<string>>();
	v->reserve(framecount);//节省扩容次数
	unique_ptr<Mat> frame = make_unique<Mat>();
	unique_ptr<Mat> gray = make_unique<Mat>();
	//用于存放字符串
	unique_ptr<string> s = make_unique<string>();
	int reservesize = (rows / delty) * (cols / deltx);
	s->reserve(reservesize);//提高效率

	while (n < framecount)
	{
		n++;
		video->read(*frame);
		//  转换单通道
		if (frame->channels() == 4) {
			s->clear();//clear不会删除原来的内存地址,只会清空数据,用在这正好
			cv::cvtColor(*frame, *gray, CV_BGRA2GRAY);
		}
		else if (frame->channels() == 3) {
			s->clear();
			cv::cvtColor(*frame, *gray, CV_BGR2GRAY);
		}
		else if (frame->channels() == 2) {
			s->clear();
			cv::cvtColor(*frame, *gray, CV_BGR5652GRAY);
		}
		else {
			v->push_back(*s);//防止丢帧
			continue;//不这样,当有的通道为 负数或1时会出bug
		}
		for (int row = 0; row < rows - delty; row = row + delty)
		{
			for (int col = 0; col < cols - deltx; col = col + deltx)
			{	
				value = gray->at<uchar>(row, col);//灰度值,0到255之间
				int index = (value * (myCharSize-1)) / 255 ;//记住-1,不然会越界
				s->push_back(myChar.at(index));//一定要用at,用[]越界了也不知道,一定会出bug
			}
			s->push_back('\n');
		}
		v->push_back(*s);
		printf("Now reading :%lld/%lld\n", n, framecount);
	}

	//=================显示储存的灰度值====================//

	system("cls");
	for (const auto& printValue : *v) {
		SetConsoleCursorPosition(h, pos);
		cout << printValue << endl;
		if (ofs.is_open()) {
			ofs << printValue << endl;
		}
		waitKey(atoi(myInfoVector[3].c_str()) / fps);//1000/25 或者1000/60
		//刷新间隔
	}
	if (ofs.is_open()) {
		ofs.close();
	}
	return 0;
}

注意事项:如果仅仅复制粘贴代码,是无法运行的,必须配置opencv库,至于怎么配置,可以看我的这个教程链接
https://blog.csdn.net/bioinformatique/article/details/105655809

下面是我打包后的exe文件,可以直接用,不需要安装任何库,不需要vs,解压,按照说明,一定可以运行,

(我在注意事项中详细说明了怎么使用这个exe文件,非常简单,并且你们可以随意diy,不懂c++,不懂编程,也可以用我的exe文件将你们的视频转成字符串)

链接:https://pan.baidu.com/s/10rajqK8OZi996LMoKthTBw
提取码:6r3o

如果代码对你有用,或者exe文件你用的很顺手,麻烦点个赞

成品如下

你可能感兴趣的:(opencv)