画像ファイルから全画素値を取ってくる時の速度比較

| | コメント(0) | トラックバック(0)
画像ファイルの全画素値を配列にコピーする場合の速度比較を行った。

比較するのは以下の3手法。

・方法1: C#
 - C# で Bitmap クラスの GetPixel メソッドを使った
 - 普通の方法
・方法2: C#(unsafe)
 - C# で unsafe を使った
 - ちょっと工夫した方法
・方法3: C++
 - C++ のクラスライブラリを作成し、C# から参照して使った
 - 画像処理ライブラリとして、OpenCV を用いた

一応、比較用に書いたソースは記事末に載っけときました。

557x850 の 24ビットカラー JPEG画像の場合
方法1: 21.6388260748251 (秒)
方法2: 5.06153430618396 (秒)
方法3: 0.0533208579219269 (秒)

方法1の20秒は、ありえないぐらい遅い。
unsafe を用いた方法2で処理時間は1/4になったが、C++を用いた方法3と比べると100倍近く遅い。

方法1はポインタが使えないから遅いというのは分かるような気がするが、ポインタが使える方法2と方法3がこんなに違うのは不思議だ。

JPEG のデコードで時間が掛かってるのか?と思って、ビットマップ画像でも比較。

557x850 の 24ビットカラー ビットマップ画像の場合
方法1: 21.81745337468 (秒)
方法2: 5.01866893115639 (秒)
方法3: 0.0364773279243997 (秒)

あれ?方法1と方法2があんまり変わらんのに、方法3がますます速くなってるし。


まとめ
・大量の画像を相手にしなければいけないときは C++ を使おう。


【追記(2007/11/24)】
Bitmap.Width, Bitmap.Height は意外にコストが高い(内部的にDllImportしたgdiplus.dllを利用している)ので、forループ前に一旦変数に入れてやると多少パフォーマンスが改善されるそうです。(コメントからの情報)

C#
            string fileName = @"C:\test\test.jpg";
            
            Bitmap src = new Bitmap(fileName);

            int[, ,] srcArray0 = new int[src.Width, src.Height, 3];
            int[, ,] srcArray1 = new int[src.Width, src.Height, 3];
            int[, ,] srcArray2;

            Stopwatch sw = new Stopwatch();
            sw.Start();

            for (int x = 0; x < src.Width; x++)
            {
                for (int y = 0; y < src.Height; y++)
                {
                    Color c = src.GetPixel(x, y);
                    srcArray0[x, y, 0] = c.R;
                    srcArray0[x, y, 1] = c.G;
                    srcArray0[x, y, 2] = c.B;
                }
            }

            sw.Stop();
            double sec = (double)sw.ElapsedTicks / (double)Stopwatch.Frequency;
            Console.WriteLine("process0: " + sec.ToString());

            sw.Reset();
            sw.Start();

            BitmapData imgData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, src.PixelFormat);

            unsafe
            {
                byte* p = (byte*)imgData.Scan0.ToPointer();
                for (int i = 0; i < src.Height; i++)
                {
                    for (int j = 0; j < src.Width; j++)
                    {
                        int offset = imgData.Stride * i + (imgData.Stride / imgData.Width) * j;
                        srcArray1[j, i, 0] = p[offset + 2];
                        srcArray1[j, i, 1] = p[offset + 1];
                        srcArray1[j, i, 2] = p[offset + 0];
                    }
                }

            }
            src.UnlockBits(imgData);

            sw.Stop();
            sec = (double)sw.ElapsedTicks / (double)Stopwatch.Frequency;
            Console.WriteLine("process1: " + sec.ToString());

            sw.Reset();
            sw.Start();

            srcArray2 = Class1.TestFunc(fileName);

            sw.Stop();
            sec = (double)sw.ElapsedTicks / (double)Stopwatch.Frequency;
            Console.WriteLine("process2: " + sec.ToString());

C++
	array<int,3>^ Class1::TestFunc(System::String ^fileName) {
		IplImage* srcImg = cvLoadImage((char*)(void*)Marshal::StringToHGlobalAnsi(fileName));

		array<int,3>^ tmp = gcnew array<int,3>(srcImg->width,srcImg->height,3);


		CvPixelPosition8u pos_srcImg;
		CV_INIT_PIXEL_POS( pos_srcImg,
			(unsigned char *) srcImg->imageData,
			srcImg->widthStep,
			cvGetSize(srcImg),
			0, 0,
			srcImg->origin);
		uchar *ptr_srcImg;

		for(int x=0 ; x<srcImg->width ; x++){
			for(int y=0 ; y<srcImg->height ; y++) {
				ptr_srcImg = CV_MOVE_TO(pos_srcImg, x, y, 3);
				tmp[x,y,0] = ptr_srcImg[2];
				tmp[x,y,1] = ptr_srcImg[1];
				tmp[x,y,2] = ptr_srcImg[0];
			}
		}
		
		return tmp; 
	}

トラックバック(0)

このブログ記事を参照しているブログ一覧: 画像ファイルから全画素値を取ってくる時の速度比較

このブログ記事に対するトラックバックURL: http://moro-tyo.sakura.ne.jp/mt/mt-tb.cgi/15

コメントする

このブログ記事について

このページは、moro-tyoが2006年10月10日 00:14に書いたブログ記事です。

ひとつ前のブログ記事は「サンプリング定理・フーリエ変換」です。

次のブログ記事は「主成分分析、独立成分分析」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

プロフィール

profile.jpg

モローチョ(moro-tyo)

Webエンジニア。

詳しいプロフィール

このblogのはてブ

Powered by Movable Type 4.1