Использование JavaCV для отображения живого изображения с камеры

Я использую JavaCV для обработки изображений на лету с веб-камеры. Это прекрасно работает! Я могу определить интересующую область на изображении и обрезать каждое изображение перед отображением, и оно по-прежнему будет работать со скоростью полных 30 кадров в секунду без проблем. Хороший!

Однако я использую объект CanvasFrame для отображения живого изображения. Он отлично работает (и прост), но СОВЕРШЕННО БЕСПОЛЕЗЕН для включения в приложение. Я хочу поместить живое изображение на панель (или холст или что-то еще) как один элемент окна моего приложения.

Проблема: CanvasFrame живет в своем собственном фрейме и исчезает за моим окном, когда мое окно получает фокус, а также не перемещается, когда я перемещаю свое окно.

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

Опять же, мне нужна замена CanvasFrame в JavaCV. ТИА.


person Guy Schafer    schedule 24.12.2012    source источник
comment
Дальнейшее тестирование. Поскольку объект CanvasFrame предоставляет метод getCanvas(), я попытался использовать его, а затем поместить полученный холст в свой пользовательский интерфейс. Однако это НЕ РАБОТАЕТ. Фрейм по-прежнему появляется как отдельное окно со своим холстом (и работает), а холст в пользовательском интерфейсе остается пустым. Так что это НЕ РЕШАЕТ МОЮ ПРОБЛЕМУ. Любые идеи?   -  person Guy Schafer    schedule 25.12.2012
comment
Дальнейшее тестирование. Поскольку объект CanvasFrame предоставляет методы add(), я попытался переместить в него некоторые элементы пользовательского интерфейса (а не наоборот). Это сработало, и события все еще обрабатывались, даже когда метод run() продолжался. Однако я не могу установить Undecorated (что я хочу сделать) на CanvasFrame.   -  person Guy Schafer    schedule 25.12.2012
comment
Теперь я убежден, что способ, которым я решу эту проблему, состоит в том, чтобы начать с исходного кода CanvasFrame, изменить его, чтобы его можно было не украшать, и все, что вам нужно изменить (я сделал это успешно), а затем сделать один из ваших измененных CanvasFrame , и используйте его как контейнер для всего пользовательского интерфейса (вроде того, как вы делаете контейнерные панели). Я сообщу о своих результатах.   -  person Guy Schafer    schedule 25.12.2012
comment
Узнайте о рисовании изображения с помощью Java 2D и сделайте это для каждое изображение, которое вы получаете с камеры!   -  person Samuel Audet    schedule 04.01.2013


Ответы (2)


Я запускаю поток камеры, который зацикливается и рисует на CanvasFrame до тех пор, пока не будет нажата кнопка пользовательского интерфейса. ЭТО РАБОТАЕТ ОТЛИЧНО.

В ответ на нажатие кнопки пользовательского интерфейса я останавливаю поток (который запускает функцию «grabber.stop»). Затем я беру последнее изображение и отображаю его на панели. ЭТО РАБОТАЕТ ОТЛИЧНО (я знаю, как отобразить изображение, спасибо). Я бы закончил, за исключением того, что CanvasFrame — это отдельное окно, которое отстой.

Поэтому вместо этого я хочу запустить поток камеры, который зацикливается и НЕ рисует на CanvasFrame. Вместо этого он просто хранит внутреннюю копию последнего изображения. Затем, чтобы отобразить в моем пользовательском интерфейсе, я устанавливаю таймер (который срабатывает правильно) и просто отображаю последнее изображение на своей панели. ЭТО НЕ РАБОТАЕТ - панель остается пустой. И все же, чем этот случай отличается от случая, который работает? Отличие только в том, что граббер в потоке камеры еще не остановлен. Это нормально, когда камера НЕ находится в петле захвата, но НЕ будет отображаться, когда она находится в петле. И я стараюсь делать cvCopy изображений, которые я передаю в пользовательский интерфейс, чтобы не было проблем с конкуренцией за память.

Я также скажу, что отображение на CanvasFrame в цикле, по-видимому, запускает мой автофокус Logitech C920, в то время как просто захват одного изображения и его отображение (что я могу легко сделать, пока захват остановлен), похоже, НЕ работает автоматически. -фокус.

В результате CanvasFrame, кажется, делает много сложных вещей в фоновом режиме, которые не могут быть сопоставлены с помощью только захвата.

Сэм, я видел твое имя в исходном коде CanvasFrame, так что ты лучше всех знаешь, в чем разница между двумя моими сценариями.

person Guy Schafer    schedule 04.01.2013
comment
Хорошо, я вижу, что мой ошибочно закомментированный перерисовывался. Я могу рисовать изображение нормально, ДАЖЕ ПОКА Граббер запущен (но не остановлен) в другом потоке. ====== ====== Таким образом, вы можете нарисовать его на своих собственных элементах пользовательского интерфейса так же, как CanvasFrame делает сам по себе. Спасибо, Сэм, твоя прекрасная работа над библиотекой хороша - я делаю довольно сложную обработку каждого кадра и все же могу делать это быстрее, чем камера может их обеспечить: 30+ кадров в секунду. Иногда я фактически обрабатываю один и тот же кадр дважды, потому что поток камеры не успевает за кодом JavaCV! НИЦЦА. Еще раз спасибо. - person Guy Schafer; 05.01.2013
comment
Да, и автофокус в Logitech C920 работает независимо от того, какой элемент его отображает, поэтому он работает нормально, потому что комбинация аппаратного обеспечения и драйвера обрабатывает его еще до передачи изображения. Это не лучшая автофокусировка в мире, но любая автофокусировка может иметь трудности — помогает пролить больше света. - person Guy Schafer; 05.01.2013
comment
В любом случае, если CanvasFrame отображается так, как вы хотите, пытались ли вы просто сделать что-то подобное в любом Frame, который вы хотите использовать? - person Samuel Audet; 05.01.2013

Я искал замену 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); и это так же, как живое изображение.

У меня есть объект контроллера со своим собственным потоком, который заполняет буфер изображением с камеры так быстро, как только может, и я просто запрашиваю у контроллера последнее изображение. Таким образом, синхронизация не требуется, я действительно могу запрашивать изображения быстрее или медленнее, чем камера может их сделать, и моя логика по-прежнему работает нормально.

Кнопка в пользовательском интерфейсе останавливает таймер, и я могу оставить финальное изображение на панели или полностью закрыть панель с помощью setVisible(false).

person Guy Schafer    schedule 11.01.2013
comment
Обратите внимание, что основной поток мог бы сам выполнить функцию «grabber.grab()» вместо использования отдельного потока. Помните, что функция захвата() блокирует чтение, что может быть проблемой для некоторых систем. Использование отдельного потока не сработает, если вы используете алгоритм, основанный на различиях между последующими кадрами, поскольку без синхронизации два кадра, которые вы получаете, могут фактически быть одним кадром с камеры. - person Guy Schafer; 12.01.2013