连续图像加载/处理&单击按钮时显示(在Swing中)

时间:2011-06-28 17:26:23

标签: java image swing processing swingworker

我在使用Swing进行连续图像加载和处理以及显示时遇到问题:

下面是一个简单的例子,单击按钮会使我的程序从网络摄像头抓取帧,然后在jlabel中显示该图片。它应该工作,但我必须连续点击这个“开始”按钮,以获得显示的新图像(帧)。

private void StartActionPerformed(java.awt.event.ActionEvent evt) {                                      
           displayed_img = this.getPIC_COLOR(player);       
           img_field.setIcon(new ImageIcon(displayed_img));
        }

我要求更高,我想在实时视频流中进行一些图像处理,因此我需要“抓住”& “连续”显示我的画面。你可能会说我可以启动网络摄像头流,但它不是我想要实现的,因为我即将实现一些阈值/等。功能将在运行中修改我的图像。因此,我需要尽可能快地执行此抓取和处理和显示(延迟是禁忌,因为我想实现类似10 fps的内容,包括图像处理)。尽管我的延迟是完全不合需要的,但我试图制作一些Thread.sleep,但它没有用。

简单的while(true)/ *在* /下面显示不起作用,我的程序“挂起”,甚至不显示单帧,尽管在调试器中它一直在反复工作。

private void StartActionPerformed(java.awt.event.ActionEvent evt) {                                      
        while(true){
            displayed_img = this.getPIC_COLOR(player);
            //threshholding & further processing...
            img_field.setIcon(new ImageIcon(displayed_img));               
        }            
    }

以防万一需要getPIC_COLOR(),我将其粘贴到下面:

public BufferedImage getPIC_COLOR(Player player){

            FrameGrabbingControl frameGrabber = (FrameGrabbingControl)player.getControl("javax.media.control.FrameGrabbingControl");
            Buffer buf = frameGrabber.grabFrame();
            Image img = (new BufferToImage((VideoFormat)buf.getFormat()).createImage(buf));
            BufferedImage buffImg = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB);
            Graphics2D g = buffImg.createGraphics();            
            g.drawImage(img, null, null);

            return buffImg;
    }

非常感谢任何帮助。


好的,经过一些阅读后,我设法编写了一些SwingWorker代码:

private void SingleFrameActionPerformed(java.awt.event.ActionEvent evt) {
   SwingWorker<Void, BufferedImage> worker = new  SwingWorker<Void, BufferedImage>() { 
    @Override
    protected Void doInBackground() {

        while (!isCancelled()) {
            displayed_img = getPIC_COLOR(player);
            publish(displayed_img);
            try {
                Thread.sleep(1000);  

            } catch (InterruptedException e) {
                break;
            }
        }            
        return null;
    }

    @Override
    protected void process(List mystuff) {

        Iterator it = mystuff.iterator();            
        while (it.hasNext()) { 
            img_field.setIcon(new ImageIcon(displayed_img));
                try {
                    ImageIO.write(displayed_img, "png", new File("c:\\testimg.jpg"));                        
                } catch (IOException ex) {
                    Logger.getLogger(TestCAMGUI.class.getName()).log(Level.SEVERE, null, ex);
                }
        }
    }

    @Override
    protected void done() {
        infoBAR.setText("FINISHED");
    }
};
   worker.execute();

}

现在严重困扰我的是我的img_field没有动态更新,尽管ImageIO.write中存在process,但C:\上的图像被“重新绘制” MAD速度(非常需要“疯狂速度”)。此外,即使我创建了这个swing工作线程,我的GUI仍然被冻结......

顺便说一下,我也尝试“暂停”这个保存线程一秒钟,但是即使这个额外的睡眠我的GUI也会挂起

现在对我的代码有一些解释:

  • doInBackground()返回void,因为我不需要返回任何内容,因为我假设此过程将一直运行直到取消(除非程序关闭,否则不太可能发生)。
  • process()内部我已经将{/ 1}包含在try / catch块中,以确保我的线程已启动并正常工作
  • 我没有使用'SwingUtilities.invokeLater',因为浏览指南/教程我已经读过,在我的情况下最好使用SwingWorker
  • 更令我烦恼的是:在ImageIO.write我操作列表扩大了...我不需要那个,我只需要一个元素就可以了。那么有没有办法从process收集单个对象?制作名单对我来说似乎是浪费。或者我可能doInBackground()clear()结尾处的列表中process()? (为了减少分配的内存)

感谢任何进一步的提示。

1 个答案:

答案 0 :(得分:2)

您不能在从事件调用的方法中运行该表单的任何类型的无限循环(除非您明确打算挂起您的用户界面,这至少可以说是奇怪的。)

你应该在一个单独的线程中运行你的帧抓取,然后使用SwingUtilities.invokeLater之类的东西来显示它。