- PR -

LockBitsの処理が重い(C#)

投稿者投稿内容
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2007-10-18 19:03
まず何が遅くしている主犯なのかを突き止めるのが先決じゃない?
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2007-10-18 19:06
引用:

れいさんの書き込み (2007-10-18 18:56) より:
引用:

Jittaさんの書き込み (2007-10-18 18:46) より:
それでも読んでくれる人はいるでしょうが、回答を得る機会を自ら減らしているのではないでしょうか。



読んじゃいましたが、
やっぱめんどくさかったです。
放棄しようかと思いましたが、
最初に答えてしまったので。

引用:

コードの1つ1つ、何をしたいのか、説明してください。
読み手に、解読の負担を強いないでください。



高速化したいってことなんで、
コードが重要なんですよね。

更に言うと、
コードがきちんとインデントされてるといいんですがね。
今回はインデントされてれば問題点が一目瞭然かと。


BBコードをご存知ないのでしょう
メモ帳にコピペしたらインデントされていたりしませんか?
私は、今携帯電話なので試しません(だから余計にコードは見難い)


あと、モノクロって、明度持ってます?0と1しかないんじゃないかなぁ?グレースケールの間違いですかねぇ?


それで、明度が同じならコピーってのも、なんだか?全部コピーしているのと変わらないような?
あるいは、0だけコピーしなければ、256回のループが1回になるような?
意図が読めないので、どうだかわかりませんが
ぽぴ王子
ぬし
会議室デビュー日: 2006/03/24
投稿数: 475
お住まい・勤務地: お住まい:城・勤務地:城
投稿日時: 2007-10-18 19:22
Jitta さんも書かれていますが、BBコードというものがあります。
投稿する際に「この投稿で BBコード を使わない」というチェックボックスが
ありますが、その「BBコード」という部分のリンクをクリックすると説明が
見れると思います。
その中で「codeタグ」というものを使うと、インデントされたソースが入力
できるはずです。またコードを入力する機会があればそれを使ってみてください。

引用:

れいさんの書き込み (2007-10-18 18:56) より:

更に言うと、
コードがきちんとインデントされてるといいんですがね。
今回はインデントされてれば問題点が一目瞭然かと。


例えば、コードが書かれている記事を「引用」で編集画面にリンクすると
テキストボックスの中はインデントされた状態のコードが入っているはず
(投稿者がインデント込みで入力していればですが)なので、そこから
コピーしてたぐっていく…というのはどうでしょう?(僕はたまにやります)。

ただ、本質的には Jitta さんも書かれてますが、読む側のことを考えて
投稿してもらうのが一番楽ではあります。
もちろん強制ではないですが、こういうのも人と人との<del>ヒットビット</del>
コミュニケーションなので「こんなんじゃオレ答えるのや〜んぴ!」という
私のような方もいらっしゃるのかなと。
なので、自分でわかる範囲、自分にしかわからない範囲はできるだけ細かく
説明するようにすると回答もつきやすいかもしれません。

なんだかれいさんへの返答と満月さんへの返答がごっちゃになってしまいました orz

ところで、Pixcel って Pixel のことでしょうか。
_________________
ぽぴ王子@わんくま同盟
ぽぴ王子の人生プログラミング中 / ぽぴンち。
とっちゃん
大ベテラン
会議室デビュー日: 2005/07/19
投稿数: 203
投稿日時: 2007-10-18 19:50
ソース上にもわからんことは多数残ってるんですが...

誰も指摘していないので...とりあえず最低限の修正で若干でも効果が見込める部分だけ。

DoEvents();
Invalidate();

ではなく、
Refresh();
に変えてみてください。

それと、Refresh()するコントロールは、画像を表示しているコントロールそのものを対象にしてみてください。

これだけでも大分状況が変わるはずです。

それでも満足できないのなら、次は再描画のタイミングをもうちょっと減らす
(たとえば、256回もやるのではなくて、16回にするとかw)
ということを検討してはいかがでしょう?

_________________
// とっちゃん(高萩 俊行)@わんくま同盟
// とっちゃん’Blog
// MS-MVP for Developer Tools - Visual C++
// WindowsInstallerの話題はhttp://www.freeml.com/msiまで
満月
会議室デビュー日: 2007/10/18
投稿数: 12
投稿日時: 2007-10-18 23:30
ご指摘のとおり、まったく読みづらいものに対して答えて下って本当にありがとうございます。

引用:

れいさんの書き込み (2007-10-18 18:50) より:

全ての言語で共通して最も重要なことは
とにかくループの深さを減らすことです。
その後、一番深いループから順に、
深いループの処理をより浅いループに移せないか検討します。



なるほど、勉強になります。できないか考えてみます。


引用:

Jittaさんの書き込み (2007-10-18 19:06) より:
あと、モノクロって、明度持ってます?0と1しかないんじゃないかなぁ?グレースケールの間違いですかねぇ?



すみません、モノクロではなくグレースケールの間違いですね。
256色のグレースケールです。

BBコードは、すみません知らなかったです。使い方は理解できましたので次回から気をつけます。
Jittaさん、ぽぴ王子(本物)さん、ありがとうございました。

引用:

とっちゃんさんの書き込み (2007-10-18 19:50) より:
DoEvents();
Invalidate();

ではなく、
Refresh();
に変えてみてください。



お答えいただいてありがとうございます!
変えてみた結果、遅くなってしまったので、なにか他にないか探してみます。


コード、張りなおしておきます。

このプログラムでやりたいことは、
カラー・グレースケール(256色)・透明の3枚の画像を使用して。
グレースケール画像の色を見て、黒(0)→白(255)の順にカラー画像を透明画像に移(表示)していくというものです。(256枚のパラパラアニメのような感じでしょうか)
例えば、グレースケール上では明度が5の所をカラー画像の同じところにある色を透明画像に描画し、次は明度6の所…といった風に

コード:
private void Set() 

{
BitmapData bmpDate, bmpDate2, bmpDate3;
bmpDate2 = base1.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
bmpDate = mat.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
bmpDate3 = effe.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
bytes = w * h * 4;

IntPtr ptr = bmpDate.Scan0;//カラー画像
byte[] rgbVlues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbVlues, 0, bytes);

IntPtr ptr2 = bmpDate2.Scan0;//透明画像
byte[] rgbVlues2 = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr2, rgbVlues2, 0, bytes);

IntPtr ptr3 = bmpDate3.Scan0;//グレースケール画像
byte[] rgbVlues3 = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr3, rgbVlues3, 0, bytes); //byte型の変数にビットマップの情報を代入
effe.UnlockBits(bmpDate3);
mat.UnlockBits(bmpDate);

//ココから以降が重いようです。

for(int z=0; z <= 254; z++)  //明度0〜255
{
bool byouga = false;
bmpDate2 = base1.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); //画像をロックする

for(int a = 0; a < bytes; a=a+4)  
{
if (rgbVlues3[a] == z)  //同明度のところを描いていく
{

rgbVlues2[a] = rgbVlues[a]; //B
rgbVlues2[a+1] = rgbVlues[a+1]; //G
rgbVlues2[a+2] = rgbVlues[a+2]; //R
rgbVlues2[a+3] = rgbVlues[a+3]; //アルファ値
byouga = true;
}
}

System.Runtime.InteropServices.Marshal.Copy(rgbVlues2, 0, ptr2, bytes);
base1.UnlockBits(bmpDate2);

if (byouga == true)
{
Application.DoEvents();
Invalidate();
}
       System.Threading.Thread.Sleep(10); //ウェイト
}
}




[ メッセージ編集済み 編集者: 満月 編集日時 2007-10-19 00:13 ]
れい
ぬし
会議室デビュー日: 2005/11/01
投稿数: 346
投稿日時: 2007-10-18 23:54
引用:

満月さんの書き込み (2007-10-18 23:30) より:
このプログラムでやりたいことは、
カラー・グレースケール(255色)・透明の3枚の画像を使用して。
グレースケール画像の色を見て、黒(0)→白(255)の順にカラー画像を透明画像に移(表示)していくというものです。(255枚のパラパラアニメのような感じでしょうか)



なんと!ぱらぱらアニメなのか!
無駄だらけだと思ったらそういうことでしたか。
それはJittaさんのいうとおり、
言葉で説明がないと全然わかりませんでした。

そうすると、最初に思いつくのは、
全部作っておくことですね。
表示の前に256個分全部作る。

色数が少なくていいならインデックスなBMPを使うというのもあります。
これが一番速いかな。

あと、無駄なsleepは要らない。
sleepしてる間に次のコマを作るべき。
ticktimeとかで時間を取得して、
時間が余っていたらそのとき初めてsleepすべき。

メモリを使いたくないとかで、
コマをリアルタイムで作りつつ表示したいなら、
ループの一番内側を何とかします。
つまりここ。
コード:

if (rgbVlues3[a] == z)  //同明度のところを描いていく
{

rgbVlues2[a] = rgbVlues[a]; //B
rgbVlues2[a+1] = rgbVlues[a+1]; //G
rgbVlues2[a+2] = rgbVlues[a+2]; //R
rgbVlues2[a+3] = rgbVlues[a+3]; //アルファ値
byouga = true;
}



とりあえず、byteを4つばらばらにコピーするのは無駄ですね。
byte配列でなく、integer配列にすれば、一回で全部できますよ。

あと、256段階全部表示するのをやめて間引くとか。
10msecで1回、256段階の一つを表示しても
見えないと思うので、半分くらいにしても問題ないのではないですか?

あとマルチスレッドなCPUなら、
別スレッドで別のBitmapオブジェクトに作らせておくと
早くできる場合もあります。
排他処理とかいろいろやらなきゃいけないのでめんどくさいし
効果が出ない場合もあるのでお勧めしませんが。

まぁそんなところを適当に組み合わせて
対応したらどうでしょう?
いまのPCなら、そこそこ実用的なぱらぱらアニメができるんじゃないでしょうか。

[ メッセージ編集済み 編集者: れい 編集日時 2007-10-19 00:36 ]
満月
会議室デビュー日: 2007/10/18
投稿数: 12
投稿日時: 2007-10-19 00:59
引用:

れいさんの書き込み (2007-10-18 23:54) より:

とりあえず、byteを4つばらばらにコピーするのは無駄ですね。
byte配列でなく、integer配列にすれば、一回で全部できますよ。



何度もすみません、ありがとうございます。
integer配列にすれば、一回で全部というのは、
integerってintのことですよね? int配列で一回で出来るんですか?
ジャグ配列のことでしょうか。
勉強不足で申し訳ありません、もう少し詳しく教えていただいていいでしょうか。
れい
ぬし
会議室デビュー日: 2005/11/01
投稿数: 346
投稿日時: 2007-10-19 02:02
引用:

満月さんの書き込み (2007-10-19 00:59) より:
integerってintのことですよね?



うげ。混乱を招く書き方はよくないですね。
Int32、C#ならint、VBならIntegerのことです。

引用:

もう少し詳しく教えていただいていいでしょうか。



PixelFormat.Format32bppArgbなので、
1ピクセル -> 32 bit -> 4 byte -> 1 Int32
ですね。

コード:

IntPtr ptr = bmpDate.Scan0;//カラー画像
byte[] rgbVlues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbVlues, 0, bytes);


ptrからbytesだけbyte配列rgbVluesにコピーしてるわけですが、
ここで、bytes = w * h * 4で、4バイトを単位で確保してますよね。
1ピクセル=32bitだから当然ですが。

つぎにrgbVluesを使うところでは、
コード:

rgbVlues2[a] = rgbVlues[a]; //B
rgbVlues2[a+1] = rgbVlues[a+1]; //G
rgbVlues2[a+2] = rgbVlues[a+2]; //R
rgbVlues2[a+3] = rgbVlues[a+3]; //アルファ値


いつも必ず連続して4バイト、コピーしてますよね。
これも1ピクセル=32bitなので当然ですが。

なら、確保もコピーも32bit=1 UInt32単位でやったらどうですか?
ということです。
コード:

IntPtr ptr = bmpDate.Scan0;//カラー画像
UInt32[] rgbVlues = new UInt32[w*h];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbVlues, 0, rgbVlues.Length);



コード:

for(int a = 0; a < w*h; a++)
if (rgbVlues3[a*4] == z)
rgbVlues2[a] = rgbVlues[a]; //BGRA




[ メッセージ編集済み 編集者: れい 編集日時 2007-10-19 02:04 ]

スキルアップ/キャリアアップ(JOB@IT)