【问题标题】:Using JavaCV to display live image from camera使用 JavaCV 显示来自相机的实时图像
【发布时间】:2013-01-12 01:51:01
【问题描述】:

我正在使用 JavaCV 对来自网络摄像头的动态图像进行处理。效果很好!我可以在图片中定义一个感兴趣的区域并在显示之前裁剪每个图像,它仍然可以每秒完成整整 30 帧而没有问题。不错!

但是,我使用 CanvasFrame 对象来显示实时图像。它工作得很好(而且很容易),但对于包含在应用程序中是完全没用的。我想将实时图像放在面板(或画布或其他任何东西)上,作为我的应用程序窗口的一个元素。

问题:CanvasFrame 存在于自己的框架中,并在我的窗口获得焦点时消失在我的窗口后面,并且在我移动窗口时也不会移动。

如何将实时图像添加到可以与常规 UI 元素集成的元素上?

再次,我需要在 JavaCV 中替换 CanvasFrame。 TIA。

【问题讨论】:

  • 进一步测试。由于 CanvasFrame 对象提供了一个 getCanvas() 方法,我尝试使用它,然后将接收到的 Canvas 放入我的 UI。但是,这不起作用。 Frame 仍然作为一个单独的窗口弹出,其中包含其画布(并且正在工作),并且 UI 上的画布保持空白。所以这不能解决我的问题。有什么想法吗?
  • 进一步测试。由于 CanvasFrame 对象提供了 add() 方法,因此我尝试将一些 UI 元素移入其中(而不是相反)。这有效,并且即使 run() 方法继续,事件仍然被处理。但是,我不能在 CanvasFrame 上设置未装饰(我想做)。
  • 我现在确信我将解决这个问题的方法是从 CanvasFrame 的源代码开始,修改它以便它可以不装饰以及您需要修改的任何其他内容(我已经成功完成了) ,然后制作一个修改后的 CanvasFrame,并将其用作整个 UI 的容器(类似于制作容器面板的方式)。我会报告我的结果。
  • 了解 Drawing an Image with Java 2D 并为您从相机获得的每张图像执行此操作!

标签: opencv live javacv


【解决方案1】:

我启动了一个相机线程,该线程循环抓取并在 CanvasFrame 上绘制,直到按下 UI 按钮。这很好用。

响应 UI 按钮按下,我停止线程(这会触发grabber.stop)。然后我拍摄最后一张图像,并将该图像显示在面板上。这很好用(我知道如何显示图像,谢谢)。除了 CanvasFrame 是一个有点糟糕的单独窗口之外,我已经完成了。

因此,我想启动一个相机线程,该线程在循环中抓取并且不在 CanvasFrame 上绘制。相反,它只保留最后一张图像的内部副本。然后为了在我的 UI 上显示,我设置了一个计时器(它可以正确触发)并在我的面板上显示最新的图像。这不起作用——面板保持空白。然而,这个案例与有效的案例有何不同?唯一的区别是相机线程中的抓取器尚未停止。当相机不在其抓取循环中时很好,但在循环时不会显示。而且我很小心地对传递给 UI 的图像进行 cvCopy,因此内存争用没有问题。

我还要说,在 CanvasFrame 上循环显示似乎会触发我的 Logitech C920 自动对焦,而仅抓取单个图像并显示它(只要抓取器停止,我就可以轻松完成)不会似乎自动对焦。

结果是 CanvasFrame 似乎在背景中做了很多棘手的事情,这些事情无法通过仅使用 grabber.start、grabber.grab、grabber.stop 来匹配,然后显示在您自己的面板上。

Sam,我在 CanvasFrame 源代码中看到了你的名字,所以你应该比任何人都清楚我的 2 个场景之间的区别。

【讨论】:

  • 好的,我看到我错误地注释掉了重绘。即使在另一个线程中启动(但未停止)抓取器时,我也可以很好地绘制图像。 ====== ====== 所以你可以在你自己的 UI 元素上绘制它,就像 CanvasFrame 自己做的那样。谢谢山姆,你在图书馆上的出色工作很好——我对每一帧都进行了相当复杂的处理,并且仍然可以比相机提供的速度更快:30+ fps。有时我实际上两次处理同一帧,因为相机线程跟不上 JavaCV 代码!好的。再次感谢。
  • 哦,无论显示什么元素,罗技 C920 中的自动对焦都可以正常工作,因此它工作正常,因为硬件/驱动程序组合甚至在交出图像之前就已经处理了它。这不是世界上最好的自动对焦,但任何自动对焦都可能会遇到困难——注入更多光线会有所帮助。
  • 好吧,如果CanvasFrame 显示为您想要的那样,您是否尝试过在您想要使用的任何Frame 中简单地做类似的事情?
【解决方案2】:

我一直在寻找可以在任何 UI 中使用的 CanvasFrame 替代品,现在我有了。这是一个可以显示实时(或静止)图像的摇摆元素:

import java.awt.Graphics;
import java.awt.image.*;

import javax.swing.JPanel;

public class CamImagePanel extends JPanel {

    private BufferedImage image;

    public CamImagePanel() {
        super();
        // Note that at this point, image = null
        // so be sure to call setImage() before setVisible(true)
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (image != null)      // Not efficient, but safer.
            g.drawImage(image, 0, 0, this);
    }

    public void setImage(BufferedImage img) {
        image = img;
        repaint();
    }
}

然后,我在我的主事件线程中设置了一个计时器,使其每秒唤醒 20 到 30 次(30-50 毫秒),在警报回调方法中,我只需调用 mypanel.setImage(latestPhoto);它就像一个实时图像。

我有一个控制器对象,它有自己的线程,它尽可能快地用来自相机的图像填充缓冲区,我只是向控制器询问最新的图像。这样,不需要同步,我实际上可以要求比相机更快或更慢的图像,而且我的逻辑仍然可以正常工作。

UI 上的按钮停止计时器,我可以将最终图像留在面板上,或者使用 setVisible(false) 完全关闭面板。

【讨论】:

  • 请注意,主线程可以自己执行grabber.grab(),而不是使用单独的线程。请记住,grab() 是一个阻塞读取,这对某些系统来说可能是个问题。如果您使用依赖于后续帧之间差异的算法,则使用单独的线程将不起作用,因为没有同步,您抓取的 2 帧实际上可能是来自相机的单帧。
猜你喜欢
  • 1970-01-01
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多