У меня проблемы с непрерывной загрузкой, обработкой и отображением изображений в 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()
? (для уменьшения выделяемой памяти)
Любые дальнейшие подсказки приветствуются.