3
Graphics g;
using (var bmp = new Bitmap(_frame, _height, PixelFormat.Format24bppRgb))
{
    var data = bmp.LockBits(new Rectangle(0, 0, _frame, _height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    var bmpWidth = data.Stride;
    var bytes = bmpWidth * _height;
    var rgb = new byte[bytes];
    var ptr = data.Scan0;
    Marshal.Copy(ptr, rgb, 0, bytes);

    for (var i = 0; i < _frame; i++)
    {
        var i3 = (i << 1) + i;
        for (var j = 0; j < _height; j++)
        {
            var ij = j * bmpWidth + i3;
            var val = (byte)(_values[i, j]);
            rgb[ij] = val;
            rgb[ij + 1] = val;
            rgb[ij + 2] = val;
        }
    }

    Marshal.Copy(rgb, 0, ptr, bytes);
    bmp.UnlockBits(data);

    g = _box.CreateGraphics();
    g.InterpolationMode = InterpolationMode.NearestNeighbor;
    g.DrawImage(bmp, 0, 0, _box.Width, _box.Height);
}
g.Dispose();

このコードを使用して、PictureBox 内の RGB 値 (グレースケール) の配列を変換しますが、遅いです。私の間違いを教えてください。現時点では、441,000 個のアイテムの配列が 35 ミリ秒処理されました。同時に 400 万の配列を処理する必要があります。

4

5 に答える 5

5

Array.Copyとにかく配列内のすべてのデータを上書きするため、画像から配列にデータをコピーする最初の場所をスキップできます。

これにより、25% 程度の時間が短縮されますが、より高速に処理したい場合は、ポインターを使用できるように安全でないコード ブロックを使用する必要があります。そうすれば、配列にアクセスするときに範囲チェックを回避でき、データをコピーする代わりに画像データに直接書き込むことができます。

于 2011-09-23T23:42:16.423 に答える
3

私はグッファの答えに完全に同意します。安全でないコードブロックを使用すると、処理速度が向上します。Parallelパフォーマンスをさらに向上させるために、.Net Frameworkのクラスを使用して、forループを並列に実行できます。大きなビットマップの場合、これによりパフォーマンスが向上します。これが小さなコードサンプルです:

using (Bitmap bmp = (Bitmap)Image.FromFile(@"mybitmap.bmp"))
{
  int width = bmp.Width;
  int height = bmp.Height;

  BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height),
    System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

  byte* s0 = (byte*)bd.Scan0.ToPointer();
  int stride = bd.Stride;

  Parallel.For(0, height, (y1) =>
  {
    int posY = y1*stride;
    byte* cpp = s0 + posY;

    for (int x = 0; x < width; x++)
    {              
      // Set your pixel values here.
      cpp[0] = 255;
      cpp[1] = 255;
      cpp[2] = 255;
      cpp += 3;
    }
  });

  bmp.UnlockBits(bd);
}

例を簡単にするために、ピクセル値を一定の値に設定しました。上記の例をコンパイルするには、安全でないコードを許可する必要があることに注意してください。

お役に立てれば。

于 2011-09-24T21:10:37.350 に答える
1

安全でないコードを使用してこれを試してください。

byte* rp0;
int* vp0;
fixed (byte* rp1 = rgb)
{
    rp0 = rp1;
    fixed (int* vp1 = _values)
    {
        vp0 = vp1;
        Parallel.For(0, _width, (i) =>
        {
            var val = (byte)vp0[i];
            rp0[i] = val;
            rp0[i + 1] = val;
            rp0[i + 2] = val;
        });
    }
}

私にとっては非常に高速に実行されます

于 2011-09-25T08:57:10.493 に答える
1

Guffa の優れたアドバイスに加えて、コードのプロファイルを作成して、時間がかかっている場所を確認することをお勧めします。このタイミングを計るときは、デバッガーを接続せずにリリース モードで実行していることを確認してください。

DrawImageへの呼び出しがほとんどの時間を占めていても、私は驚かないでしょう。そこで画像をスケーリングしていますが、これはかなり高価になる可能性があります。画像を描いているボックスの大きさは?

最後に、これはパフォーマンスには影響しませんが、コードを次のように変更する必要があります。

using (Graphics g = _box.CreateGraphics())
{
    g.InterpolationMode = InterpolationMode.NearestNeighbor;
    g.DrawImage(bmp, 0, 0, _box.Width, _box.Height);
}

そして、例の最初と最後の行を取り除きます。

于 2011-09-23T23:55:53.580 に答える
0

私の理解では、多次元 (正方形) 配列は .Net ではかなり遅いということです。代わりに、_values 配列を 1 次元配列に変更してみてください。ここに 1 つの参照があります。検索すると、さらに多くの参照があります: http://odetocode.com/articles/253.aspx

配列パフォーマンスの例。

using System;
using System.Diagnostics;

class Program
{
static void Main(string[] args)
{
    int w = 1000;
    int h = 1000;

    int c = 1000;

    TestL(w, h);
    TestM(w, h);


    var swl = Stopwatch.StartNew();
    for (int i = 0; i < c; i++)
    {
        TestL(w, h);
    }
    swl.Stop();

    var swm = Stopwatch.StartNew();
    for (int i = 0; i < c; i++)
    {
        TestM(w, h);
    }
    swm.Stop();

    Console.WriteLine(swl.Elapsed);
    Console.WriteLine(swm.Elapsed);
    Console.ReadLine();
}


static void TestL(int w, int h)
{
    byte[] b = new byte[w * h];
    int q = 0;
    for (int x = 0; x < w; x++)
        for (int y = 0; y < h; y++)
            b[q++] = 1;
}

static void TestM(int w, int h)
{
    byte[,] b = new byte[w, h];

    for (int y = 0; y < h; y++)
        for (int x = 0; x < w; x++)
            b[y, x] = 1;
}
}
于 2011-09-23T23:55:40.680 に答える