ホーム

ka.taoka.info

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して弄るっていう処理を複数スレッドでやることにする。

    以下、検証に使った関数たち
    続きを読む

    議論

    学生の頃は、コバルト爆弾の人たちや親や環境サークルの人たちと議論する事が日常的にあったような気がする。
    今は、あんまりそういう機会がない。会社での議論は、色々前提条件的なことが多いので、どうしたらよいかやどうすべきかを考えることは殆ど無くて、どうにかしなきゃいけないか、どうしようもないか、という類。

    最近中学生のディベートを見る機会があって、訓練された中学生は僕ら以上に論理構成ができるようになるんだなぁと思った。僕がそういう担当なら間違いなく新入社員研修に導入すると思う。
    今まで論理性って研究とかやってくうちに身についていくものかと思ったけど、そこだけを取り出して鍛えて戦うゲームがあるとは新鮮だった。

    自分はどうすべきか考える力も、それを実現する方法を模索する力も鈍っている気がする。
    しかも3.11以降自分の昔から持っていた事なかれ主義的感情がさらに大きくなってしまった感がある。
    何とかせねば!

    そんなことを考えつつ、宇宙の運命について勉強するお盆休み。
    宇宙の運命

    C#でGenericなJag配列の生成と多次元配列からの変換

    以前に、C#で配列の初期値つきの初期化について書きましたが、今回は更に多次元配列とかJag配列とかを簡単に作りたいっていう話。

    C#では多次元配列(a[2,3]みたいなやつ)も使えますが、僕はJag配列(a[2][3]みたいなやつ)の方が圧倒的に使用頻度が高いです。配列の配列っていう概念の方がわかりやすいし。
    できることとしては何が違うか知りませんが、引数の都合などでたまに多次元配列をJag配列化したいことがあります。
    最初は任意の次元の配列も再帰とかで書ける気がしたんだけど、実は書けないっぽい。

    ついでに、以前の記事のように初期値つきJag配列初期化についても考えたけど、こちらも再帰的に書けないきがしている。
    多次元の配列の初期化は、次元が増えるほど面倒なので、とりあえず妥協して、途中の次元まではArray型の配列型、最後の配列だけGenericに生成するようにして、初期化付きJag配列生成メソッドを書いてみた。

    public class k2kArray
    {
        public static T[][] ConvertToJag<T>(T[,] array)
        {
            int i, j;
            var ret = new T[array.GetLength(0)][];
            int l = array.GetLength(1);
     
            for (i = 0; i < ret.Length; ++i)
            {
                ret[i] = new T[l];
                for (j = 0; j < l; ++j) ret[i][j] = array[i, j];
            }
     
            return ret;
        }
     
        public static TElem[] Init<TElem>(TElem[] arr, TElem InitialValue) where TElem : struct { return Init<TElem>(arr, () => InitialValue); }
        public static TElem[] Init<TElem>(TElem[] arr, Func<TElem> InitElem) { return Init<TElem>(arr, (i) => InitElem()); }
        public static TElem[] Init<TElem>(TElem[] arr, Func<int, TElem> InitElem)
        {
            int i;
            for (i = 0; i < arr.Length; ++i) arr[i] = InitElem(i);
            return arr;
        }
     
        public static TElem[] CreateInit<TElem>(int Length, TElem InitialValue) where TElem : struct { return CreateInit<TElem>(Length, () => InitialValue); }
        public static TElem[] CreateInit<TElem>(int Length, Func<TElem> InitElem) { return CreateInit<TElem>(Length, (i) => InitElem()); }
        public static TElem[] CreateInit<TElem>(int Length, Func<int, TElem> InitElem) { return Init<TElem>(new TElem[Length], InitElem); }
     
        public static Array CreateJagArray<TElem>(Func<TElem> InitElem, params int[] Length)
        {
            return CreateJagArrayDelegate<TElem>(Length, Length.Length, InitElem)();
        }
     
        public static Func<Array> CreateJagArrayDelegate<TElem>(int[] Length, int Dimension, Func<TElem> InitElem)
        {
            if (Dimension == 0)
            {
                return () => CreateInit<TElem>(Length[Dimension], InitElem);
            }
            else
            {
                return () =>
                          CreateInit<Array>(Length[Dimension-1],
                                CreateJagArrayDelegate<TElem>(Length, Dimension - 1, InitElem)
                          );
            }
        }
     
    }

    なんか微妙。string[][]の初期化とかしたいんだけど、Array[]になっちゃう。。
    その後キャストするにしてもうまい方法が思いつかない。
    なんかいい方法ないかな。っていういつもの結論。

    Android用WordPressアプリ

    Androidからここを更新するのが面倒でしたが、Wordpress公式アプリで簡単にできました。
    これで猫がひっくりかえったらすぐに更新できる!
    最近ノートPCが壊れたけど、しばらく買わなくても色々なんとかなるな。AMDのAPUが気になるけど。

    image

    C#で配列の初期値つきの初期化

    C#というか.NET Frameworkって配列に初期値を入れたい時に短い書き方がないよね。
    いちいちforループ書くのめんどくさいし。
    LINQあたりでうまく書けるのかもしれないけど、トリッキーなのもやだし、自分用ライブラリに初期化用メソッドを入れてみた。

    public class k2kArray
    {
    	public static TElem[] Init<TElem>(TElem[] arr, TElem InitialValue) where TElem : struct
    	{
    		return Init<TElem>(arr, () => InitialValue);
    	}
    	public static TElem[] Init<TElem>(TElem[] arr, Func<TElem> InitElem)
    	{
    		return Init<TElem>(arr, (i) => InitElem());
    	}
    	public static TElem[] Init<TElem>(TElem[] arr, Func<int, TElem> InitElem)
    	{
    		int i;
    		for (i = 0; i < arr.Length; ++i) arr[i] = InitElem(i);
    		return arr;
    	}
     
    	public static TElem[] CreateInit<TElem>(int Length, TElem InitialValue) where TElem : struct
    	{
    		return CreateInit<TElem>(Length, () => InitialValue);
    	}
    	public static TElem[] CreateInit<TElem>(int Length, Func<TElem> InitElem)
    	{
    		return CreateInit<TElem>(Length, (i) => InitElem());	
    	}
    	public static TElem[] CreateInit<TElem>(int Length, Func<int, TElem> InitElem)
    	{
    		return Init<TElem>(new TElem[Length], InitElem);
    	}
    }

    ついでに初期化された配列をnewする関数も。
    引数にデリゲートがある関数は参照型用。引数付きコンストラクタが呼びたい気分の時のために作った。
    ついでにIndexに依存する初期値を生成するラムダ式を引数に取れたら便利かと思ったのでそれも追加。
    使うときはこんな感じ。

    byte[] arr1 = k2kArray.CreateInit<byte>( 5, 0xFF );
    string[] arr2 = k2kArray.CreateInit<string>( 5, () => "初期値だよ" );
    string[] arr3 = k2kArray.CreateInit<string>( 5, (i) => string.Format("{0}番目", i) );

    見かけ的には、デリゲートよりnew()制約つけてnewするようにしたほうが良かったかも。余計なこともできるようにするか、シンプルにするか。
    ていうかデリゲートだと遅いかな。

    結局初期化式はあんまりスマートじゃなくなってしまった。
    なんかいい方法ないかな。

    原発勉強会(+猫)

    最近、大学のサークルのOBで原発に関する勉強会をやっている。
    科学的なこと、歴史的なこと、いろいろ深くて考えるのが大変。
    放射性セシウムの半減期ぐらいで、長期的に考えようと思う。

    節電サマータイム中で、5時くらいに帰れる。
    でも、猫と遊んでるとすぐ寝る時間になる。

    Google Appsアップデート

    以前から独自ドメインでGoogle Appsの無料版を使っている。
    レンタルサーバーを借りなくても、独自ドメインでメールが出来たりして便利だったけど、通常のGoogleアカウントで使えるReaderとかが使えなかったり、例えばGoogleドキュメントなどの双方で利用できるサービスでは通常アカウント用と独自ドメインアカウント用の2つのアカウントで別々に利用できてしまって、切り替えや使い分けが面倒だった。

    最近、Google Appsがアップデートして、Readerとかも使えるようになった。
    さらに、通常アカウントと同時に2重ログインして、アカウントを切り替えながら使えるようになった。

    オヌヌメのサービスなのですが、Google先生はこのサービスの存在をあんまりアピールしていないきがする。
    むしろ無料版の存在を隠したがっている気がする。。

    ガーベッジコレクションまかせの画像処理

    画像処理書く時って、画像入れるメモリを確保したり開放したりするけど、ガーベジコレクションに慣れるとめんどくさい。

    OpenCVとか、色んなライブラリも、画像のメモリに関しては気にして書かなきゃいけなくて、C#でいうところのusingで囲得ないようなアルゴリズムも多くて、そのへんのデザインパターンがよくわからない僕としては難しいと思っちゃっています。

    速度とかわりとどうでもよかったり、テスト用のプログラムをサクっと書きたい時には、適当にManagedなbyte配列に画素値をぶっこんでごにょごにょして、適度にGC.Collect()しながら使うのが楽です。

    そのためのライブラリを作ってみたんだけど、メモリを放置できる快感を覚えてしまって、邪道と分かっていながら抜け出せない。。
    試しにつくって以来、結局いろんなフィルタとかを加えて、大きくなりつつある。
    そのうち公開します。

    GUI Toolkit

    おはようじむし
    最近linuxメインなので、GUI Toolkitに何使うか悩み中です。
    C#使いなのでMonoから呼べるラッパーがあると嬉しくて、ライセンスの緩いのがいいんだけど、そうするとwxWidgetしかない。
    でもドキュメント少ないし、とりあえずLGPLなGDI+使い中。
    なんか良いのないかなー。。。

    生きてます

    cats20110603

    cats20110603


    いやあいろんなことがありました。地震とか地震とか。
    震度5弱でしたが、家の中は震度6強ぐらいの荒れようでした。
    米びつがひっくり返って床に米がしいてあり、トイレの壁がひび割れ、水が止めどなく流れ、猫が見つかんない。。。
    あれ以来地震恐怖症で、いつも揺れてる気がするし、ちょっと揺れるだけでドキドキする。

    今更な話はこれくらいにして、
    そういえば猫飼ってます。2匹。
    そろそろ仔猫とは呼べないかな。まだ大きくなりそうだけど。
    好きな人は遊びに来てね。

    最近はLinuxを本気で使い始めたりしていました。
    デスクトップはチップセットのFake RAIDを使っちゃってるし、とりあえずWindows7メインで。
    ノートはMBRがぶっ壊れたこともあり、UbuntuとWindows VistaとPuppy Linuxのマルチブート。Ubuntuメイン。
    MBRはVistaのCDで修復できず、Grubでも起動できず、Grub4dosで何とか起動できた。勉強が足りない。
    当初はUbuntuではなくて、派生ディストリビューションのPeppermintを入れていたけど、メジャーなディストリの方が何かと調べるのが楽なので、昨日Ubuntuに入れ替えた。
    Puppyは軽さに惚れて入れといた。Grub4Dosを入れるきっかけにもなった。

    みなさんも、古い省電力ノートPCに軽いLinuxでも入れて、東京電力に協力しようね!

    1 2 3 4 5

    ホーム

    カレンダー
    « 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      
    最近の反応
    メタ情報

    ページの上部に戻る