java - 使用 Java 和 awt.Robot 时提高屏幕捕获速度

标签 java java-2d javax.imageio awtrobot

编辑:如果有人还有任何其他提高屏幕捕获性能的建议,请随时分享,因为它可能会完全解决我的问题!

各位开发者大家好,

我正在为自己开发一些基本的屏幕捕获软件。截至目前,我已经获得了一些使用 java.awt.Robot 将屏幕捕获为 BufferedImage 的概念证明/修补代码。然后我在指定的时间内进行此捕获,然后将所有图片转储到磁盘。从我的测试中,我每秒获得大约 17 帧。

试验#1

时长:15 秒 捕获的图像:255

试验#2

时长:15 秒 捕获的图像:229

显然,这对于真正的屏幕捕获应用程序来说还不够好。特别是因为这些捕获只是我在我的 IDE 中选择一些文本,而不是图形密集型的东西。

我现在有两个类(class),一个是主类(class),一个是“监视器”类(class)。 Monitor 类包含捕获屏幕的方法。我的 Main 类有一个基于时间的循环,它调用 Monitor 类并将它返回的 BufferedImage 存储到 BufferedImages 的 ArrayList 中。 如果我修改我的主类以生成多个线程,每个线程执行该循环并收集有关捕获图像时的系统时间的信息,我可以提高性能吗?我的想法是使用一个共享数据结构,它会在我插入帧时根据捕获时间自动对帧进行排序,而不是使用将连续图像插入数组列表的单个循环。

代码:

监控

public class Monitor {

/**
 * Returns a BufferedImage
 * @return
 */
public BufferedImage captureScreen() {
    Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
    BufferedImage capture = null;

    try {
        capture = new Robot().createScreenCapture(screenRect);
    } catch (AWTException e) {
        e.printStackTrace();
    }

    return capture;
}
}

主要内容

public class Main {


public static void main(String[] args) throws InterruptedException {
    String outputLocation = "C:\\Users\\ewillis\\Pictures\\screenstreamer\\";
    String namingScheme = "image";
    String mediaFormat = "jpeg";
    DiscreteOutput output = DiscreteOutputFactory.createOutputObject(outputLocation, namingScheme, mediaFormat);

    ArrayList<BufferedImage> images = new ArrayList<BufferedImage>();
    Monitor m1 = new Monitor();

    long startTimeMillis = System.currentTimeMillis();
    long recordTimeMillis = 15000;

    while( (System.currentTimeMillis() - startTimeMillis) <= recordTimeMillis ) {
        images.add( m1.captureScreen() );
    }

    output.saveImages(images);

}
}

最佳答案

重新使用屏幕矩形和机器人类实例将为您节省一点开销。真正的瓶颈是将所有 BufferedImage 存储到数组列表中。

我会首先对你的 robot.createScreenCapture(screenRect); 的速度进行基准测试。调用没有任何 IO(不保存或存储缓冲图像)。这将为您提供机器人类的理想吞吐量。

long frameCount = 0;
while( (System.currentTimeMillis() - startTimeMillis) <= recordTimeMillis ) {
    image = m1.captureScreen();
    if(image !== null) {
        frameCount++;
    }
    try {
        Thread.yield();
    } catch (Exception ex) {
    }
}

如果事实证明 captureScreen 可以达到您想要的 FPS,则不需要多线程机器人实例。

与其使用缓冲图像的数组列表,不如使用 AsynchronousFileChannel.write 中的 Futures 数组列表。

  • 捕获循环
    • 获取缓冲图像
    • 将 BufferedImage 转换为包含 JPEG 数据的字节数组
    • 创建到输出文件的异步 channel
    • 开始写入并将立即返回值( future )添加到您的 ArrayList
  • 等待循环
    • 检查你的 Futures ArrayList 并确保它们都完成了

关于java - 使用 Java 和 awt.Robot 时提高屏幕捕获速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19843050/

相关文章:

java - 我能说出 BufferedImage 最初的文件类型是什么吗?

java - ImageIO 无法正确导入 BufferedImage

java - 迭代 DFS 以查找从源到目标的路径

java - groovy.swing.factory.BindProxyFactory 在哪里?

java - java图形只渲染窗口大小还是所有内容?

java - 在 Java 中为后台计算创建图形上下文

android - 无法在 Android 应用程序中导入 javax.imageio.ImageIO

java - Functions 类型中的方法 replace(String, String, String) 不适用于参数 (StringBuffer, String, String)

Java - 将日期格式的字符串从 SQL 数据库转换为日期对象以进行比较

java - Spring Data Rest - Bean 验证未应用于 PUT 方法?