Отображение изображений с высокой частотой кадров - PullRequest
1 голос
/ 28 октября 2010

вот в чем проблема: у меня есть нестандартное аппаратное устройство, и мне нужно взять изображения с него в C # / WPF и отобразить их в окне, все со 120 + FPS.

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

По-видимому, существует несколько способов сделать это, но у меня нетНе удалось найти правильный.

Вот что я попробовал:

  • Простой таймер (или DispatcherTimer) - отлично работает для медленных кадров, но яне можем пройти мимо, скажем, 60 FPS.

  • Однопоточный бесконечный цикл - довольно быстро, но я должен поместить DoEvents / его WPF-эквивалент в цикл для окнабыть перерисованным;это имеет некоторые другие нежелательные (странные) последствия, такие как события нажатия клавиш от некоторых элементов управления, которые не запускаются и т. д.

  • Выполнение опроса / загрузки в другом потоке и отображение в потоке пользовательского интерфейса, что-то вродеэто:

     new Thread(() =>
            {
                while (StillCapturing)
                {
                    if (Camera.CheckForAndDownloadImage(CameraInstance))
                    {
                        this.Dispatcher.Invoke((Action)this.DisplayImage);
                    }
                }
            }).Start();
    

    Ну, это работает относительно хорошо, но сильно загружает ЦП и, конечно, полностью убивает машину, если на ней нет более одного ЦП / ядра, что недопустимо.Кроме того, у меня есть большое количество споров о потоках.

Вопрос очевиден - есть ли лучшие альтернативы, или один из них - путь в этом случае?

Обновление:
Я как-то забыл упомянуть об этом (ну, забыл подумать об этом при написании этого вопроса), но, конечно, мне не нужно все *Отображается 1032 * кадра, однако мне все еще нужно захватить их все, чтобы их можно было сохранить на жесткий диск.

Update2: Я обнаружил, что метод DispatcherTimer медленный не потому, что он не может обработать все достаточно быстро, а потому, что DispatcherTimer ожидает следующую вертикальную синхронизациюперед запуском тика;что на самом деле хорошо в моем случае, потому что в тиковом событии я могу сохранить все ожидающие изображения в буфер памяти (используемый для сохранения изображений на диск) и отобразить только последнее.

Что касается старых компьютеровПолностью «убитый» захватом, кажется, что WPF возвращается к программному рендерингу, который очень медленный.Наверное, я ничего не могу поделать.

Спасибо за все ответы.

Ответы [ 2 ]

1 голос
/ 28 октября 2010

Я думаю, вы пытаетесь использовать слишком упрощенный подход.Вот что я бы сделал.

a) поместите Thread.Sleep (5) в цикл опроса, который должен позволить вам приблизиться к 120 кадрам в секунду, сохраняя при этом низкое время процессора.

b) Обновлять только дисплейкаждый 5-й кадр или около тогоЭто сократит объем обработки, так как я не уверен, что WPF создан для обработки гораздо более 60 кадров в секунду.

c) Используйте ThreadPool для создания подзадачи для каждого кадра, который затем будет идти, и сохраните его.на диск (в отдельном файле на кадр), таким образом вы не будете так ограничены производительностью диска.Дополнительные кадры будут просто накапливаться в памяти.

Лично я бы реализовал их в таком порядке.Скорее всего, а или б решит ваши проблемы.

0 голосов
/ 28 октября 2010

Вы можете сделать следующее (все psuedocode): 1. Запустить рабочий поток, работающий с процессом захвата:

List<Image> _captures = new List<Image>();
 new Thread(() =>
    {
        while (StillCapturing)
        {
            if (Camera.CheckForAndDownloadImage(CameraInstance))
            {
                lock(_locker){_captures.Add(DisplayImage);


            }
        }
    }).Start();
  1. Получить поток таймера диспетчера для последнего захваченного изображения(очевидно, что он пропустил некоторые снимки со времени последнего тика) и показ.Поэтому поток пользовательского интерфейса регулируется и делает как можно меньше, он не выполняет всю «захват», это делают рабочие потоки.извините, я не могу отформатировать этот бит (но вы поняли идею):

    void OnTimerTick(can't remember params)
    

    {Image imageToDisplay;lock (_locker) {imageToDisplay = _captures [k.Count - 1];DisplayFunction (imageToDisplay);}

  2. Возможно, список является очередью, а другой поток используется для удаления очереди и записи на диск или чего-либо другого.

...