之前在B站经常看到有up制作badapple的字符串动画,感觉挺好玩的,今天自己也尝试了一下。
制作字符串动画其实原理也挺简单,
1. 首先,将视频保存为一帧一帧的图片。
2. 然后,用程序读取图片的每个像素点,并获取像素点的颜色值,判断颜色接近黑色还是接近白色,接近黑色的写入字符串到txt文件,接近白色的写入一个空格。
3. 逐张的读取转换好的txt文件显示出来就是逐帧动画了。
下面就以bad apple这段视频作为素材吧,黑白色简单点。
一、准备材料
1. bad apple的视频(自行百度)
2. 绘声绘影,用来将视频转成图片
二、视频转成图片
打开绘声绘影,在下面的时间轴右键,插入视频
然后点击右上角的\[共享\],格式选择自定义-友立图像序列,点右边的齿轮设置一下输出的像素,设置小一点,不需要多大的像素,多了转成字符串也显示不了那么多。

点击开始,稍等一会视频就转换完成了。
二、将图片转成字符串
附上java代码
package com.test;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
public class Image {
public static void main(String\[\] args) {
//初始化线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(100, Integer.MAX\_VALUE, 200, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
//一共要转换5477张图片
for (int i = 0; i < 5477; i++) {
MyTask myTask = new MyTask(i);
executor.execute(myTask);
}
executor.shutdown();
}
}
/\*\*
\* 处理线程
\* @author Administrator
\*
\*/
class MyTask implements Runnable {
private int num;
public MyTask(int num) {
this.num = num;
}
@Override
public void run() {
try {
System.out.println("正在转换第 " + num + "张图片......");
StringBuilder imageName=new StringBuilder("T");
for (int i = 0; i < 4 - String.valueOf(num).length(); i++) {
imageName.append("0");
}
imageName.append(num).append(".JPG");
StringBuilder imgPath=new StringBuilder("C:/Users/Administrator/Desktop/badapple/");
imgPath.append(imageName.toString());
StringBuilder txtPath=new StringBuilder("F:\badappletxt").append(num).append(".txt");
image2txt(imgPath.toString(), txtPath.toString());
System.out.println("第 " + num + "张图片转换完毕");
} catch (Exception e) {
e.printStackTrace();
}
}
/\*\*
\* 将图片转换为字符串
\* @param imgPath
\* @param txtPath
\* @throws Exception
\*/
public void image2txt(String imgPath, String txtPath) throws Exception {
int\[\] rgb = new int\[3\];
File file = new File(imgPath);
BufferedImage bi = null;
try {
bi = ImageIO.read(file);
} catch (Exception e) {
e.printStackTrace();
}
int width = bi.getWidth();
int height = bi.getHeight();
int minx = bi.getMinX();
int miny = bi.getMinY();
StringBuilder sb=new StringBuilder();
for (int i = miny; i < height; i++) {
for (int j = minx; j < width; j++) {
int pixel = bi.getRGB(j, i); // 下面三行代码将一个数字转换为RGB数字
rgb\[0\] = (pixel & 0xff0000) >> 16;
rgb\[1\] = (pixel & 0xff00) >> 8;
rgb\[2\] = (pixel & 0xff);
//判断接近白色还是黑色,接近白色写入空格,接近黑色写入字符串
if (rgb\[0\] > 175&&rgb\[1\]>175&&rgb\[2\]>175) {
sb.append(" ");
} else {
sb.append(getRandomString(1));
}
}
sb.append("
");
}
writeToTxt(txtPath, sb.toString());
}
/\*\*
\* 将字符串写入文件
\* @param filePath
\* @param content
\*/
public void writeToTxt(String filePath, String content) {
BufferedWriter out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath, true)));
out.write(content);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/\*\*
\* 获取随机字符串
\* @param length
\* @return
\*/
public String getRandomString(int length) {
// 定义一个字符串(A-Z,a-z,0-9)即62位;
String str = "zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
// 由Random生成随机数
Random random = new Random();
StringBuffer sb = new StringBuffer();
// 长度为几就循环几次
for (int i = 0; i < length; ++i) {
// 产生0-61的数字
int number = random.nextInt(62);
// 将产生的数字通过length次承载到sb中
sb.append(str.charAt(number));
}
// 将承载的字符转换成字符串
return sb.toString();
}
}
判断颜色的时候我看了下调色板发现rgb都大于175基本上就是白色了,因为bad apple只有黑白两个色,理论上来说要不都是255,要不都是0,但是刚才转图片的时候改了分辨率,产生了颜色损失,可能边缘的地方不都是255或者0,索性就判断一下吧。bad apple还挺准的,其他视频没试过不知道,应该不怎么准。
三、显示字符串
将图片转换成字符串文本之后,将文本一个一个的读取然后显示出来就可以动起来了。可以用java做个桌面程序显示,或者直接控制台也可以。用js也可以做,用ajax请求txt文件然后把文本输出到canvas上也行。这部分就不做了,没别的,就是懒