「トップページ/CPPCLI/IMAGE/BITMAP-COST」の編集履歴(バックアップ)一覧はこちら
追加された行は緑色になります。
削除された行は赤色になります。
|&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 >>===========================================================