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

发布于 2024-11-17 17:01:38 字数 3766 浏览 2 评论 0原文

我在 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();

}

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

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

现在关于我的代码的一些解释:

  • doInBackground() 返回 void,因为我不需要返回任何内容,因为我假设此进程将运行直到取消(这不太可能发生,除非程序关闭)。
  • process() 中,我在 ImageIO.write 中包含了 try/catch 块,只是为了确保我的线程启动并正常工作,
  • 因为事实上我没有使用“SwingUtilities.invokeLater”我读过浏览指南/教程,在我的情况下最好使用 SwingWorker
  • 还有什么让我烦恼:在 process 中,我对扩大的列表进行操作...我不需要那个,我只需要一个元素就够了。那么有没有办法从doInBackground()收集单个对象呢?列出清单对我来说似乎是浪费记忆。或者也许我应该clear()process()末尾的列表? (为了减少分配的内存)

任何进一步的提示都值得赞赏。

I have trouble with continuous image loading&processing&display in Swing:

Below there is simple case where clicking a button causes my program to grab frame from webcam and then display this picture in jlabel. It works as it should, but i have to consecutively click this "Start" button in order to get new image(frame) shown.

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

Im more demanding and i would like to make some image processing during live video stream, therefore i need to "grab" & "show" my frames continuously. You might say that i can just launch webcam stream, but it is not what i want to achieve since i'm about to implement some threshholding/etc. functions which will modify my image on-fly. Therefore i need to perform this grabbing&processin&display as fast as possible (delay is a no-no since i want to achieve something like 10 fps including image processing). Despite the fact that i delay is utterly undesirable i tried to make some Thread.sleep however it didnt work.

Simple while(true) /* presented below */ does not work, my program "hangs" and not even single frame is displayed, although in debugger it keeps working over and over.

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));               
        }            
    }

just in case getPIC_COLOR() was required, i paste it below:

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;
    }

Any help greatly appreciated.


Ok, after some reading i managed to write some SwingWorker Code:

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();

}

Now what seriously bothers me is the fact that my img_field is not updated in swing, although ImageIO.write present in process works, and image is "redrawn" on C:\ with MAD speed ("mad speed" is highly desirable). Moreover my GUI is still frozen even though i created this swing worker thread...

btw i also tried to "sleep" this saving thread for a second, however my GUI hangs even with this additional sleep

Now some explanations about my code:

  • doInBackground() returns void, as i dont need to return anything, since i assume this process will run till cancelled (which is unlikely to happen, unless program is closed).
  • inside process() i've included try/catch block with ImageIO.write just to make sure my thread launched and works
  • i didnt use 'SwingUtilities.invokeLater' due to fact that browsing guides/tutorials i've read that it is better to use SwingWorker in my case
  • What bothers me furthermore: in process i operate on list which enlarges... i dont need that, i just need a single element and thats all. So is there a way to collect single object from doInBackground()? making list seems memory waste for me. Or maybe i should clear() the list at the end of process()? (in order to reduce memory allocated)

Any further hints are appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

她如夕阳 2024-11-24 17:01:38

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

您应该在单独的线程中运行帧抓取,然后使用类似 SwingUtilities.invokeLater 显示它。

You must not run any kind of infinite loop of that form in a method that is called from an event (unless you explicitly intend to hang your user interface, which would be odd to say the least).

You should run your frame grab in a separate thread, and then use something like SwingUtilities.invokeLater to display it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文