ホーム > .NET Framework | Tips | プログラミング > C#でポインタとbyte配列の高速なやり取り

C#でポインタとbyte配列の高速なやり取り

C#で、ポインタとバイト配列を相互にやり取りしたい事が多い。
例えば、画像の画素値を高速に得るためにBitmapData.Scan0を使いたいけど、byte[]に入れて色々処理したい時とか。
Marshal.Copyでいいじゃんと言われそうだけど、たとえばRGB画像のR画像だけ欲しい時、いちいち全部Marshal.Copyしてから扱うのは無駄に思える。
(実際は中の人がDMAを使ってるのか、すごく速い)

やり方は色々思いつくけど、どれが高効率かわからないので、実験してみた。
以下Marshalクラスを眺めたりして思いついた方法。IntPtrが指すRGB画像を色ごとにbyte[]にぶち込むのが目標とする。

  • managed
    • Marshal.Readbyte(…)を使う
      • Readbyte(ptr, ofs)でofsをインクリメント
      • アドレスをインクリメントして、Readbyte(new IntPtr(addr))する
    • Marshal.Copyで普通にやる
      • 全画像Copyして、配列で頑張る
      • 全画像Copyして、1色ずつ画像を完成させていく(Read画像とWrite画像が1つずつにできるので、キャッシュを期待)
      • Line毎にCopyしてみる
      • 画像を幾つかのパートに分けて、マルチスレッド化してLine毎にCopyしてみる
  • unmanaged
    • ptr.ToPointer()からfixed(byte* R_Image)にポインタインクリメントしながらコピー
    • ptr.ToPointer()からMarshal.AllockでコピーしてからMarshal.Copy
    • unmanagedmemorystreamからReadByteする

結論から言うと、Marshal.ReadByteやUnmanagedMemoryStreamは遅かった。前述した通り、Marshal.Copyはとても速いので、これらの関数はこの用途には使えないね。ググってもほとんどMarshal.Copyしか出てこないのはこういう訳か。
unsafeポインタ系はやっぱり速いけど、unsafeはあんまり使いたくないので、Line毎にMarshal.Copyして弄るっていう処理を複数スレッドでやることにする。

以下、検証に使った関数たち

 
protected void MarshalReadByte(BitmapData bd, byte[] r, byte[] g, byte[] b)
{
    int x, y;
    int i_in = 0;
    int i_out = 0;
    int offset = bd.Stride - bd.Width * 3;
 
    for (y = 0; y < bd.Height; ++y)
    {
        for (x = 0; x < bd.Width; ++x)
        {
            b[i_in] = Marshal.ReadByte(bd.Scan0, i_out); ++i_out;
            g[i_in] = Marshal.ReadByte(bd.Scan0, i_out); ++i_out;
            r[i_in] = Marshal.ReadByte(bd.Scan0, i_out); ++i_out;
            ++i_in;
        }
        i_out += offset;
    }
}
 
protected void MarshalCopy(BitmapData bd, byte[] r, byte[] g, byte[] b, byte[] buff)
{
    int x, y;
    int i_in = 0;
    int i_out = 0;
    int offset = bd.Stride - bd.Width * 3;
    for (y = 0; y < bd.Height; ++y)
    {
        for (x = 0; x < bd.Width; ++x)
        {
            b[i_in] = buff[i_out]; ++i_out;
            g[i_in] = buff[i_out]; ++i_out;
            r[i_in] = buff[i_out]; ++i_out;
            ++i_in;
        }
        i_out += offset;
    }
}
 
protected void MarshalCopyChannel(BitmapData bd, byte[] r, byte[] g, byte[] b)
{
    int i, j;
    int stride = bd.Width * 3;
    byte[] buff = new byte[stride * bd.Height];
 
    long addr = bd.Scan0.ToInt64();
    for (i = 0; i < buff.Length; i += stride)
    {
        Marshal.Copy(new IntPtr(addr), buff, i, stride);
        addr += bd.Stride;
    }
 
    for (i = j = 0; i < b.Length; ++i, j += 3) b[i] = buff[j];
    for (i = 0, j = 1; i < g.Length; ++i, j += 3) g[i] = buff[j];
    for (i = 0, j = 2; i < r.Length; ++i, j += 3) r[i] = buff[j];
}
 
protected void MarshalCopyLine(BitmapData bd, byte[] r, byte[] g, byte[] b)
{
    int i, j;
    int stride = bd.Width * 3;
    byte[] buff = new byte[stride];
 
    long addr = bd.Scan0.ToInt64();
 
    i = 0;
    while( i < r.Length   )
    {
        Marshal.Copy(new IntPtr(addr), buff, 0, stride);
        addr += bd.Stride;
 
        j = 0;
        while(j < stride)
        {
            b[i] = buff[j]; ++j;
            g[i] = buff[j]; ++j;
            r[i] = buff[j]; ++j;
            ++i;
        }
    }
}
 
protected void MarshalCopyLineChannel(BitmapData bd, byte[] r, byte[] g, byte[] b)
{
    int i, j, k;
    int stride = bd.Width * 3;
    byte[] buff = new byte[stride];
 
    long addr = bd.Scan0.ToInt64();
 
    i = 0;
    while (i < r.Length)
    {
        Marshal.Copy(new IntPtr(addr), buff, 0, stride);
        addr += bd.Stride;
 
        for (j = i, k = 0; k < stride; ++j, k += 3) b[j] = buff[k];
        for (j = i, k = 1; k < stride; ++j, k += 3) g[j] = buff[k];
        for (j = i, k = 2; k < stride; ++j, k += 3) r[j] = buff[k];
        i += bd.Width;
    }
}
 
protected void MarshalCopyLineTh(BitmapData bd, byte[] r, byte[] g, byte[] b, int StartLine, int Length)
{
    int i, j;
    int stride = bd.Width * 3;
    byte[] buff = new byte[stride];
 
    long addr = bd.Scan0.ToInt64() + StartLine * bd.Stride;
 
    i = StartLine * bd.Width;
    while (i < StartLine * bd.Width + Length)
    {
        Marshal.Copy(new IntPtr(addr), buff, 0, stride);
        addr += bd.Stride;
 
        j = 0;
        while (j < stride)
        {
            b[i] = buff[j]; ++j;
            g[i] = buff[j]; ++j;
            r[i] = buff[j]; ++j;
            ++i;
        }
    }
}
protected void MarshalCopyLineTh(BitmapData bd, byte[] r, byte[] g, byte[] b)
{
    const int ThreadCount = 4;
    int i;
    k2kDelegate.Act<BitmapData, byte[], byte[], byte[], int, int> del = MarshalCopyLineTh;
    var result = new IAsyncResult[ThreadCount];
 
    for (i = 0; i < ThreadCount; ++i) result[i] = del.BeginInvoke(bd, r, g, b, bd.Height / ThreadCount * i, bd.Width * bd.Height / ThreadCount, null, null);
    for (i = 0; i < ThreadCount; ++i) del.EndInvoke(result[i]);
}
 
protected unsafe void PointerInc(BitmapData bd, byte[] r, byte[] g, byte[] b)
{
    int x, y;
    int offset = bd.Stride - bd.Width * 3;
 
    fixed (byte* pr0 = r, pg0 = g, pb0 = b)
    {
        byte* pr = pr0, pg = pg0, pb = pb0;
        byte* p = (byte*)bd.Scan0.ToPointer();
        for (y = 0; y < bd.Height; ++y)
        {
            for (x = 0; x < bd.Width; ++x)
            {
                *pb = *p; ++p; ++pb;
                *pg = *p; ++p; ++pg;
                *pr = *p; ++p; ++pr;
            }
            p += offset;
        }
    }
}
 
protected unsafe void MarshalCopyPointerInc(BitmapData bd, byte[] r, byte[] g, byte[] b, byte[] buff)
{
    int x, y;
    int offset = bd.Stride - bd.Width * 3;
 
    fixed (byte* pr0 = r, pg0 = g, pb0 = b, p0 = buff)
    {
        byte* pr = pr0, pg = pg0, pb = pb0;
        byte* p = p0;
        for (y = 0; y < bd.Height; ++y)
        {
            for (x = 0; x < bd.Width; ++x)
            {
                *pb = *p; ++p; ++pb;
                *pg = *p; ++p; ++pg;
                *pr = *p; ++p; ++pr;
            }
            p += offset;
        }
    }
}
 
protected unsafe void PointerToPointer(BitmapData bd, byte[] r, byte[] g, byte[] b)
{
    int x, y;
    int offset = bd.Stride - bd.Width * 3;
 
    IntPtr pr0 = Marshal.AllocHGlobal(r.Length);
    IntPtr pg0 = Marshal.AllocHGlobal(r.Length);
    IntPtr pb0 = Marshal.AllocHGlobal(r.Length);
 
    byte* pr = (byte*)pr0.ToPointer();
    byte* pg = (byte*)pg0.ToPointer();
    byte* pb = (byte*)pb0.ToPointer();
    byte* p = (byte*)bd.Scan0.ToPointer();
 
    for (y = 0; y < bd.Height; ++y)
    {
        for (x = 0; x < bd.Width; ++x)
        {
            *pb = *p; ++p; ++pb;
            *pg = *p; ++p; ++pg;
            *pr = *p; ++p; ++pr;
        }
        p += offset;
    }
 
    Marshal.Copy(pr0, r, 0, r.Length);
    Marshal.Copy(pg0, g, 0, r.Length);
    Marshal.Copy(pb0, b, 0, r.Length);
 
    Marshal.FreeHGlobal(pr0);
    Marshal.FreeHGlobal(pg0);
    Marshal.FreeHGlobal(pb0);
}
 
 
protected unsafe void UseUnmanagedMemoryStream(BitmapData bd, byte[] r, byte[] g, byte[] b)
{
    int x, y;
    int offset = bd.Stride - bd.Width * 3;
 
    using (var reader = new BinaryReader(
                            new UnmanagedMemoryStream((byte*)bd.Scan0.ToPointer(), bd.Stride * bd.Height)
                        ))
    {
        for (y = 0; y < bd.Height; ++y)
        {
            for (x = 0; x < bd.Width; ++x)
            {
                b[x + y * bd.Width] = reader.ReadByte();
                g[x + y * bd.Width] = reader.ReadByte();
                r[x + y * bd.Width] = reader.ReadByte();
            } 
            reader.ReadBytes(offset);
        }
    }
}

コメント:4

바카라추천http://www.skt1004.com온라인바카라,http://www.skt1004.com 바둑이백화점,바둑이나라,그랜드게임,엠엘비게임,타이탄게임 바카라사이트 주소 skt1004.com,바카라추천,skt1004.com,바카라,skt1004.com 카 2017/02/07

바카라주소,바카라추천,바카라주소,온라인카지노,카지노주소,온라인바카라,바카라사이트,
카지노사이트첫충,재충 이벤트팡팡카지노주소안전공원1등카지노더카지노www.skt1004.com카지노들어가기바카라양방스포츠토토,토토사이트,안전놀이터,안전공원10년무사고,24시콜센터,총알충환전카지노주소skt1004.com바카라주소,www.skt1004.com더카지노,http://www.skt1004.com
바둑이백화점,바둑이나라,그랜드게임,엠엘비게임,타이탄게임
바카라사이트 주소 skt1004.com,바카라추천,
skt1004.com,바카라,skt1004.com
카지노사이트 주소 skt1004.com,카지노천국 skt1004.com
릴게임,skt1004.com

Proteinshake 2018/05/07

Hello just wanted to give you a brief heads up and let you
know a few of the pictures aren’t loading properly.
I’m not sure why but I think its a linking issue. I’ve tried it in two
different browsers and both show the same outcome.

DS真人视讯厅平台|真人娱乐游戏官网、DS真人视讯、DS真人视讯厅、DS真人视讯平台、DS真人娱乐、DS真人娱乐平台、DS真人游戏、DS真人娱乐官网、DS真人游戏官网 2018/09/03

DS真人视讯厅平台|真人娱乐游戏官网
DS真人视讯、DS真人视讯厅、
DS真人视讯平台DS真人娱乐、
DS真人娱乐平台 DS真人游戏
DS真人娱乐官网/DS真人游戏官网/ag真人平台

重庆时时彩、重庆时时彩投注平台、时时彩投注平台、
北京赛车网上投注、北京赛车投注平台、
北京赛车、北京赛车网站腾讯分分彩、
分分彩、分分彩开奖、分分彩投注
五分彩、重庆五分彩、北京五分彩、

AG真人游戏、OG真人棋牌游戏、OG真人游戏、在线真人棋牌游戏、OG真人游戏网站、AG真人游戏平台、AG真人游戏网站、AG真人游戏网站、OG真人游戏网站平台、OG真人游戏官网、AG真人游戏平台网站 2018/10/07

AG真人游戏、OG真人棋牌游戏、
OG真人游戏、在线真人棋牌游戏、
OG真人游戏网站、AG真人游戏平台、
AG真人游戏网站、AG真人游戏网站、
OG真人游戏网站平台、OG真人游戏官网、
AG真人游戏平台网站、在线真人棋牌游戏、
AG真人游戏官方网站、AG真人游戏平台

コメントフォーム
入力した情報を記憶する

トラックバック:0

この記事のトラックバック URL
http://ka.taoka.info/wp-trackback.php?p=183
トラックバックの送信元リスト
C#でポインタとbyte配列の高速なやり取り - ka.taoka.info より

ホーム > .NET Framework | Tips | プログラミング > C#でポインタとbyte配列の高速なやり取り

カレンダー
« 2018 年 10月 »
S M T W T F S
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
最近の反応
メタ情報

ページの上部に戻る