IntPtrで引っ張り出した画像へのポインタ、Int*で処理したほうが速い?

画像のポインタ、普通は、バイト配列で処理するもんですが
ちょいと裏技で、int*にキャストしてやって、intの配列で処理してやったほうが
メモリ~CPU間の通信量が減って、速度が上がる

と、C言語の頃は、王道だったんですが…

C#の世界でも、通用するのかと、ちょいとサンプル書いて、実行してみました

条件は以下のとおり

CPU : AMD Athlon64x2 3800+(2.0GHz)
Memory : 1GB
OS : Windows XP Pro
言語: Visual Studio 2005(C#2.0) + .Net FrameWork2.0

画像データ1000回の
グレースケール処理を実行
リリースコンパイル
640 * 480
24ビットピクセル
byte配列処理
10,437ミリ秒
640 * 480
32ビットピクセル
int配列処理
10,093ミリ秒


あいたっ!
さほど、差が無い(滝汗

JITが、スットコドッコイなコード、吐き出しているのかなぁ。。。

3バイト画像を無理して4バイトに変換してInt配列処理させるよりは
byte配列でそのまんま、処理させたほうが、かえっていいかも

4バイトにしちゃうと、容量25%増しだし…

でも、C言語じゃ、当たり前だった、小技、使っても意味無いとは、ねぇ。。。


頭きたんで、このグレースケール処理、4スレッドでぶん回してみる!
次回をお楽しみにぃ~~


public partial class Form1 : Form
{
private Bitmap m_ImageBackup; // 一時データ
private Bitmap m_bmapIn; // 入力データ
private Bitmap m_bmapOut; // 出力データ

private int m_Width; // Image サイズ
private int m_Height; // Image サイズ

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{

pictureBox1.Image = null;
}

private void button1_Click(object sender, EventArgs e)
{
string FileName;

if (openFileDialog1.ShowDialog() != DialogResult.OK)
{
return;
}
FileName = openFileDialog1.FileName;

m_ImageBackup = new Bitmap(FileName);
m_Width = m_ImageBackup.Width;
m_Height = m_ImageBackup.Height;
m_bmapOut = new Bitmap(m_Width, m_Height);

if (radioButton1.Checked == true)
{
m_bmapIn = m_ImageBackup;
}
else
{
Rectangle dstRect = new Rectangle(0, 0, m_Width, m_Height);
m_bmapIn = m_ImageBackup.Clone(dstRect, PixelFormat.Format32bppArgb);
}

if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}

pictureBox1.Image = m_bmapIn;

}

private void button2_Click(object sender, EventArgs e)
{
DateTime dt = DateTime.Now;

int min = dt.Minute;
int sec = dt.Second;
int mili = dt.Millisecond;


lblStart.Text = “開始時間:” + min.ToString() + “_” + sec.ToString() + “_” + mili.ToString();

Bitmap bd = pictureBox1.Image as Bitmap;
Bitmap bs;

BitmapData bDataInS;
BitmapData bDataInD;
IntPtr Scan0_InS; // ピクセルデータの開始アドレス
IntPtr Scan0_InD; // ピクセルデータの開始アドレス
bs = new Bitmap(m_bmapIn);

if (radioButton1.Checked == true)
{
bDataInS = bs.LockBits(new Rectangle(0, 0, bs.Width, bs.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
Scan0_InS = bDataInS.Scan0; // ピクセルデータの開始アドレス

bDataInD = bd.LockBits(new Rectangle(0, 0, bd.Width, bd.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
Scan0_InD = bDataInD.Scan0; // ピクセルデータの開始アドレス

for(int i = 0; i < 1000; i++)
{
GrayScaleB(Scan0_InS, Scan0_InD, bd.Width, bd.Height);
}

bd.UnlockBits(bDataInD);
bs.UnlockBits(bDataInS);

}
else
{
bDataInS = bs.LockBits(new Rectangle(0, 0, bd.Width, bd.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
Scan0_InS = bDataInS.Scan0; // ピクセルデータの開始アドレス

bDataInD = bd.LockBits(new Rectangle(0, 0, bd.Width, bd.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
Scan0_InD = bDataInD.Scan0; // ピクセルデータの開始アドレス

for(int i = 0; i < 1000; i++)
{
GrayScaleI(Scan0_InS, Scan0_InD, bd.Width, bd.Height);
}
bd.UnlockBits(bDataInD);
bs.UnlockBits(bDataInS);
}



DateTime dt2 = DateTime.Now;
min = dt2.Minute;
sec = dt2.Second;
mili = dt2.Millisecond;

lblEnd.Text = "終了時間:" + min.ToString() + "_" + sec.ToString() + "_" + mili.ToString();;

TimeSpan tm = dt2.Subtract(dt);

lblJob.Text = "経過時間:" + tm.TotalSeconds.ToString();

//pictureBox1.Refresh();
Refresh();
}

public void GrayScaleI(IntPtr ptS, IntPtr ptD, int tmpWidth, int tmpHeight)
{
int x, y;
int index;
byte PixelData;
byte red, green, blue;
uint dat;

unsafe
{
uint* ps = (uint*)ptS;
uint* pd = (uint*)ptD;

for (y = 0; y < tmpHeight; y++)
{
for (x = 0; x < tmpWidth; x++)
{
index = (y * tmpWidth) + x;

dat = ps[index];

red = (byte) ((dat & 0x00ff0000) >> 16);
green = (byte) ((dat & 0x0000ff00) >> 8);
blue = (byte) ((dat & 0x000000ff));

PixelData = (byte)(0.299f * ((float)red) + 0.587f * ((float)green) + 0.114f * ((float)blue));
pd[index] = (uint)(PixelData * 0x010101) | 0xff000000;

}
}
}
}

public void GrayScaleB(IntPtr ptS, IntPtr ptD, int tmpWidth, int tmpHeight)
{
int x, y;
int index;
byte PixelData;
byte red, green, blue;

int scanl = tmpWidth * 3;

unsafe
{
byte* ps = (byte*)ptS;
byte* pd = (byte*)ptD;

for (y = 0; y < tmpHeight; y++)
{
for (x = 0; x < scanl; x += 3)
{
index = (y * scanl) + x;

blue = ps[index ];
green = ps[index + 1];
red = ps[index + 2];

PixelData = (byte)(0.299f * ((float)red) + 0.587f * ((float)green) + 0.114f * ((float)blue));

pd[index] = PixelData;
pd[index + 1] = PixelData;
pd[index + 2] = PixelData;

}
}
}
}
}

[/csharp]