2

同じ古い GDI 手法を使用して C# で画像処理を行い、ネストされた for ループですべてのピクセルを反復処理し、その (ビットマップ) 画像で GetPixel メソッドと SetPixel メソッドを使用しようとしています。

私はすでにポインターアプローチ(安全でないコンテキストを使用)で同じ結果を得ていますが、ビットマップで遊ぶために古い学校のGet / Set-Pixelメソッドを実行しようとしています...

    Bitmap ToGrayscale(Bitmap source)
    {
        for (int y = 0; y < source.Height;y++ )
        {
            for (int x = 0; x < source.Width; x++)
            {
                Color current = source.GetPixel(x, y);
                int avg = (current.R + current.B + current.G) / 3;
                Color output = Color.FromArgb(avg, avg, avg);
                source.SetPixel(x, y, output);
            }
        }
        return source;
    }

上記のコードのパフォーマンスを考慮すると、1800x1600 の画像の処理が完了するのを待つユーザーにストレスを与えながら、完了するのに時間がかかりすぎます。

そこで、HLSL で使用する手法を使用して、ピクセルごとに個別の関数を実行できると考えました (ピクセル シェーダー エンジン (私が考えていたように) は、float4 (色) を返す関数を GPU に何千回もコピーして、並列処理)。

そこで、ピクセルごとに個別のタスク (関数) を実行して、これらのタスク変数をリストに入れ、List.ToArray() の「待機」を試みました。しかし、次のタスクが実行される前に、すべての新しいタスクが完了するのを「待っている」ため、失敗しました。

これを実行するために、ピクセルごとに新しいタスクを呼び出したいと思いました:

                Color current = source.GetPixel(x, y);
                int avg = (current.R + current.B + current.G) / 3;
                Color output = Color.FromArgb(avg, avg, avg);
                source.SetPixel(x, y, output);

一日の終わりに、非同期の非ブロックコードを取得しましたが、並列ではありません...何か提案はありますか?

4

3 に答える 3

3

GetPixelここでの主なボトルネックでSetPixelある可能性があります。

これを並列化しようとする代わりにBitmap.LockBits、構文解析をより効率的に処理するために を使用することをお勧めします。

そうは言っても、次の方法で現在のバージョンを並列化できます。

Bitmap ToGrayscale(Bitmap source)
{
    Parallel.For(0, source.Height, y =>
    {
        for (int x = 0; x < source.Width; x++)
        {
            Color current = source.GetPixel(x, y);
            int avg = (current.R + current.B + current.G) / 3;
            Color output = Color.FromArgb(avg, avg, avg);
            source.SetPixel(x, y, output);
        }
    });

    return source;
}

ただし、このBitmapクラスはスレッド セーフではないため、問題が発生する可能性があります。

より良いアプローチは、 を使用LockBitsしてから、生データを直接処理することを並列化することです (上記のように)。外側のループのみを (意図的に) 並列化していることに注意してください。これにより、作業項目でコアが過飽和になるのを防ぐことができます。

于 2013-08-22T00:30:42.210 に答える
1

タスクを使用すると、CPU に複数のスレッドが設定されるだけで、グラフィック プロセッサは使用されません。また、使用している Bitmap オブジェクトはスレッド セーフではないことは確かなので、複数のスレッドを使用してそれらにアクセスすることはできません。

画像をグレースケールに変換するだけの場合は、まず組み込みの機能を調べます。一般に、.NET フレームワークに組み込まれているものは、低レベルの「安全でない」コードを使用して、安全でなくても、他の方法よりも効率的に物事を行うことができます。方法: イメージをグレースケールに変換する を試してください。

カスタムビットマップ処理に複数のスレッドを本当に使用したい場合は、バイト配列を作成し、それをマルチスレッドで変更し、最後にバイト配列からビットマップ オブジェクトを作成する必要があると思います。その方法については、 https://stackoverflow.com/a/15290190/1453269を参照してください。

于 2013-08-22T00:43:03.830 に答える