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

Java 连续图像加载/处理&;单击按钮时显示(在Swing中),java,image,swing,processing,swingworker,Java,Image,Swing,Processing,Swingworker,我无法在Swing中连续加载、处理和显示图像: 下面是一个简单的例子,单击一个按钮会导致我的程序从网络摄像头抓取帧,然后在jlabel中显示此图片。它可以正常工作,但我必须连续单击这个“开始”按钮才能显示新的图像(帧) 我的要求更高,我想在现场视频流中进行一些图像处理,因此我需要不断地“抓取”和“显示”我的帧。您可能会说我可以启动网络摄像头流,但这不是我想要实现的,因为我将要实现一些thresholding/etc.功能,这些功能将动态修改我的图像。因此,我需要尽可能快地执行抓取、处理和显示(延

我无法在Swing中连续加载、处理和显示图像:

下面是一个简单的例子,单击一个按钮会导致我的程序从网络摄像头抓取帧,然后在jlabel中显示此图片。它可以正常工作,但我必须连续单击这个“开始”按钮才能显示新的图像(帧)

我的要求更高,我想在现场视频流中进行一些图像处理,因此我需要不断地“抓取”和“显示”我的帧。您可能会说我可以启动网络摄像头流,但这不是我想要实现的,因为我将要实现一些thresholding/etc.功能,这些功能将动态修改我的图像。因此,我需要尽可能快地执行抓取、处理和显示(延迟是不允许的,因为我希望实现10 fps的速度,包括图像处理)。尽管我拖延时间是完全不受欢迎的,但我还是试着做了一些工作

下面显示的Simple 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();
private void SingleFrameActionPerformed(java.awt.event.ActionEvent evt){
SwingWorker worker=新SwingWorker(){
@凌驾
受保护的Void doInBackground(){
而(!isCancelled()){
显示的\u img=getPIC\u颜色(播放器);
发布(显示);
试一试{
睡眠(1000);
}捕捉(中断异常e){
打破
}
}            
返回null;
}
@凌驾
受保护的无效进程(列表mystuff){
迭代器it=mystuff.Iterator();
而(it.hasNext()){
img_field.setIcon(新图像图标(显示的img));
试一试{
ImageIO.write(显示为“png”,新文件(“c:\\testimg.jpg”);
}捕获(IOEX异常){
Logger.getLogger(TestCAMGUI.class.getName()).log(Level.SEVERE,null,ex);
}
}
}
@凌驾
受保护的void done(){
infoBAR.setText(“完成”);
}
};
worker.execute();
}

现在,让我感到严重困扰的是,我的
img_字段
没有在swing中更新,尽管
ImageIO.write
过程
中有效,并且图像在C:\上以疯狂的速度“重新绘制”(疯狂的速度是非常可取的)。此外,我的GUI仍然冻结,即使我创建了这个swing worker线程

顺便说一句,我还试图“睡眠”这一保存线程一秒钟,但我的GUI挂起,即使有这种额外的睡眠

下面是关于我的代码的一些解释:

  • doInBackground()
    返回void,因为我不需要返回任何内容,因为我假设此进程将一直运行到取消为止(除非程序关闭,否则这不太可能发生)
  • process()
    中,我在
    ImageIO中加入了try/catch块。write
    只是为了确保我的线程启动并正常工作
  • 我没有使用“SwingUtilities.invokeLater”,因为我阅读了浏览指南/教程,在我的案例中使用SwingWorker更好
  • 还有什么困扰着我:在
    过程中
    我操作的列表会放大。。。我不需要它,我只需要一个元素就可以了。那么有没有一种方法可以从
    doInBackground()
    收集单个对象呢?列清单对我来说似乎是浪费记忆。或者我应该
    clear()
    清除
    process()末尾的列表。
    ?(以减少分配的内存)

任何进一步的提示都非常感谢。

您不能在从事件调用的方法中运行任何形式的无限循环(除非您明确地打算挂起您的用户界面,至少可以说这很奇怪)


您应该在一个单独的线程中运行frame grab,然后使用类似的方式来显示它。

您的代码是多线程的吗?在Swing事件调度线程中运行无限while循环肯定是不健康的。嗯,不,它不是,我最初考虑的是多线程,但这个字段我一无所知(因此我没有参与这种高级编程),显然在这种情况下它是强制性的,对吗?尽管如此,我只想执行这个框架gram+进程+显示结果,所以我认为没有必要,尽管在我启动网络摄像头流之前,您需要知道“很少”行,但我猜它可能会对我的无限循环产生一些影响?您基本上需要了解多线程来执行Swing。某些方法必须在Swing事件调度线程(EDT)上运行,而其他方法不得在EDT上运行。在您的情况下,
setIcon
必须在EDT上运行,因为它修改了Swing组件,但是while循环必须在另一个线程上(这是可能的)。我不知道javax.media,所以我不确定
getPIC\u COLOR
是否应该在EDT上运行。感谢您提供有用的提示,我想我必须参与多线程的工作;)@Marian这里有一些反产品步骤,请阅读,左侧是相关线程,以及JButton、SwingWorker的单独操作,将图像/图标保存到单独的viod,类…好的,谢谢帮助,我想我必须浏览一些多线程指南/教程来进一步了解这件事。
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();