Java快速像素操作

11

我想知道如何在Java中最好地处理像素操作。我正在使用swing,并且绘制一个1x1像素的矩形非常缓慢。我需要至少达到60 fps,而不使用太多资源。首先对图像进行blitting是否意味着可以成功实现这一目标?还是用Java完成这项任务是不好的选择,我需要坚持使用C或其他替代方法吗?

我正在编写光线追踪器的初始阶段,由于我正在使用的openCL有一个Java包装器,因此我更喜欢使用Java。


1
我建议您了解中间图像的概念。这里有一个示例 - http://www.java2s.com/Code/Java/Advanced-Graphics/IntermediateImages.htm - mre
我认为中间图像技术沿着我描述的路线,即图像传输。但是,我不熟悉Java中的速度结果,这正是我想知道的。 - RobotRock
这种技术在Java中无法获得60fps的结果,仍然太慢了。 - RobotRock
我不确定这里的评论如何与下面选定的答案相关。 @mre提出的“Intermediate Image”参考中使用了BufferedImage,就像@Devon_C_Miller的答案一样。而且很难想象你不能用60fps绘制一个1 x 1像素的矩形。 - class stacker
2个回答

5

在@camickr的建议上添加:

创建一个BufferedImage(BI),将其包装为IconImage,将其设置为JLabel的图标。在BI上绘制更改,并调用JLabel的repaint()将这些更改刷新到屏幕上。在BI中缓存部分图像减少了绘图例程的工作量。它只需要复制图像而不是渲染图像。使用SwingWorkers部署后台线程来运行计算并将结果传递回EDT进行绘画。

只要你谈论的是静态图像,那就可以很好地工作。如果您考虑像视频游戏一样的东西(一些固定的图像和其他移动的图像),请查看VolatileImage。这里有一个很好的描述:http://gpwiki.org/index.php/Java:Tutorials:VolatileImage

更新:

以下内容给我略高于80 fps:

public class Demo extends javax.swing.JPanel {
    private Image src = null;
    public Demo() {
        new Worker().execute();
    }
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (src != null) g.drawImage(src, 0, 0, this);
    }
    private class Worker extends SwingWorker<Void, Image>{
        private final Color[] colors = { Color.red, Color.green, Color.blue };
        protected void process(List<Image> chunks){
            for (Image bufferedImage : chunks){
                src = bufferedImage;
                repaint();
            }
        }
        protected Void doInBackground() throws Exception{
            int frames = 0;
            int[] mem = new int[1024 * 768];
            long start = System.currentTimeMillis();
            long end = start + 15000;
            long last = start;
            while (last < end){
                int col = colors[frames % colors.length].getRGB();
                for (int y = 0; y < 768; y++)
                    for (int x = 0; x < 1024; x++)
                        mem[x + y * 1024] = col;
                Image img = createImage(new MemoryImageSource(1024, 768, mem, 0, 1024));
                BufferedImage bi = new BufferedImage(1024, 768, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2 = bi.createGraphics();
                g2.drawImage(img, 0, 0, null);
                g2.dispose();
                publish(bi);
                last = System.currentTimeMillis();
                frames++;
            }
            System.err.println("Frames = " + frames + ", fps = " + ((double) frames / (last - start) * 1000));
            return null;
        }
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run(){
                JFrame jf = new JFrame();
                jf.getContentPane().add(new Demo(), BorderLayout.CENTER);
                jf.setSize(1024, 768);
                jf.setVisible(true);
            }
        });
    }
}

我在1024x768的图像上填充像素时,得到了10fps的帧率。有什么想法可以加快速度吗?我正在使用你说的技术,并运行一个无限循环来进行渲染。 - RobotRock
如果只将渲染输出到BI而不实际绘制到屏幕上,您会得到什么样的性能?通常,在光线追踪中的瓶颈更多地在于计算而不是屏幕更新。尝试每次完成一个屏幕的计算时输出System.currentTimeMillis()。 - Devon_C_Miller
我正在绘制非计算像素,所以只是逐个像素地填充屏幕。在320x240时,我可以获得100+ fps,在1024x768时则下降到10。如果我省略repaint(),它不会改变结果。 - RobotRock
2
将x和y循环的顺序交换,以提高性能(更好的局部性)。 - Ben Voigt
记录一下:在 Windows 10 Pro (64 位),jre1.8.0_66,Xeon E3-1230 v3 @ 3.30GHz 和 16 GB 内存上运行以上代码,得到 Frames = 7187,fps = 479.10139324045065 - Jack
显示剩余5条评论

4
使用BufferedImage和setRGB(...)方法。然后在绘制例程中绘制整个图像。

我能通过这种方式(例如在1024x768的分辨率下)满足要求(60 fps)吗? - RobotRock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接