C#とWPFとOpenCVSharpを使って非同期で動画のフレームをキャプチャするの時の高速化で試行錯誤って?

c#

はまってたので愚痴で書いただけです。

すべての元凶は「非同期使ってみたかった」というだけです。別スレッドありきですヽ(*^。^*)ノ
適当に無茶なことしても今のCPUならこなしてくれるはず!
(ほかの処理もバリバリ裏で動いている「はず」ですが、一番重いところの、ファイルからフレームを読み込む、サイズを変更する、画面に表示するの部分を別タスクにした例)

タスク内でまとめてやった方が高速って何?とか聞かれても、いろいろ試してくださいとしか(^◇^;
シークとかリサイズとかいろいろ。前後の処理のCPUキャッシュの乗り具合もあるだろうし、データサイズによっては全く意味がないこともあるので。これが答えだっていうのはないと思います。
TS動画再生だけなら1フレームの処理に1/30秒も余裕があるので結構なことができます。ポリゴン処理のレジスタ管理に比べたらぬるいぬるい。適当でもそれなりに動きます(笑)

まぁ、非同期でやらなければいいという話なんですが、CPU暇そうだし、読み込みを別スレッドにした時のオーバーヘッドくらい気にならんだろうという…
そのぉ、動画プレイヤーじゃないので!’`,、’`,、(ノ∀`)’`,、’`,、

OpenCVSharp使って2週間くらいのコードを少し詰めただけなんで、、、、
みんな通る道なので、、、、と、言い訳しつつ。
こんな状況でも動いていたので最適化は中断。もっと簡略化して高速化の道はあると思います。

さんぷる。Mat返すんかい!っていう突込みは置いておいてくださいw
1フレーム処理があるのと可読性のためにフレーム数を使っています。

/* 「フレーム読み込んでサイズ変更」を別スレッドにした感じ */
private async Task GetFrameAsync(int frameNum)
{
    return await Task.Run(() =>
    {
        …

        // シークのフレーム指定はミリ秒のほうが今のソースでは遅延は少なかった(スレッド内でシークしたほうが処理が速いという例)
        int posMsec = (int)((1000 * frameNum) / vCapture.Fps);
        vCapture.Set(CaptureProperty.PosMsec, posMsec);

        // 読み込み
        Mat m = new Mat();
        vCapture.Read(m);

        // エラー&終了処理
        …

        // サイズ変更する
        OpenCvSharp.Size cv2_size = new OpenCvSharp.Size(previewImageWidth, previewImageHeight);
        Mat thumbFrame = new Mat();
        Cv2.Resize(m, thumbFrame, cv2_size);

        // 加工処理やメモリ開放
        …

        return thumbFrame;
    });
}

private async Task DrawPreviewAsync(int frameNum)
{
        // フレームの“φ(._.) チェック!とかいろいろ
        …

        // シークのフレーム指定はミリ秒のほうが今のソースでは遅延は少なかった
        //(さらに外でやって別スレッド中でやらない場合は遅いという話)
        int posMsec = (int)((1000 * frameNum) / vCapture.Fps);
        vCapture.Set(CaptureProperty.PosMsec, posMsec);

        Mat m = await GetFrameAsync(frameNum);
        if(m != null) {
            PreviewImage.Source = m.ToWriteableBitmap();
        }else{

        …

        return true;
}

※ 要点:非同期の場合ですが!
・シークはミリ秒指定にする
・スレッドの中でシークする
これだけでフレームキャプチャの処理はかなり改善されると思います。

と、未来の自分にメモを残す。
この手のヤツを集めるとかなり軽くなるんだろうなぁ・゚・(ノД`)・゚・

—課題
・capture.Read(mat);
・mat=RetrieveMat();
奥が深い。やれることはまだまだあるってことだね。
メモリ確保&使いまわし。同じサイズならもっと効率上げられそう…

ネタがないのでにゃんこの絵で癒される…
デスクトップと参考フレームが重なる瞬間!’`,、’`,、(ノ∀`)’`,、’`,、