我在使用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();
}
现在严重困扰我的是我的img_field
没有动态更新,尽管ImageIO.write
中存在process
,但C:\上的图像被“重新绘制” MAD速度(非常需要“疯狂速度”)。此外,即使我创建了这个swing工作线程,我的GUI仍然被冻结......
顺便说一下,我也尝试“暂停”这个保存线程一秒钟,但是即使这个额外的睡眠我的GUI也会挂起
现在对我的代码有一些解释:
doInBackground()
返回void,因为我不需要返回任何内容,因为我假设此过程将一直运行直到取消(除非程序关闭,否则不太可能发生)。process()
内部我已经将{/ 1}包含在try / catch块中,以确保我的线程已启动并正常工作ImageIO.write
我操作列表扩大了...我不需要那个,我只需要一个元素就可以了。那么有没有办法从process
收集单个对象?制作名单对我来说似乎是浪费。或者我可能doInBackground()
在clear()
结尾处的列表中process()
? (为了减少分配的内存)感谢任何进一步的提示。
答案 0 :(得分:2)
您不能在从事件调用的方法中运行该表单的任何类型的无限循环(除非您明确打算挂起您的用户界面,这至少可以说是奇怪的。)
你应该在一个单独的线程中运行你的帧抓取,然后使用SwingUtilities.invokeLater之类的东西来显示它。