Непрерывная загрузка / обработка изображений и отображение по нажатию кнопки (в Swing) - PullRequest
0 голосов
/ 28 июня 2011

У меня проблемы с непрерывной загрузкой, обработкой и отображением изображений в Swing:

Ниже приведен простой случай, когда нажатие кнопки приводит к тому, что моя программа захватывает кадр с веб-камеры, а затем отображает это изображение в формате jlabel. Он работает как надо, но мне нужно последовательно нажимать эту кнопку «Пуск», чтобы получить новое изображение (кадр).

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

Я более требовательный, и я хотел бы немного обработать изображение во время потокового видео, поэтому мне нужно «захватывать» и «показывать» мои кадры непрерывно. Вы можете сказать, что я могу просто запустить поток с веб-камеры, но это не то, чего я хочу достичь, так как я собираюсь реализовать некоторые пороги / и т.д. функции, которые будут изменять мое изображение на лету. Поэтому мне нужно выполнить этот захват, обработку и отображение как можно быстрее (задержка - нет-нет, так как я хочу достичь чего-то вроде 10 кадров в секунду, включая обработку изображений). Несмотря на то, что задержка совершенно нежелательна, я попытался заставить Thread.sleep, однако, это не сработало.

Простое, хотя (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 ...

Кстати, я также пытался "спить" эту цепочку сохранения на секунду, однако мой графический интерфейс зависает даже с этим дополнительным сном

Теперь некоторые пояснения по поводу моего кода:

  • doInBackground() возвращает void, поскольку мне не нужно ничего возвращать, поскольку я предполагаю, что этот процесс будет выполняться до отмены (что вряд ли произойдет, если программа не будет закрыта).
  • внутри process() я включил блок try / catch с ImageIO.write только для того, чтобы убедиться, что мой поток запущен и работает
  • я не использовал 'SwingUtilities.invokeLater' из-за того, что я прочитал руководства / руководства по просмотру, что в моем случае лучше использовать SwingWorker
  • Что меня больше всего беспокоит: в process я оперирую списком, который расширяется ... Мне это не нужно, мне просто нужен один элемент, и это все. Так есть ли способ собрать один объект из doInBackground()? создание списка кажется пустой тратой памяти для меня. Или, может быть, я должен clear() список в конце process()? (для уменьшения выделяемой памяти)

Любые дальнейшие подсказки приветствуются.

1 Ответ

2 голосов
/ 28 июня 2011

Вы не должны запускать какой-либо бесконечный цикл этой формы в методе, который вызывается из события (если вы явно не намереваетесь повесить свой пользовательский интерфейс, что было бы странно, если не сказать больше).

Вы должны запустить захват кадра в отдельном потоке, а затем использовать что-то вроде SwingUtilities.invokeLater , чтобы отобразить его.

...