Skip to content

dantecsm/notepad-player

Repository files navigation

notepad-player

用代码在记事本上播放视频

原理概述

视频的基础是图像。要把视频转化为字符动画,首先要知道怎么把一张静态图像转化为字符图像。

假设我们现在能够做到这一点,那么:对任意一个视频,只要提取其所有视频帧,分别“翻译”为字符图像,然后按时间顺序先后写入一个txt文件即可。而播放这个txt文件的方法是:调整记事本窗口到刚好与一帧图像同等大小,按住PageDown令其不断翻页——酱就能展示出动画效果!所以,问题归结为:如何把一张静态图像,“翻译”成一张字符图像?

一般电脑中使用的图像都是RGB图像,先将它转化为灰度图,灰度图所有像素点从黑到白分成256级,表示为0~255。我们称之为灰度值。灰度值越高,一个像素点越亮,灰度值越低,这个像素点越暗。那么如何用字符来表示这种点的亮暗关系呢?很简单,就是以字符本身黑色点在空间中所占的比例来替代图片的灰度值。

想象一下:在一个空间有限的白色正方形中掷点,只掷一个点跟掷成千上万个点,宏观上带给我们的视觉认知是不一样的——前者我们更倾向于认为是白色,后者我们更倾向于当成灰色。为说明这种现象,不妨以两个汉字:“一”与“串”为例,两个单字看上去似乎没有亮暗之分。但当我们把它在有限空间内大量重复的话,就会看到这样的区别: 

密集的一.png

密集的串.png

既然不同字符在大量重复的情况下是有其明暗规律的。根据这一点,我们不妨取出多个字符。统计每个字符在同样空间中所占的比例,按黑像素点所占比例划为256个级别。分别与灰度图的256个灰度值建立一一映射关系。如果我们找到这种映射关系,那么对一张特定的图像,先把它等比例缩放到合适尺寸,再读取此图所有像素点的灰度值,对照着在一个文档中写入相应字符,即可形成字符图像。

对于给定图像, 每次访问像素点时在在字符集中查找与其灰度级相近的字符进行替代比较麻烦,而且遍历会很费时间。一个很好的解决办法就是预先建立一个"字典",每次我们访问一个灰度值时按字典索引到相应的字符即可。


构造字典

这里我选择20902个汉字为素材构建字典。大体步骤是:

  • 首先,我们需要一份汉字的数据集,所以上网下载一份包含所有汉字的txt文档 03准备汉字数据.png

  • 用matlab遍历每一个汉字字符,每个字重复40行40列写入一个个新文档 04汉字重排.png

  • 借助这个小工具,把所有TXT文档图像化 05汉字图像.png

  • 最后,读取所有图像,统计每张图像黑点比例


获取每个汉字的黑点比例后,将其写入Dsty 数组,然后作如下处理:

  • 数据映射:Dsty数组标准化为[0,1]区间的数据,再整体乘以255将区间投影到[0,255]

  • 构造字典:遍历整数0-255。对于每个整数,分别在Dsty数组投影的[0,255]区间中找到与之最接近的数据,对应找到相应的汉字字符,写入字典。

统计所有样本后,得到灰度-汉字字典如下:

06字典图.png

其中,dict的数组下标代表灰度值数组元素代表相应的汉字字符

至此,我们获得了翻译灰度值为字符的字典,有了字典,就可以将静态图像转为字符图像。测试一下效果:


原图

07甜甜私房猫before.png 08伊东杂音before.png


转换图

09甜甜私房猫after.png 10伊东杂音after.png

可见,字典的效果还是很显著的。现在只差临门一脚:

将视频每一帧作字典转换,把结果按时间顺序写入一个txt文件,然后不断翻页,用记事本“播放”一个视频这么一件有bigger的事就实现啦!


实现代码

以下是代码:

%%输入一个视频,输出转换后的txt文件
%%确保跟dictionary.mat(字典数据)在同一目录下

load dictionary;    %载入字典
fid=fopen('merge.txt','wt');    %新建文档
video=VideoReader('op.avi');    %读入视频

for k=1:video.numberofFrame
    Frame=read(video,k);    %读取视频帧
    Frame=rgb2gray(Frame);  %视频帧图像处理开始
    Frame=imresize(Frame,[76,185]);
    Frame=imadjust(Frame,[],[],2.5);
    Frame=histeq(Frame);    %视频帧图像处理结束
    char_pic=dict(double(Frame)+1); %视频帧转化为文本帧
    for j=1:size(Frame,1)   %文本帧写入文档
        fprintf(fid,'%s\n',char_pic(j,:));
    end
end

fclose(fid);    %关闭文档

代码看着简单,是因为我们之前为了构造出这份字典,做了大量铺垫。可以说80%的思考量,都花在构造字典上。以后我们需要画面优化,只须更新字典即可。

注:如果你的电脑配置跟我一样,不是很高的话。用系统自带记事本翻页画面会有闪动,毕竟1秒60页对它似乎比较吃力。这里推荐使用notepad++代替记事本播放代码。


最后附上实现效果

用代码播放一首parasol

Releases

No releases published

Packages

No packages published

Languages