- 題名: 画像の分割・拡大
- 日時: 2009/02/15 4:54:57
- ID: 24003
- この記事の返信元:
- (なし)
- この記事への返信:
- [24008] Re[1]: 画像の分割・拡大2009/02/16 8:12:07
- [24014] Re[1]: 画像の分割・拡大2009/02/17 10:26:00
- ツリーを表示
■No24003に返信(昆布巻きさんの記事) > あるビットマップ(256×256)を4分割した後、それぞれを4倍に拡大(64×64→256×256)し、 > それをさらに4分割し…と5回繰り返し、1枚のビットマップから1024枚のビットマップを作る処理を作成しています。 はじめまして、まことと申します。 4分割して4倍して5回繰り返すと…すみません、最終的に元の画像の何倍に なればいいんでしょうか?(^^; 当方C#しか使えないので読みにくいかとは思いますが、以下の様なコーディング を行う事で、結果的に元画像を縦横2倍にして4等分にした画像を保存できます。 ※元画像の特定領域を拡大コピーして保存するイメージです。 速度的にご満足頂けるかは分かりかねますが、一応オフスクリーン(メモリ内)で 処理しています。 private void button1_Click(object sender, EventArgs e) { using (Image srcImg = Image.FromFile(@"b:\sample.bmp")) using (Bitmap dstImg = new Bitmap(srcImg.Width, srcImg.Height)) // ここも変更する必要有り? using (Graphics dstGrp = Graphics.FromImage(dstImg)) { int captWidth = srcImg.Width / 2; // この辺を最終的な拡大サイズに合わせて int captHeight = srcImg.Height / 2; // 変更する必要があります。 Rectangle dstRect = new Rectangle(0, 0, dstImg.Width, dstImg.Height); for (int y = 0; y < dstImg.Height; y += captHeight) { for (int x = 0; x < dstImg.Width; x += captWidth) { dstGrp.DrawImage(srcImg, dstRect, x, y, captWidth, captHeight, GraphicsUnit.Pixel); dstImg.Save(string.Format(@"b:\{0}{1}.bmp", x, y)); } } } }
■No24022に返信(昆布巻きさんの記事) ■No24018に返信(昆布巻きさんの記事) > この方法(DrawImageを使用)だと速度的に難があるので別の方法を模索中です。 拡大処理じゃなくて縮小処理だったんですね(^^; 掲示板に書き込む内容を用意 してる間に新情報がずらずらと出て来たので1から考えなおしてみました。 で、ちょっと汚いソースですがこんな感じで実現出来まして、当方の環境(CoreDuo 1.83GHz,MEM 2G) では約27秒前後で終了しました…DrawImage でやってもStretchBltでやってもです。 DrawImage は安定して27秒台をキープしていたのですが、StretchBltだと1分以上 掛る場合もありましたが、その辺はよく分かりません。 つまり、DrawImageが元凶とはならないのでは?と言う事です。 ■ DrawImage 版 private void button1_Click(object sender, EventArgs e) { using (Bitmap srcImg = new Bitmap(@"C:\sample\sample.bmp")) using (Bitmap dstImg = new Bitmap(256, 256)) using (Graphics dstGrp = Graphics.FromImage(dstImg)) { dstGrp.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; Rectangle dstRect = new Rectangle(0, 0, dstImg.Width, dstImg.Height); this.Text = string.Empty; DateTime st = DateTime.Now; for (int cnt = 2; cnt < 64; cnt+=cnt) { Size captSize = new Size(srcImg.Width / cnt, srcImg.Height / cnt); for (int y = 0; y < srcImg.Height; y += captSize.Height) { for (int x = 0; x < srcImg.Width; x += captSize.Width) { dstGrp.DrawImage(srcImg, dstRect, x, y, captSize.Width, captSize.Height, GraphicsUnit.Pixel); dstImg.Save(string.Format(@"c:\sample\{0}-({1},{2}).bmp", captSize.Width, x, y)); } } } DateTime et = DateTime.Now; TimeSpan ts = et - st; this.Text = ts.ToString(); } } ■ StretchBlt版 (各種宣言は省略) private void button2_Click(object sender, EventArgs e) { using (Bitmap srcImg = new Bitmap(@"C:\sample\sample.bmp")) using (Bitmap dstImg = new Bitmap(256, 256)) using (Graphics srcGrp = Graphics.FromImage(srcImg)) using (Graphics dstGrp = Graphics.FromImage(dstImg)) { Rectangle dstRect = new Rectangle(0, 0, dstImg.Width, dstImg.Height); this.Text = string.Empty; DateTime st = DateTime.Now; IntPtr srcHbmp = srcImg.GetHbitmap(); for (int cnt = 2; cnt < 64; cnt += cnt) { Size captSize = new Size(srcImg.Width / cnt, srcImg.Height / cnt); for (int y = 0; y < srcImg.Height; y += captSize.Height) { for (int x = 0; x < srcImg.Width; x += captSize.Width) { IntPtr srcHdc = srcGrp.GetHdc(); IntPtr dstHdc = dstGrp.GetHdc(); SelectObject(srcHdc, srcHbmp); try { StretchBlt(dstHdc, 0, 0, dstRect.Width, dstRect.Height, srcHdc, x, y, captSize.Width, captSize.Height, TernaryRasterOperations.SRCCOPY); } finally { DeleteObject(srcHbmp); srcGrp.ReleaseHdc(); dstGrp.ReleaseHdc(); } dstImg.Save(string.Format(@"c:\sample\{0}-({1},{2}).bmp", captSize.Width, x, y)); } } } DateTime et = DateTime.Now; TimeSpan ts = et - st; this.Text = ts.ToString(); } }
■No24026に返信(まことさんの記事) 追伸です。 > dstGrp.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; DrawImage でも上記の設定をしないと処理速度が重くなりました。(2分強) DrawImage が遅いと仰られてる原因は恐らくこれではありませんか? InterpolationMode プロパティのデフォルト値でも何かしらのスムージング処理 をしているようです。
■No24028に返信(昆布巻きさんの記事) > 当方の環境でもStretchBltの方がかなり遅くなってしまいました。。。 StretchBlt は拡大処理が入る関係上、BitBltよりも処理が重くなります。 さらにGetHdcやReleaseHdc、更にSelectObjectやDeleteObjectなども都度 実行していますので、その辺りのオーバーヘッドも気になる所です。 > InterpolationModeプロパティの変更も試してはみましたが、 > 多少は速くなるもののFillRectangleほどの高速化のもなりませんね。。。 ちなみにTextureBrush時のスムージング制御は、No.23870の魔界の仮面弁士さん の書込みを見るに対応していない様です。 つまりスムージングを制御する方が大事なのであれば、TextureBrushによる FillRectangleは使えないと言う事になってしまいます。 一応、先のコードを FillRectangle に改造してみたのですが、なんと37秒強 とDrawImage版(27秒台)よりも遅い結果が出ちゃいました(^_^; 描画速度で稼ぐ時間よりも、TextureBrushの生成で消費される時間の方が多い のかもしれません。 しかし腑に落ちないのはDrawImageの処理速度ですねぇ…、C#とVBでは処理に 違いが有るのでしょうか。(.NET Frameworkでそれは無いと思いたい) さらなる高速化を図るには…処理をスレッド化して512〜64サイズと32サイズ とで分けてみるとかは如何でしょうか。 しかし何となく手詰まりな感じがしてまいりました(~_~; private void button1_Click(object sender, EventArgs e) { using (Bitmap srcImg = new Bitmap(@"C:\sample\sample.bmp")) using (Bitmap dstImg = new Bitmap(256, 256)) using (Graphics dstGrp = Graphics.FromImage(dstImg)) { dstGrp.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; Rectangle dstRect = new Rectangle(0, 0, dstImg.Width, dstImg.Height); this.Text = string.Empty; DateTime st = DateTime.Now; for (int cnt = 2; cnt < 64; cnt += cnt) { Size captSize = new Size(srcImg.Width / cnt, srcImg.Height / cnt); for (int y = 0; y < srcImg.Height; y += captSize.Height) { for (int x = 0; x < srcImg.Width; x += captSize.Width) { TextureBrush tb = new TextureBrush(srcImg, new Rectangle(x, y, captSize.Width, captSize.Height)); tb.ScaleTransform(256 / captSize.Width, 256 / captSize.Height); dstGrp.FillRectangle(tb, 0, 0, 256, 256); dstImg.Save(string.Format(@"c:\sample\{0}-({1},{2}).bmp", captSize.Width, x, y)); } } } DateTime et = DateTime.Now; TimeSpan ts = et - st; this.Text = ts.ToString(); } }
分類:[.NET]
あるビットマップ(256×256)を4分割した後、それぞれを4倍に拡大(64×64→256×256)し、
それをさらに4分割し…と5回繰り返し、1枚のビットマップから1024枚のビットマップを作る処理を作成しています。
とりあえずGraphics.DrawImageを使って作成してみたのですが、この処理をどうにかもっと高速化したいのです。
そこで以下の方法を試してみました。
1.ビットマップをMemoryStreamに読み込み、そこから切り出したデータを元に拡大したデータをバイト配列に入れてビットマップを作成。
→バイナリデータを1バイトずつ読み込みコピーするので、ほとんど処理時間は短縮できず。
2.TextureBrushに元のビットマップを設定し、Graphics.FillRectangleで拡大描画。
→処理自体は非常に高速になったが、切り出した画像のフチ(右と下だけ)がスムージングされた画像になってしまう。
3.WndowsAPIのStretchBltを使用して切り出し・拡大。
対象となるビットマップをいったんピクチャーボックスなどに表示(実際の画面上に描画)してやらないと使用できない。
今回の処理では画面は表示せずすべてバックグランドで処理したい。
これで手詰まりになってしまいました。
どなたか他の方法をご存知の方おられませんでしょうか?
あとTextureBrushのスムージングについて何かご存じ(そういう仕様である、回避方法)の方おられましたら教えていただけませんでしょうか。
よろしくお願いします。