で、以下のコードで実行してみると、CPU稼動率は100%で張り付いたものの、5回の平均を計ると18.297秒。なんと10%くらい性能が悪化していました。BitmapのGetPixおよびSetPixはマルチスレッドに対応していないようで、結果的に同期のコストがかかることが原因ということがわかりました。
で、残念なコードは以下のとおり。
private void btnGlay2_Click(object sender, EventArgs e)
{
textBox1.Text = "グレースケール化(2)";
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
Bitmap bmp = new Bitmap(ctlPicture.Image);
int h = bmp.Height;
int w = bmp.Width;
Parallel.For(0, w, delegate(int i)
{
for (int j = 0; j < h; j++)
{
Color color;
lock (bmp)
{
color = bmp.GetPixel(i, j);
// 計算式にて、値を算出してセットする
//int col = (int)(color.R * 0.299 + color.G * 0.587 + color.B * 0.114);
//int col = (int)((color.R + color.G + color.B) / 3);
int col = (int)Math.Round((color.R + color.G + color.B) / 3.0d);
Color pix = Color.FromArgb(col, col, col);
bmp.SetPixel(i, j, pix);
}
}
});
ctlPicture.Image = bmp;
sw.Stop();
textBox1.Text = String.Format(textBox1.Text + " 完了{0:#,##0}ms", sw.ElapsedMilliseconds);
}
{
textBox1.Text = "グレースケール化(2)";
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
Bitmap bmp = new Bitmap(ctlPicture.Image);
int h = bmp.Height;
int w = bmp.Width;
Parallel.For(0, w, delegate(int i)
{
for (int j = 0; j < h; j++)
{
Color color;
lock (bmp)
{
color = bmp.GetPixel(i, j);
// 計算式にて、値を算出してセットする
//int col = (int)(color.R * 0.299 + color.G * 0.587 + color.B * 0.114);
//int col = (int)((color.R + color.G + color.B) / 3);
int col = (int)Math.Round((color.R + color.G + color.B) / 3.0d);
Color pix = Color.FromArgb(col, col, col);
bmp.SetPixel(i, j, pix);
}
}
});
ctlPicture.Image = bmp;
sw.Stop();
textBox1.Text = String.Format(textBox1.Text + " 完了{0:#,##0}ms", sw.ElapsedMilliseconds);
}