简介
使用C和OpenCV来请鸡哥在控制台唱,跳,rap,打篮球。music!
首先,让我们来看看这段代码的核心功能。代码的主要目的是读取一个本地视频文件,并将其转换成ASCII字符表示的形式。这是通过读取视频的每一帧,然后将每个像素的灰度值映射到一个预定义的ASCII字符集来实现的。
这个项目使用了多个库,方便调用其API,包括windows.h(系统自带的一些API)、iostream、opencv2/opencv.hpp、easyx.h和mmsystem.h。每个库都有其特定的功能,比如easyx.h用于图形界面的绘制,opencv用于处理视频和图像,而mmsystem.h则用于处理音频。
环境资源准备
下载visual studio,创建一个cpp项目,补全main函数,准备好鸡哥的练习视频放在项目目录下
并去下载并引入所需要的文件
#include <windows.h> // 包含Windows API函数的头文件。
#include <iostream> // 包含输入输出流的标准库。
#include <opencv2/opencv.hpp> // 包含OpenCV库的头文件,用于图像处理和计算机视觉。
#include <easyx.h> // 包含EasyX图形库的头文件,用于简单的图形编程。
#include <mmsystem.h> // 包含多媒体系统函数的头文件,用于音频的播放控制。
#pragma comment(lib,"winmm.lib") // 告诉编译器链接winmm.lib库,以便使用多媒体函数。
#注:OpenCv需要提前去配置,我使用的是visual studio。在项目中配置完了,还要去配置环境变量,然后才能在代码中引入这个文件。配置需要单独的去看,可能有点繁琐。
定义一个窗口并使用命名空间
不同的库和代码文件中可能会定义相同的变量名、函数名或类名。如果没有命名空间的隔离,这些名称冲突会导致编译错误或意想不到的行为。可以简化 OpenCV 函数和类型的调用,如将 cv::Mat
简化为 Mat
。
#define WIDTH 900 // 定义窗口宽度为900像素。
#define HEIGHT 600 // 定义窗口高度为600像素。
using namespace std; // 使用标准命名空间。
using namespace cv; // 使用OpenCV的命名空间。
初始化窗口,并读取视频流
initgraph(WIDTH, HEIGHT); // 初始化EasyX图形窗口,大小为900x600像素。
VideoCapture video("./ikun2.mp4"); // 打开视频文件“ikun2.mp4”进行读取。
mciSendString("open ikun3.mp3 alias bgm", 0, 0, 0);
// 使用多媒体控制接口(MCI)打开音频文件“ikun3.mp3”,并给它分配别名“bgm”。
Mat img; // 定义一个Mat类型的变量img,用于存储当前视频帧。
Mat show; // 定义一个Mat类型的变量show,用于显示缩放后的灰度图像。
设置窗口的字符串显示格式
const char* str = "@#$&%=+*,';+(). ";
// 定义一个字符串,用于字符画的像素表示。字符越前表示亮度越高。
int len = strlen(str); // 获取字符字符串的长度,表示不同亮度的字符种类数。
int index = 0; // 定义一个索引变量,用于选择字符画中的字符。
String text; // 定义一个OpenCV的String对象,用于存储生成的字符行。
settextstyle(12, 0, "楷体"); // 设置字符画文本的字体样式为楷体,字号为12。
setbkmode(TRANSPARENT); // 设置文本背景为透明。
settextcolor(WHITE); // 设置文本颜色为白色。
开始绘制
代码中使用了多线程的技术,通过BeginBatchDraw和EndBatchDraw函数来实现。这样做可以提高程序的性能,确保视频播放的流畅性,不会卡帧。
###将彩色图像转换为灰度图像可以简化处理过程、提高性能、简化字符映射,并且实现起来更简单。这对于生成字符动画(主要针对控制台)尤其重要,因为它让图像的每个像素的亮度信息可以直接映射到字符的不同亮度级别。灰度图像的存储需求比彩色图像少,因为每个像素只需要一个灰度值,而彩色图像每个像素需要三个颜色值(RGB)。
BeginBatchDraw(); // 开始批量绘制,提升绘图性能。
while (1) {
video >> img; // 读取视频中的一帧,存储在img中。
if (img.empty()) { // 检查是否已经读完视频。
break; // 如果视频结束,跳出循环。
}
cvtColor(img, img, COLOR_BGR2GRAY); // 将彩色帧转换为灰度图像。
resize(img, show, Size(300, 150)); // 将灰度图像缩放到300x150尺寸,便于显示。
resize(img, img, Size(150, 50)); // 将图像进一步缩小到150x50尺寸,用于生成字符画。
cleardevice(); // 清空EasyX图形窗口。
for (int x = 0; x < img.rows; x++) { // 遍历每一行像素。
for (int y = 0; y < img.cols; y++) { // 遍历每一列像素。
int color = img.at<uchar>(x, y); // 获取当前像素的灰度值。
index = color / 256.0 * len; // 根据灰度值选择对应的字符画字符索引。
text += str[index]; // 将对应字符添加到当前行的字符文本中。
}
outtextxy(0, x * textheight(str[index]), text.data());
// 在窗口中输出当前行的字符画文本,x坐标固定为0,y坐标为行数乘以字符高度。
text.clear(); // 清空text,为下一行做准备。
}
//对原视频进行处理后的结果,见最后效果图的左上角
imshow("kun", show); // 使用OpenCV显示缩放后的灰度图像。
moveWindow("kun", 0, 0); // 将OpenCV的窗口移动到左上角,
mciSendString("play bgm", 0, 0, 0); // 播放程序背景音乐文件"bgm"。
int key = waitKey(24); // 等待24毫秒以显示帧并检测键盘输入。
if (key == ' ') { // 如果检测到空格键按下,则退出循环。
break;
}
FlushBatchDraw(); // 刷新EasyX窗口中的绘图。
}
结束绘制并关闭图形窗口
EndBatchDraw(); // 结束批量绘制。
closegraph(); // 关闭EasyX图形窗口。
可以通过按空格键来停止视频播放。
效果展示(截图)
说简单点就是将视频的每一帧实时转换为字符动画,并在控制台窗口中显示这些字符动画。
往期文章推荐:
高效JS刷网课脚本https://mp.csdn.net/mp_blog/creation/editor/141573603 python多平台消息轰炸
https://mp.csdn.net/mp_blog/creation/editor/141585953