天天看點

技術加藝術:用Java創造精美的ASCII字元GIF畫!

作者:Java程式設計世界

在這篇文章中,我們将探讨如何使用Java編寫一個程式,将視訊片段中的圖像生成ASCII字元GIF圖像。本文将包括對程式實作的詳細說明以及源代碼。完整代碼可在評論區留言擷取!!!

技術加藝術:用Java創造精美的ASCII字元GIF畫!

實作方法

在開始編寫程式之前,我們需要了解将視訊轉換為ASCII字元圖像的方法。這可以通過以下步驟實作:

  • 從視訊中提取圖像。
  • 将圖像轉換為灰階圖像。
  • 将每個像素映射到ASCII字元。
  • 将所有ASCII字元組成GIF圖像。

在Java中,我們可以使用Java圖形界面(JavaFX)和Java2D庫來完成這些步驟。JavaFX是Java的一個強大的圖形使用者界面(GUI)工具包,可以建立各種類型的應用程式。Java2D是Java的一個強大的2D繪圖庫,可以處理各種類型的圖像。

程式實作

下面是程式的實作過程:

導入JavaFX和Java2D庫。

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.image.PixelReader;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
           

建立JavaFX應用程式

public class Main extends Application {
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Video to ASCII GIF Converter");
 
        Group root = new Group();
        Scene scene = new Scene(root, 640, 480, Color.BLACK);
 
        Canvas canvas = new Canvas(scene.getWidth(), scene.getHeight());
        root.getChildren().add(canvas);
 
        GraphicsContext gc = canvas.getGraphicsContext2D();
 
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}
           

從視訊中提取圖像

public class Main extends Application {
    private static final String VIDEO_PATH = "path/to/video.mp4";
 
    @Override
    public void start(Stage primaryStage) {
        // ...
 
        // Extract frames from video
        VideoDecoder decoder = new VideoDecoder(VIDEO_PATH);
        List<BufferedImage> frames = decoder.decodeFrames();
    }
}
           

我們使用了VideoDecoder類來從視訊中提取圖像。該類使用JavaCV庫實作,這是一個基于OpenCV的Java庫,可以用來處理視訊和圖像。

import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
 
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
 
public class VideoDecoder {
    private final String videoPath;
 
    public VideoDecoder(String videoPath) {
        this.videoPath = videoPath;
    }
 
    public List<BufferedImage> decodeFrames() {
        List<BufferedImage> frames = new ArrayList<>();
 
        FFmpegFrameGrabber grab = new FFmpegFrameGrabber(videoPath);
    grabber.start();

    Frame frame = null;
    while ((frame = grabber.grabImage()) != null) {
        BufferedImage image = SwingFXUtils.fromFXImage(SwingFXUtils.toFXImage(frame), null);
        frames.add(image);
    }

    grabber.stop();
    return frames;
}
}           

将圖像轉換為灰階圖像

public class Main extends Application {
    // ...
 
    @Override
    public void start(Stage primaryStage) {
        // ...
 
        // Convert frames to grayscale
        List<BufferedImage> grayscaleFrames = new ArrayList<>();
        for (BufferedImage frame : frames) {
            BufferedImage grayscaleFrame = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
            Graphics2D g = grayscaleFrame.createGraphics();
            g.drawImage(frame, 0, 0, null);
            g.dispose();
            grayscaleFrames.add(grayscaleFrame);
        }
    }
}           

我們使用了Graphics2D類将每個圖像轉換為灰階圖像。

将每個像素映射到ASCII字元

public class Main extends Application {
    // ...
 
    private static final String ASCII_CHARS = "@#&$%*o!;:.";
 
    @Override
    public void start(Stage primaryStage) {
        // ...
 
        // Map pixels to ASCII characters
        List<String> asciiFrames = new ArrayList<>();
        for (BufferedImage grayscaleFrame : grayscaleFrames) {
            StringBuilder asciiFrame = new StringBuilder();
            PixelReader pixelReader = grayscaleFrame.getRaster().getPixelReader();
            int width = grayscaleFrame.getWidth();
            int height = grayscaleFrame.getHeight();
            for (int y = 0; y < height; y += 6) {
                for (int x = 0; x < width; x += 3) {
                    int pixel = pixelReader.getSample(x, y, 0);
                    int index = (int) (pixel / 25.6);
                    asciiFrame.append(ASCII_CHARS.charAt(index));
                }
                asciiFrame.append("\n");
            }
            asciiFrames.add(asciiFrame.toString());
        }
    }
}
           

在這裡,我們将每個像素映射到ASCII字元。首先,我們将灰階圖像的像素讀入像素閱讀器中。然後,我們将每個像素的值除以25.6,得到一個介于0到9之間的值。接下來,我們使用這個值來索引ASCII_CHARS字元串中的字元。

将所有ASCII字元組成GIF圖像

public class Main extends Application {
    // ...
 
    private static final String OUTPUT_PATH = "output/ascii.gif";
 
    @Override
    public void start(Stage primaryStage) {
        // ...
 
        // Create GIF from ASCII frames
        AnimatedGifEncoder encoder = new AnimatedGifEncoder();
        encoder.start(OUTPUT_PATH);
        encoder.setDelay(100);
        encoder.setRepeat(0);
        for (String asciiFrame : asciiFrames) {
            BufferedImage image = new BufferedImage(640, 480, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = image.createGraphics();
            g.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 8));
            g.setColor(Color.WHITE);
            g.drawString(asciiFrame, 0, 10);
            g.dispose();
            encoder.addFrame(image);
        }
         encoder.finish();
    }           

完整代碼可在評論區留言擷取!!!