1

ここに問題があります: 私はカスタム ハードウェア デバイスを持っており、C#/WPF でそこから画像を取得し、それらをすべて 120+ FPS でウィンドウに表示する必要があります。

問題は、イメージの準備ができたことを示すイベントがないことですが、常にデバイスをポーリングし、新しいイメージがあるかどうかを確認してからダウンロードする必要があります。

どうやらいくつかの方法があるようですが、私はまだ正しい方法を見つけることができませんでした。

これが私が試したことです:

  • シンプルなタイマー (または DispatcherTimer) - 遅いフレーム レートではうまく機能しますが、たとえば 60 FPS を超えることはできません。

  • シングル スレッドの無限ループ - 非常に高速ですが、ウィンドウを再描画するには、DoEvents/それと同等の WPF をループに配置する必要があります。これには、一部のコントロールからのキー押下イベントが発生しないなど、他の望ましくない (奇妙な) 結果があります。

  • 別のスレッドでポーリング/ダウンロードを行い、UI スレッドで表示すると、次のようになります。

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

    これは比較的うまく機能しますが、CPU にかなりの負荷がかかり、もちろん、複数の CPU/コアがない場合はマシンを完全に停止させます。これは容認できません。また、このように多数のスレッド競合があります。

問題は明らかです。より良い代替手段はありますか、またはこの場合、これらのいずれかが適していますか?

更新:
どういうわけかそれについて言及するのを忘れていました (まあ、この質問を書いているときにそれについて考えるのを忘れていました)、もちろん、すべてのフレームを表示する必要はありませんが、保存できるようにすべてをキャプチャする必要がありますハードドライブに。

Update2: DispatcherTimer メソッドが遅いのは、すべてを十分に高速に処理できないためではなく、DispatcherTimer がティック イベントを発生させる前に次の垂直同期を待機するためであることがわかりました。tick イベントでは、保留中のすべての画像をメモリ バッファー (画像をディスクに保存するために使用) に保存し、最後の画像だけを表示できるため、これは実際に私の場合は良いことです。

キャプチャによって完全に「殺されている」古いコンピューターに関しては、WPF は非常に遅いソフトウェア レンダリングにフォールバックするようです。私にできることはきっと何もない。

すべての答えをありがとう。

4

2 に答える 2

1

単純すぎるアプローチを試みていると思います。これが私がすることです。

a) ポーリング ループに Thread.Sleep(5) を配置します。これにより、CPU 時間を低く保ちながら 120fps に近づけることができます。

b) 約 5 フレームごとに表示を更新するだけです。WPFが60fpsをはるかに超える処理を行うように作成されているかどうかわからないため、処理量が削減されます。

c) ThreadPool を使用して、フレームごとにサブタスクを生成し、それをディスクに (フレームごとに別のファイルで) 保存します。これにより、ディスクのパフォーマンスによって制限されることはありません。余分なフレームはメモリに積み上げられます。

個人的には、その順序で実装します。a または b で問題が解決する可能性があります。

于 2010-10-28T13:05:34.377 に答える
-1

以下を実行できます (すべて疑似コード): 1. キャプチャ プロセスを処理するワーカー スレッドを実行します。

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


            }
        }
    }).Start();
  1. ディスパッチャ タイマー スレッドに最新のキャプチャ イメージを取得させ (最後のティック以降、一部のキャプチャを見逃していることは明らかです)、表示します。したがって、UI スレッドは調整され、できる限り少ない処理が行われます。すべての "キャプチャ" は行われません。これはワーカー スレッドによって行われます。申し訳ありませんが、このビットをフォーマットできません(ただし、アイデアはわかります):

    void OnTimerTick(can't remember params)
    

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

  2. リストがキューであり、別のスレッドを使用してキューをブリードし、ディスクなどに書き込む可能性があります。

于 2010-10-28T13:18:53.963 に答える