java 实现视频转字符画
作为一个萌新,也想尝试写写教程。哈哈哈,高手误喷啊。不重复造轮子,很多代码参考其他大神
之前看到网上有很多字符画,感觉很炫,也想尝试完成下。csdn中只找到了python实现的。我们的大java怎么没有呢
话不多少先上效果
效果图
思路分析
- 对视频进行抽帧得到图片
- 对图片进行处理得到字符画
- 按照一定顺序和一定时间在终端打印字符画实现动画效果代码实现
代码实现
为了快速实现功能和方便同学们,这里使用了maven
<!-- https://mvnrepository.com/artifact/org.bytedeco/javacv -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.0</version>
</dependency>
对视频进行抽帧得到图片
public class VideoToImage {
/**
* 视频抽帧
* @param filePath 批量处理,视频所在文件夹
* @param targetPath 输出图片文件夹
* @throws Exception
*/
public static void videoToImage(String filePath,String targetPath ) throws Exception {
File file = new File(filePath);
if (file.isDirectory()){
File[] files = file.listFiles();
for (int i=0; i<files.length; i++) {
String fpath = files[i].getParent()+"\\"+files[i].getName();
//System.out.println(fpath);
String fileName = files[i].getName();
randomGrabberFFmpegImage(fpath, targetPath, fileName.substring(0, fileName.length()-4));
}
}
}
public static void randomGrabberFFmpegImage(String filePath, String targerFilePath, String targetFileName)
throws Exception {
FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
ff.start();
int ffLength = ff.getLengthInFrames();
System.out.println(ffLength);
System.out.println("帧率: " + ff.getFrameRate());
System.out.println("视频长度: " + ff.getLengthInTime());
Frame f;
int t = 3; //抽帧间隔,可以自行调节
for (int k=0; k<ffLength; k++){
String format = String.format("%05d", k);
f = ff.grabImage();
if (k%t==0){
doExecuteFrame(f, targerFilePath, targetFileName, format);
}
}
ff.stop();
}
public static void doExecuteFrame(Frame f, String targerFilePath, String targetFileName, String index) {
if (null == f || null == f.image) {
return;
}
Java2DFrameConverter converter = new Java2DFrameConverter();
String imageMat = "jpg";
String FileName = targerFilePath + File.separator + targetFileName + "_" + index + "." + imageMat;
BufferedImage bi = converter.getBufferedImage(f);
File output = new File(FileName);
try {
ImageIO.write(bi, imageMat, output);
} catch (IOException e) {
e.printStackTrace();
}
}
}
对图片进行处理得到字符画
public class ImageToStr {
/**
* 图片转字符
* @param filePath
* @param targetPath
*/
public static void createAsciiPic(String filePath,String targetPath) {
//final String base = "@#&$%*o!;.";// 字符串由复杂到简单
final String base = "KSPksp;,";
try { //输出图片文件夹
File file = new File(filePath);
FileWriter fileWriter = null;
fileWriter = new FileWriter(targetPath);//创建文本文件
BufferedWriter bw = new BufferedWriter(fileWriter);
if (file.isDirectory()){
File[] files = file.listFiles();
System.out.println(files.length);
for (int i=0; i<files.length; i++) {
//System.out.println(files[i].getName());
BufferedImage image = ImageIO.read(files[i]);
for (int y = 0; y < image.getHeight(); y += 4) {
StringBuilder sss=new StringBuilder ( "" );
for (int x = 0; x < image.getWidth(); x+=2) {
final int pixel = image.getRGB(x, y);
final int r = (pixel & 0xff0000) >> 16, g = (pixel & 0xff00) >> 8, b = pixel & 0xff;
final float gray = 0.299f * r + 0.578f * g + 0.114f * b;
final int index = Math.round(gray * (base.length() + 1) / 255);
sss.append(index >= base.length() ? " " : String.valueOf(base.charAt(index)));
}
String s = sss.toString()+"\r\n";
bw.write(s);// 往已有的文件上添加字符串
}
}
}
bw.close();
fileWriter.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
}
按照一定顺序和一定时间在终端打印字符画实现动画效果代码实现
public class TextMove {
private static final int FRAME_WIDTH = 900;
private static final int FRAME_HEIGHT = 900;
/**
* 字符动画
* @param filePath
* @throws IOException
* @throws InterruptedException
*/
public static void textMove(String filePath) throws IOException, InterruptedException {
//JFrame的相关内容自行学习
JFrame frame = new JFrame();
frame.setTitle("字符动画");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0,FRAME_WIDTH,FRAME_HEIGHT);
frame.setResizable(false); //设置框架是否可由用户调整大小。
frame.setUndecorated(false); //禁用或启用此框架的装饰
JTextArea area = new JTextArea();
area.setBackground(Color.white);
area.setForeground(Color.BLACK);
area.setBounds(0,0,FRAME_WIDTH,FRAME_HEIGHT);
area.setFont(new Font("微软雅黑",Font.PLAIN,10));
frame.add(area);
frame.setVisible(true);
File file =new File(filePath);
show(area,file);
}
/**
* 显示到窗口
* @param area
* @param file
* @throws IOException
* @throws InterruptedException
*/
public static void show(JTextArea area, File file) throws IOException, InterruptedException {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
StringBuffer sb = new StringBuffer();
int line = 0;
int page = 0;
String[] pageStr=new String[41];
while (line <= 4000 ) { //总行数
String str = br.readLine();
sb.append(str+"\r\n");
line++;
if(line%100 == 0){ // 每帧的行数
page++;
//System.out.print(sb);
pageStr[page] = sb.toString();
sb = new StringBuffer();
area.setText(pageStr[page]);
Thread.sleep(25L); //视觉暂留
}
}
for(int j=0;j<1000;j++){
for(String sss : pageStr){
area.setText(sss);
Thread.sleep(25L);
}
}
}
}
最后把这三个步骤串起来
public static void main(String[] args) throws Exception {
//对视频进行抽帧得到图片
VideoToImage.videoToImage("E:\\testmp4","E:\\pic");
//对图片进行处理得到字符画
ImageToStr.createAsciiPic("E:\\pic","E:\\a.txt");
//按照一定顺序和一定时间在终端打印字符画实现动画效果代码实现
TextMove.textMove("E:\\a.txt");
}
最后一步 “按照一定顺序和一定时间在终端打印字符画实现动画效果代码实现 ” 大家根据不同视频大小可以自行调整。也有很多其他实现的方式,希望大家提出更好的解决方案。
好了大功告成 。The Good Night!