七个礼拜的寒假到今天已经过去一半了,感觉比想象中的还慢一点呢,可能是以前的假期是真的没这么闲吧😂
主要是有关IO的东东,思路很简单,就是把一个个像素替换为对应的字符。
>>> 一:
读取指定位置的图片,在控制台和文件夹输出字符画
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import javax.imageio.ImageIO;
public class Word_1 {
//把in.png转换为out.txt,路径:D:/CC/image2word_2
public static void main(String[] argv) throws IOException {
java.awt.image.BufferedImage img = ImageIO.read(new File(“D:/CC/image2word_2/in.png”));
File newfiFile = new File(“D:/CC/image2word_2/out.txt”);
FileOutputStream fileOutputStream;
int width = img.getWidth();
int height = img.getHeight();
int q = 1;
//多少像素取一个点进行转换,越大越抽象(这种方法有点偷鸡,但大多数情况还行)
int max = 0;
try {
fileOutputStream = new FileOutputStream(newfiFile);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(newfiFile));
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
for (int y = 0; y < height; y += q) {
for (int x = 0; x < width; x += q) {
int r = img.getRGB(x, y);
int red = (r >> 16) & 0x0ff;
int green = (r >> 8) & 0x0ff;
int blue = r & 0x0ff;
//上面三行我具体也不清楚,“r”经过上面的操作,分成能看懂的RGB。
max = Math.max(red, Math.max(green, blue));
if (max < 178) {
bufferedWriter.write(“* “);
System.out.print(“* “);
} else {
bufferedWriter.write(“. “);
System.out.print(“. “);
}
//这里是试出来的,不知道有没有更好的方法
}
bufferedWriter.write(“\n”);
System.out.println(“”);
}
bufferedWriter.close();
outputStreamWriter.close();
fileOutputStream.close();
System.err.println(“ok”);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
颜色
把像素点的RGB数值均调为最大的那个值,那个像素点就成黑白的了,每个像素都做一遍,整个图片就灰化了
例如: R:200 G:100 B:50 -> R:200 G:200 B:200
把上面的改改就能实现灰化图片了,把RGB数值还原回一个数的语句:r = (red << 16) | (green << 8) | blue;
IO流
我就是从这里学的,这里就不把你们往茄子地里带了😝
字符画
得先自己试好一套字体,字符。首先得满足不同字符占位大小是一样的,再自己多试试不同字符字体间的搭配
@ # $ % ^ & X O H I + / . ‘ `
在if语句那里多写几句就可以让字符画细节保留的更多一些,把0~255平均分成若干份就行了(0到255,从黑到白)。都是差不多的
成品
>>> 蛋糕.doc <<<
输入的图片最好提前处理的好一点。相比与靠改程序里的“q”,还是提前把图片缩小好效果好,亮度提前也要调好,不要整个画面都太亮或太暗(除非你有针对这种情况调整程序)
>>> 二:
把Bad apple视频逐帧拆解为图片,再用上面的程序转换为字符画并创建窗口进行播放
下面是实现前半句的程序,从网上复制的。得引用外部库,下一个javacv全都有了
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Test {
// 视频文件路径
private static String videoPath = “D:\图片\test”;
// 视频帧图片存储路径
public static String videoFramesPath = “D:\图片\test”;
public static void grabberVideoFramer(String videoFileName) {
// Frame对象
Frame frame = null;
// 标识
int flag = 0;
FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(videoPath + “/“ + videoFileName);
try {
fFmpegFrameGrabber.start();
int ftp = fFmpegFrameGrabber.getLengthInFrames();
// System.out.println(fFmpegFrameGrabber.grabKeyFrame());
System.out.println(“时长 “ + ftp / fFmpegFrameGrabber.getFrameRate());
BufferedImage bImage = null;
System.out.println(“开始运行视频提取帧,耗时较长”);
while (flag <= ftp) {
// 文件绝对路径+名字
String fileName = videoFramesPath + “/img_” + String.valueOf(flag) + “.jpg”;
// 文件储存对象
File outPut = new File(fileName);
// 获取帧
frame = fFmpegFrameGrabber.grabImage();
// System.out.println(frame);
if (frame != null) {
ImageIO.write(FrameToBufferedImage(frame), “jpg”, outPut);
}
flag++;
}
System.out.println(“============运行结束============”);
fFmpegFrameGrabber.stop();
} catch (IOException E) {
}
}
public static BufferedImage FrameToBufferedImage(Frame frame) {
// 创建BufferedImage对象
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bufferedImage = converter.getBufferedImage(frame);
return bufferedImage;
}
public static void main(String[] args) {
String videoFileName = “123.mp4”;
//这里写视频的文件名
grabberVideoFramer(videoFileName);
}
public static String getVideoPath() {
return videoPath;
}
public static void setVideoPath(String videoPath) {
Test.videoPath = videoPath;
}
}
下面是实现后半句的程序,有两个类(要新建两个class)
Wordplayer中的all参数是看你总共提取出多少图片,如果你是用上面提取的,文件名应该是img_1.jpg,img_2.jpg顺下去的,下面就是不停的打开下一帧的图片
//Wordplayer
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Wordplayer {
public static void main(String[] args) {
new Window();
new cc().start();
}
}
class cc extends Thread {
int width = 0, height = 0, q = 20, r = 0, sleeptime = 1, all = 13147;
String word = “”;
public void run() {
for (int i = 0; i <= all; i++) {
try {
java.awt.image.BufferedImage img = ImageIO.read(new File(“D:\图片\test\img_” + i + “.jpg”));
//上面写你那一帧帧的图片在哪个文件夹,叫什么名
width = img.getWidth();
height = img.getHeight();
for (int y = 0; y < height; y += q) {
for (int x = 0; x < width; x += q) {
r = img.getRGB(x, y);
if (((r >> 16) & 0x0ff) > 178 || ((r >> 8) & 0x0ff) > 178 || ((r >> 8) & 0x0ff) > 178)
word += “.”;
else
word += “*”;
}
word += “\n”;
}
// System.out.println(word);
Window.settext(word);
sleep(sleeptime);
word = “”;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.err.println(“End”);
System.exit(0);
}
}
//Window
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.text.*;
import javax.swing.JTextPane;
import java.awt.Font;
public class Window extends JFrame {
private static final long serialVersionUID = 1L;
static JTextPane textPane = new JTextPane();
private static JPanel contentPane;
public Window() {
setTitle(“Bad apple BY:CC2001”);
setVisible(true);
setAlwaysOnTop(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(900, 500, 465, 385);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
textPane.setFont(new Font(“Calibri Light”, Font.PLAIN, 12));
textPane.setEditable(false);
Style style = new StyleContext().new NamedStyle();
StyleConstants.setLineSpacing(style, -0.6f);
StyleConstants.setFontSize(style, 10);
StyleConstants.setBold(style, true);
textPane.setLogicalStyle(style);
contentPane.add(textPane, BorderLayout.CENTER);
}
public static void settext(String text) {
textPane.setText(text);
textPane.repaint();
}
}
成品

效果还是挺爽的,可能有点吃配置
还没有声音,没法控制播放速度(这里的sleeptime是死的,没法根据运算的快慢进行动态调整)
存一群图片才能放片也是有点不爽的一点