在 JPanel 中显示图像的问题

问题描述

我正在尝试编写一个应用程序来获取视频帧,处理它们,然后在 JPanel 中将它们显示为图像。我使用 OpenCV 库来获取视频帧(一帧一帧),然后对其进行处理,然后显示在屏幕上(以获得播放视频的效果)。

我使用 Java Swing 创建了 GUI。使用必要的按钮和面板创建了一个窗口应用程序来显示视频。单击“开始”后,将调用方法 playVideo,该方法从所选视频中获取视频帧,对其进行修改并将其显示在面板中。我的代码如下所示:

public class HelloApp {
    private JFrame frame;
    private JPanel panel;
    final JLabel vidpanel1;
    ImageIcon image;
    public static void main(String[] args) {
        EventQueue.invokelater(new Runnable() {

            @Override
            public void run() {
                HelloApp window = new HelloApp();
                window.frame.setVisible(true);
            }
        });
    }

    public void playVideo() throws InterruptedException{
        Mat inFrame = new Mat();
        VideoCapture camera = new VideoCapture();
        camera.open(Config.filename);
        
        while (true) {
            if (!camera.read(inFrame))
                break;
            Imgproc.resize(inFrame,inFrame,new Size(Config.FRAME_WIDTH,Config.FRAME_HEIGHT),0.,Imgproc.INTER_LINEAR);

            ... processing frame

            ImageIcon image = new ImageIcon(Functions.Mat2bufferedImage(inFrame)); // option 0
            vidpanel1.setIcon(image);
            vidpanel1.repaint();
        }
    }

    public HelloApp() {
        frame = new JFrame("MULTIPLE-TARGET TRACKING");
        frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);//new FlowLayout() 
        frame.setResizable(false);
        frame.setBounds(50,50,800,500);
        frame.setLocation(
            (3 / 4) * Toolkit.getDefaultToolkit().getScreenSize().width,(3 / 4) * Toolkit.getDefaultToolkit().getScreenSize().height
        );
        frame.setVisible(true);
        vidpanel1 = new JLabel();

        panel = new JPanel();
        panel.setBounds(11,39,593,371);
        panel.add(vidpanel1);
        frame.getContentPane().add(panel);
        JButton btnStart = new JButton("START / REPLAY");
        btnStart.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                EventQueue.invokelater(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            playVideo();
                        } catch (InterruptedException e) {
                            e.printstacktrace();
                        }
                    }
                });
            }
        });
    }
}

每次点击“开始”按钮时,我都尝试删除旧面板并创建一个新面板,但没有用。我也在运行方法 playVideo 之前尝试使用方法清理所有面板:

panel.removeAll();
panel.repaint();
playVideo();

老实说,我不知道出了什么问题。 GUI 被创建,帧被拍摄和处理,但面板只显示最后一帧。我将不胜感激任何建议:)

解决方法

首先,证明它确实可以以某种方式与您的代码一起工作。
在这里,我阅读了位于 resources 文件夹中的 JPG 图片,但实际上并不重要。

enter image description here

你的代码也有点乱。您在哪里将 btnStart JButton 连接到外面板?您也需要了解how to layout components

您有一个主 JFrame 和一个需要布局的根 JPanel。在这种情况下,我们可以选择 BorderLayout

panel = new JPanel(new BorderLayout());

然后我们添加我们的组件。

panel.add(btnStart,BorderLayout.PAGE_START);
panel.add(vidpanel1,BorderLayout.CENTER);

enter image description here

现在谈到你的问题,你说

GUI 已创建,帧已拍摄并处理,但面板仅显示最后一帧

我不知道“最后一帧”部分有多少是正确的,主要是因为您在 Event Dispatch Thread 内运行了一个无限阻塞循环,这将导致 GUI 冻结并变得无响应。

actionPerformed 中,您实际上应该生成一个新的 Thread,而在 playVideo 中,您应该包装

ImageIcon image = new ImageIcon(Functions.Mat2bufferedImage(inFrame));
vidpanel1.setIcon(image);
vidpanel1.repaint(); // Remove this

EventQueue.invokeAndWait中,例如

// Process frame
...

// Update GUI
EventQueue.invokeAndWait(() -> {
  ImageIcon image = new ImageIcon(Functions.Mat2bufferedImage(inFrame));
  vidpanel1.setIcon(image);
});