直接贴代码,我在这个大佬(https://www.bilibili.com/video/BV1f5411t7oD)的代码基础上进行了修改
这是他的代码:(方便你们更好的理解)
#include<stdio.h>
#include<opencv2/opencv.hpp>
#include<string>
#include<vector>
#include<windows.h>
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;
}
我在原有基础上,
- 增加读文件操作,方便那些不懂c++的人放自己喜欢的视频,以及更改显示的字符串和修改每秒显示的帧数;并且可以自行设定字符串之间的间隔
- 增加写文件操作,将输出字符串存到对应的文本文件中。(因为这样的文本文件打开很大,并且可能打开时会卡住,所以请根据需要将这个文件留住或者删除,不影响进程)
- 将在栈区的数据都改成了堆区,强制类型转换和指针用c++11的格式
- 修复了导入某些视频出bug的问题,即增加了通道判断
- 增加了注释
- 把代码的所有警告都进行了修正(除了opencv的警告我不懂改不了以外)
- 这个是没有声音的,声音只能用其他库去加,或者自己用视频合成软件去添加
- 针对容器进行了优化,提前扩容,增加效率
- 哪怕没人看,我也要认真搞好><
#include<iostream>
#include<fstream>
#include<opencv2/opencv.hpp>
#include<vector>
#include<windows.h>
#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文件你用的很顺手,麻烦点个赞
成品如下
版权声明:本文为bioinformatique原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。