「トップページ/CPPCLI/IMAGE/BITMAP-COST」の編集履歴(バックアップ)一覧はこちら

トップページ/CPPCLI/IMAGE/BITMAP-COST」(2007/10/24 (水) 09:59:25) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

|&big(){いろいろ}| #contents() ---- *System.Bitmapにおける、Lock,Unlockのコスト  ポインタでBitmapにアクセスするときに欠かせないのがLockとUnlockメソッドです。  このLockに渡すPixelFormatって、いじりやすいってだけで、なんとなくFormat24bppRgbにしたりしてないでしょうか?そもそも、Bitmap自体の生成時に、PixelFormatを特に指定しなかったりしてないでしょうか?  簡単な実験の結果、BitmapとLockメソッドで指定するPixelFormatを揃えていないと、以外と大きなコストを払っていることが分かりました。 #ref(BitmapLockToUnlockTime.gif) // [共通プロパティ]→[参照設定]で、System.Drawingを追加する。 using namespace System; using namespace System::Drawing; using namespace System::Drawing::Imaging; //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ // 指定されたBitmapに対し、指定されたPixelFormatでLock,Unlockを行い、時間を計測する。 void TestLockToUnlockTime(Bitmap^ bmp, PixelFormat fmt) { const int LoopCnt = 1000; Console::Write(" {0,-20} = ", fmt.ToString()); Diagnostics::Stopwatch^ sw = gcnew Diagnostics::Stopwatch(); sw->Start(); try { for (int i = 0 ; i < LoopCnt; i++ ) { BitmapData^ bmpData = bmp->LockBits( Rectangle(0,0,bmp->Width,bmp->Height), ImageLockMode::ReadWrite, fmt); bmp->UnlockBits(bmpData); } } catch (ArgumentException^) { Console::WriteLine("非対応っぽい"); return; } sw->Stop(); Console::WriteLine(sw->ElapsedMilliseconds / (double)LoopCnt); return; } //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ // 指定されたPixelFormatをSourceとし、すべてのPixelFormatでTestLockToUnlockTimeを呼ぶ。 void Test(PixelFormat fmt) { Bitmap^ bmp = gcnew Bitmap(640,480,fmt); Console::WriteLine("Source = " + fmt.ToString()); // PixelFormat列挙型でループを回す array<String^>^ a = Enum::GetNames( PixelFormat::typeid ); for each ( String^ s in a) { // PixelFormat列挙型のうち、Format...で始まる物のみテスト対象とする if (s->IndexOf("Format") >= 0) { TestLockToUnlockTime( bmp, (PixelFormat)Enum::Parse(PixelFormat::typeid, s)); } } } //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ int main(array<System::String ^> ^args) { // PixelFormat列挙型でループを回す array<String^>^ a = Enum::GetNames( PixelFormat::typeid ); for each ( String^ s in a) { // PixelFormat列挙型のうち、Format...で始まる物のみテスト対象とする if (s->IndexOf("Format") >= 0) { Test((PixelFormat)Enum::Parse(PixelFormat::typeid, s)); } } Console::ReadLine(); return 0; } //===<< END OF FILE >>=========================================================== ---- *System.Bitmapにおける、DrawImage(Bitmap, Point)のコスト  Format8bppIndexedで画像処理をして、表示用のBitmapに描画し、その上に更に何かを描画してから、PictureBox->Imageに代入するとか、よくあるシチュエーションだと思います。  リサイズしないで、Bitmapに対してべつのBitmapを描画するときの速度を計測してみました。 #ref(BitmapDrawImageTime.gif)  32bppArgbが、無指定で生成したBitmapのPixelFormatです。  この結果を見ると、32bppPArgbでBitmapを扱うのが、効率の点からよさそうです。 // [共通プロパティ]→[参照設定]で、System.Drawingを追加する。 using namespace System; using namespace System::Drawing; using namespace System::Drawing::Imaging; //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ // 指定されたBitmapに対し、指定されたPixelFormatでDrawImageを行い、時間を計測する。 void TestDrawImageTime(Bitmap^ bmp, PixelFormat fmt) { const int LoopCnt = 100; Console::Write(" {0,-20} = ", fmt.ToString()); Graphics ^ g = Graphics::FromImage(bmp); Bitmap^ bmp2 = gcnew Bitmap(bmp->Width, bmp->Height, fmt); Diagnostics::Stopwatch^ sw = gcnew Diagnostics::Stopwatch(); sw->Start(); try { for (int i = 0 ; i < LoopCnt; i++ ) { g->DrawImage(bmp2, Point(0,0)); } } catch (ArgumentException^) { Console::WriteLine("非対応っぽい"); return; } sw->Stop(); Console::WriteLine(sw->ElapsedMilliseconds / (double)LoopCnt); return; } //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ // 指定されたPixelFormatをSourceとして、すべてのPixelFormatでTestDrawImageTimeを呼ぶ。 void Test(PixelFormat fmt) { Bitmap^ bmp = gcnew Bitmap(640,480,fmt); Console::WriteLine("Source = " + fmt.ToString()); // PixelFormat列挙型でループを回す array<String^>^ a = Enum::GetNames( PixelFormat::typeid ); for each ( String^ s in a) { // PixelFormat列挙型のうち、Format...で始まる物のみテスト対象とする if (s->IndexOf("Format") >= 0) { TestDrawImageTime(bmp, (PixelFormat)Enum::Parse(PixelFormat::typeid, s)); } } } //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ int main(array<System::String ^> ^args) { Bitmap^ bmp = gcnew Bitmap(640,480); ; Console::WriteLine("PixelFormatを指定しないでBitmapを生成すると……" + bmp->PixelFormat.ToString()); // PixelFormat列挙型でループを回す array<String^>^ a = Enum::GetNames( PixelFormat::typeid ); for each ( String^ s in a) { // PixelFormat列挙型のうち、Format...で始まる物のみテスト対象とする if (s->IndexOf("Format") >= 0 && s->IndexOf("Indexed") < 0 && s->IndexOf("1555") < 0 && s->IndexOf("GrayScale") < 0) { Test((PixelFormat)Enum::Parse(PixelFormat::typeid, s)); } } Console::ReadLine(); return 0; } //===<< END OF FILE >>===========================================================
|&big(){System.Bitmapの操作にかかるコスト}| #contents() ---- *System.Bitmapにおける、Lock,Unlockのコスト  ポインタでBitmapにアクセスするときに欠かせないのがLockとUnlockメソッドです。  このLockに渡すPixelFormatって、いじりやすいってだけで、なんとなくFormat24bppRgbにしたりしてないでしょうか?そもそも、Bitmap自体の生成時に、PixelFormatを特に指定しなかったりしてないでしょうか?  簡単な実験の結果、BitmapとLockメソッドで指定するPixelFormatを揃えていないと、以外と大きなコストを払っていることが分かりました。 #ref(BitmapLockToUnlockTime.gif) // [共通プロパティ]→[参照設定]で、System.Drawingを追加する。 using namespace System; using namespace System::Drawing; using namespace System::Drawing::Imaging; //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ // 指定されたBitmapに対し、指定されたPixelFormatでLock,Unlockを行い、時間を計測する。 void TestLockToUnlockTime(Bitmap^ bmp, PixelFormat fmt) { const int LoopCnt = 1000; Console::Write(" {0,-20} = ", fmt.ToString()); Diagnostics::Stopwatch^ sw = gcnew Diagnostics::Stopwatch(); sw->Start(); try { for (int i = 0 ; i < LoopCnt; i++ ) { BitmapData^ bmpData = bmp->LockBits( Rectangle(0,0,bmp->Width,bmp->Height), ImageLockMode::ReadWrite, fmt); bmp->UnlockBits(bmpData); } } catch (ArgumentException^) { Console::WriteLine("非対応っぽい"); return; } sw->Stop(); Console::WriteLine(sw->ElapsedMilliseconds / (double)LoopCnt); return; } //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ // 指定されたPixelFormatをSourceとし、すべてのPixelFormatでTestLockToUnlockTimeを呼ぶ。 void Test(PixelFormat fmt) { Bitmap^ bmp = gcnew Bitmap(640,480,fmt); Console::WriteLine("Source = " + fmt.ToString()); // PixelFormat列挙型でループを回す array<String^>^ a = Enum::GetNames( PixelFormat::typeid ); for each ( String^ s in a) { // PixelFormat列挙型のうち、Format...で始まる物のみテスト対象とする if (s->IndexOf("Format") >= 0) { TestLockToUnlockTime( bmp, (PixelFormat)Enum::Parse(PixelFormat::typeid, s)); } } } //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ int main(array<System::String ^> ^args) { // PixelFormat列挙型でループを回す array<String^>^ a = Enum::GetNames( PixelFormat::typeid ); for each ( String^ s in a) { // PixelFormat列挙型のうち、Format...で始まる物のみテスト対象とする if (s->IndexOf("Format") >= 0) { Test((PixelFormat)Enum::Parse(PixelFormat::typeid, s)); } } Console::ReadLine(); return 0; } //===<< END OF FILE >>=========================================================== ---- *System.Bitmapにおける、DrawImage(Bitmap, Point)のコスト  Format8bppIndexedで画像処理をして、表示用のBitmapに描画し、その上に更に何かを描画してから、PictureBox->Imageに代入するとか、よくあるシチュエーションだと思います。  リサイズしないで、Bitmapに対してべつのBitmapを描画するときの速度を計測してみました。 #ref(BitmapDrawImageTime.gif)  32bppArgbが、無指定で生成したBitmapのPixelFormatです。  この結果を見ると、32bppPArgbでBitmapを扱うのが、効率の点からよさそうです。 // [共通プロパティ]→[参照設定]で、System.Drawingを追加する。 using namespace System; using namespace System::Drawing; using namespace System::Drawing::Imaging; //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ // 指定されたBitmapに対し、指定されたPixelFormatでDrawImageを行い、時間を計測する。 void TestDrawImageTime(Bitmap^ bmp, PixelFormat fmt) { const int LoopCnt = 100; Console::Write(" {0,-20} = ", fmt.ToString()); Graphics ^ g = Graphics::FromImage(bmp); Bitmap^ bmp2 = gcnew Bitmap(bmp->Width, bmp->Height, fmt); Diagnostics::Stopwatch^ sw = gcnew Diagnostics::Stopwatch(); sw->Start(); try { for (int i = 0 ; i < LoopCnt; i++ ) { g->DrawImage(bmp2, Point(0,0)); } } catch (ArgumentException^) { Console::WriteLine("非対応っぽい"); return; } sw->Stop(); Console::WriteLine(sw->ElapsedMilliseconds / (double)LoopCnt); return; } //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ // 指定されたPixelFormatをSourceとして、すべてのPixelFormatでTestDrawImageTimeを呼ぶ。 void Test(PixelFormat fmt) { Bitmap^ bmp = gcnew Bitmap(640,480,fmt); Console::WriteLine("Source = " + fmt.ToString()); // PixelFormat列挙型でループを回す array<String^>^ a = Enum::GetNames( PixelFormat::typeid ); for each ( String^ s in a) { // PixelFormat列挙型のうち、Format...で始まる物のみテスト対象とする if (s->IndexOf("Format") >= 0) { TestDrawImageTime(bmp, (PixelFormat)Enum::Parse(PixelFormat::typeid, s)); } } } //------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ int main(array<System::String ^> ^args) { Bitmap^ bmp = gcnew Bitmap(640,480); ; Console::WriteLine("PixelFormatを指定しないでBitmapを生成すると……" + bmp->PixelFormat.ToString()); // PixelFormat列挙型でループを回す array<String^>^ a = Enum::GetNames( PixelFormat::typeid ); for each ( String^ s in a) { // PixelFormat列挙型のうち、Format...で始まる物のみテスト対象とする if (s->IndexOf("Format") >= 0 && s->IndexOf("Indexed") < 0 && s->IndexOf("1555") < 0 && s->IndexOf("GrayScale") < 0) { Test((PixelFormat)Enum::Parse(PixelFormat::typeid, s)); } } Console::ReadLine(); return 0; } //===<< END OF FILE >>===========================================================

表示オプション

横に並べて表示:
変化行の前後のみ表示: