関連記事
- なんと!今週の土曜日も仕事してますた.来週の土曜日も仕事臭い.TCPソケット通信をゴリゴリ書いてる 【2025年08月30日(土)】
- 【ChatGPT o4】祝日なのに仕事ーバテすぎー今夜こそ絶命だーモルモルモル 【2025年03月20日(木)】
- 【#CSharp】制御系が動き出したべ 【2025年02月20日(木)】
- 【#CSharp】ひっさしぶりにガッツリなC#案件をやっているぞー 【2025年02月19日(水)】
- 今週もひたすらモノ書き #JAVA 祭りがまだまだ続く そろそろC#を書かせろー 【2024年12月04日(水)】
画像のポインタ、普通は、バイト配列で処理するもんですが
ちょいと裏技で、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;
}
}
}
}
}


データキャッシュが効いてるんじゃないですか?
あ、それとメモリもコンパイラがデータをワードアラインに揃えるように処理しちゃって、
3バイトも4バイトも、実メモリ消費は4バイトになってたりするかもしれません^^;;;;
>>康ちゃん@まったり~ さま
読み込み即書き込みなんで
データキャッシュよりは,アライメントでドカンと引き上げてるほうが,可能性ありそうですねぇ
最近のCPU工学は,とんでもない実装になっているみたいじゃし
まぁ,オレラが小細工するよりは
素直に見やすいコードを書いたほうが良さそうですのぉ(笑