• 締切済み

重いグラフィックス処理

Windows VisualC++/MFC でのご質問です。 大きなグラフィックスデータをSDIアプリケーションで表示しているのですが、データが重く描画に10数秒時間を要してしまいます。1mil1画素といった具合に割り当てているのですが、あまりにも重過ぎます。描画を早くしたいのですが、何か良い手はありますでしょうか? 現在はDCに直接描画しています。メモリDCも試しましたが、サイズが大きすぎてbitmapが作れまずあきらめました。 以上、ご指導よろしくお願いします。

みんなの回答

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.6

>Windowのビュー/マップモードに頼らないで..メモリDC+自分でスケーリングというのが近道でしょうか? >..でもマッピングモードに頼って広大なDCを使っているのが間違いなのかもしれません。ただ、全景を表示したときつぶれなく表示され、拡大はかなり高速にそして滑らかに表示されたので...その点は良いと考えていました。 はい、マッピングモードには問題はないです。 >MoveTo,LineToで書いている以上、論理サイズの大きさは、速度にあまり影響ありません。BitBltとかStretchBltとかしていると別ですが。 と、書いたとおりです。 とにかく、無断な線を引かないのが一番効果があります。 >データ解析 : 確かに遅く。試行覚悟していますが、ダメですね。 >中間ファイルに落として...というのも試しましたが、更にデータ数が増えてしまうという情け無い結果に終わったり...してしまいました。 でも、現状でも、ファイルを読み込んでMoveTo,LineToにしているわけですよね? でしたら、そのMoveTo、LineToに与えているパラメータを予め計算して配列かなんかに保存しておくだけです。メモリは使うでしょうが、スピードは速くなるはずです。 >他にも手法はあるとのことですが...私にはなかなか手の届く範囲では無いような気がします。 無駄な線を引かないだけなら難しいことではありません。 例えば、一本の線の始点と終点がウィンドウの上端よりも上にあるのなら、その線は画面に表示されません。なので、その線を引く必要はありません。同様の処理を、ウィンドウの左と右と下についても行えば、大きく拡大したときなどは引く線の数を大きく減らすことができます。 「手の届く範囲では無い」とおっしゃいますが、一つ一つの技術はそう難しいものではないですよ。

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.5

#1です。 なるほど、だいたいわかりました。 MoveTo,LineToで書いている以上、論理サイズの大きさは、速度にあまり影響ありません。BitBltとかStretchBltとかしていると別ですが。 MoveTo,LineToで線を何本書いているのでしょうか?その数が非常に多いのであれば、速度が遅いのは仕方がないですね。 ただ、工夫はできます。 ウィンドウと同じ大きさのビットマップを用意して、一度そのビットマップに描いてからBitBltします。これなら、一度目は同じ時間がかかりますが、2回目以降はBitBltの時間だけで済みます。 また、一部を拡大して表示する場合は、すべての線を引く必要はないですよね?画面に表示される線だけを引くようにすれば、これも早くなります。 同様にスクロールの際も、必要がある部分のみ描画します。 当然、 >データファイルの読み込み解析に時間が掛かっていることが判明しました こんなロスは論外です。解析なんぞはファイル読み込んだその一回きりにとどめましょう。 あと、遅くてもあまりストレスに感じさせない方法としては、WM_PAINTで一気に描画するのではなく、アイドルループや別スレッドなどで書く方法があります。これだと、スクロールの際に、画面を全部書き終えるまえに、さらにスクロールを続けたりとできます。拡大縮小なんかでも同様。 とにかく、いろいろと工夫の余地はありますので、頑張りましょう。

kambeys
質問者

補足

ありがとうございます。 確かに数えきれないくらいのMoveTo/LineToを呼び出しています。 Windowのビュー/マップモードに頼らないで..メモリDC+自分でスケーリングというのが近道でしょうか? ..でもマッピングモードに頼って広大なDCを使っているのが間違いなのかもしれません。ただ、全景を表示したときつぶれなく表示され、拡大はかなり高速にそして滑らかに表示されたので...その点は良いと考えていました。 ちなみに印刷DCとなると解像度の関係でおなじような状況となります。 データ解析 : 確かに遅く。試行覚悟していますが、ダメですね。 中間ファイルに落として...というのも試しましたが、更にデータ数が増えてしまうという情け無い結果に終わったり...してしまいました。 他にも手法はあるとのことですが...私にはなかなか手の届く範囲では無いような気がします。 読みながら描画して無駄をなくすとか???を考えたりもしましたが... もう少し悪戦苦闘してみます。 ありがとうございました。 他に何かありましたらご支援お願いいたします。

  • jjk65536
  • ベストアンサー率59% (66/111)
回答No.4

過去に仕事で大きい画像の表示に関するプログラムを書いたことがあります。 ドット単位の画像アクセスをしながら数十ミリ秒くらいで描画できて いました。 (当時は質問者様と同じくWindows VisualC++/MFC環境でした) そのときは参考URLのページをみながらDIBを作って、ドットアクセスは 自分で確保したメモリにアクセスしつつ、矩形転送などは StreatchBltなどを使ってハードウェアアクセラレーションきかせて 描画、みたいにいいトコどりで作ったと記憶してます。 1mil1画素、という単位は私も知りませんが、高速な描画は参考URLの 方のサンプルコードで実現できている気がします。

参考URL:
http://lcl.web5.jp/prog/dibfirst.html
kambeys
質問者

補足

ありがとうございます。 その昔何かの機会でこのDIBの方法は使ったような気もします。 いつもその場しのぎで対応しているので... でもこのDIBというのを使っても今回の画像を表現できないというかサイズに制限があったような気がします。StrechDIBかSetDIBなるAPIを試した気がします。

  • penta1331
  • ベストアンサー率64% (16/25)
回答No.3

画像全体をタイル状に分割して、画面表示にはタイルを組み合わせて表示する、と考えてはどうですか? 表示領域サイズのメモリDCを複数個用意して、表示している領域付近の表示用データをメモリDCに先読みして作成する。 画面には複数のメモリDCを組み合わせて表示する。 裏読みなどテクニックが必要になってきますが、パフォーマンスは上がると思います。 元のデータが画像ではないようですから、そのフォーマットによっては実現できないかもしれません。

kambeys
質問者

補足

ありがとうございます。 メモリDCを使いたいのは山々なんです。 というのもレイヤが使えるので、表示する対象物を要素毎にレイヤ分けして重ねて表示したりしたいのです。 なるほど並べてという手法ですが... 部分ズーミングなどする際に...その時はどうすれば良いか? 思い浮かびません。メモリDCって自分のディスプレイサイズ程度しか確保できないようで、困ってます。

  • php504
  • ベストアンサー率42% (926/2160)
回答No.2

なじみのない単位ですが1mil=1/1,000in =0.0254mm のことかな ソース見ないとなぜ重いのかはわかりません ボトルネックになってる処理を探して最適化してください

kambeys
質問者

補足

ありがとうございます。 グラフィックスが重いのもさることながら、データファイルの読み込み解析に時間が掛かっていることが判明しました。グラフィックですが、領域が大きすぎるためメモリDCをあきらめたこともあり、直接DCに描いています。このこともあり、要素に応じて何度が上書きしています。 たとえば、パターンを描いたあと、穴を上書きするとか... とりあえず、ファイル読み込み解析の無駄を無くして時間を短縮する意向です。ただ、描画の方も... 高速?にスケーリング(拡大縮小)をしたくて、WINDOW/VIEWの座標系を変更して瞬時にできるマップモードを使っているのがダメ?なのでしょうか?(確かMM_ISO....だったような?) それからゴメンナサイ1mil = 1/10000inchと勘違いしていました。 ゆえに5000000* 5000000のサイズが対象です。 以上、よろしくお願いいたします。

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.1

>大きなグラフィックスデータ 具体的にどんな大きさなのでしょうか?ピクセル数および色数は? >1mil1画素 意味がわかりません。「1ミリ1画素」・・だとしても不明です。 >現在はDCに直接描画 使用しているAPI、関数等は何でしょうか? 以上、補足お願いします。

kambeys
質問者

補足

すみません。 内容不足で.. 不具合的に 1mil = 1/1000inchです。 ここに意味はなく、データの単位系がmilです。 データ上1000という座標には1000画素を割り当てるようにしています。 そして全体の大きさは500000mil * 500000milを想定しています。 MFCを使っていて.. MoveTo,LineToです。(Poly...も使ってみたりしましたが大差ありませんでした。) 具体的には、プリント板のパターンを描画しています。

関連するQ&A

  • C#のGraphicsクラスについて(GDI+)

    以下のようにgraphicsクラスをつかった画像の描画をおこないました。 Graphics gr = Graphics.FromImage(mapObj); というふうにからのリソースからGraphicsオブジェクトをつくる方法です。 using System; using System.IO; using System.Windows.Forms; using System.Drawing; using System.Web; using System.Net; using System.Text; using System.Threading; using System.ComponentModel; public class MainClass{ public static void Main(string [] args){ NewForm formObj = new NewForm(); formObj.RenderMethod(); Application .Run(formObj); } } public class NewForm : Form{ public NewForm(){ this.Width = 500; this.Height = 500; } public void RenderMethod(){ Bitmap mapObj = new Bitmap(500,500); Graphics gr = Graphics.FromImage(mapObj); Image imageObj = Image.FromFile("C:\\test.jpg"); gr .DrawImage(imageObj, 0,0,150,150); this.BackgroundImage = mapObj; } } このほかに、フォームコントロールの thisl.CreateGraphics()という メソッドを使っても画像を描画できるとききました。 あるサンプルをみると public class NewForm : Form{ public NewForm(){ this.Width = 500; this.Height = 500; } public void RenderMethod(){ Graphics gr = this.CreateGraphics(); Image imageObj = Image.FromFile("C:\\test.jpg"); gr .DrawImage(imageObj, 0,0,150,150); } } とこのようにthis.CreateGraphics()をつかっていましたが 実際にはこれが描画されないのです。 Graphics gr = Graphics.FromImage(mapObj); というGraphicsクラスの静的メソッドを使う方法ではなく コントロールのCreateGraphicsメソッドをつかって描画するにはどうしたらよいのですか? 識者のかた、ご教授ください。

  • GDI+のDrawStringを使って文字を滑らかに描画したいのですが。。。

    GDI+のDrawStringを使って文字を滑らかに描画したいのですが。。。 環境は、VC++のWin32プロジェクトです。 WindowのデバイスコンテキストからGraphicsオブジェクトを生成し、DrawStringとすると滑らかに描画されます。 しかし、BitmapオブジェクトからGraphicsオブジェクトを生成し、DrawStringを行うとビットマップフォントのようです。 Graphics g(hdc); g.DrawString(......); -> この場合はなめらか(画像の下の方) しかし、 Bitmap bmp(w, h, PixelFormat32bppARGB); Graphics g (&bmp); g.SetSmootingMode(SmoothingModeHighQuality); g.DrawString(...); -> ジャギが目立つ。(画像の上の方) ビットマップ(メモリ)にスムーズなテキストを描画することはできないのでしょうか? ちなみにフォントはメイリオです。

  • autocad2012 グラフィックスボード

    autocad2012 グラフィックスボードの設定方法に苦悶しております。 グラフィックスボードは、ATI FirePro V3700 (FireGL)です。 最新のドライバーを更新しましたが、 autocadの3DCONFIG コマンドを実行しますと、 3D デバイス ------- 名前 : ATI FirePro V3700 (FireGL) 製造元 : ATI チップ セット : FirePro V3700 (FireGL) メモリ : 1015 MB ドライバ : 8.17.0010.1077 お使いのコンピュータに搭載されている 3D デバイスは認定されていません。 オートデスクで動作が確認されたグラフィックス カードと 3D ディスプレイ ドライバは、オートデスクの Web サイトで公開されています。 最新の認定リストをダウンロードして更新を確認することができます。3DCONFIG コマンドを起動し、[更新をチェック]ボタンをクリックしてください。 現在のアプリケーション ドライバ: acaddm10.hdi と表示されます。 解決方法をご指導願います。

  • Bitmapを重ね合わせる方法

    最近プログラミングを始めた初心者です。 環境はXP SP2 及びVC++6.0 です。 Win32APIのみを用いてプログラミングしております(MFCは使えません)。 宜しくお願い致します。 やりたいことは、あるビットマップを背景にして(bmpback.bmp)、その上に、bmpback.bmpよりサイズが小さいbmp1.bmpとbmp2.bmpを、WM_TIMERを使って交互に表示させる、です。 その際、WM_TIMER内でbmpback.bmpとbmp1.bmp(又はbmp2.bmp)を重ね合わせたbitmapを作成し、そのbitmapをWM_PAINT内でBitBltなどを用いてメモリDCからクライアント領域用のDCに転送して、ディスプレイに表示させたいと考えています。 検索したところ、以下のリンクに正に同じ質問があったのですが、難しくて理解出来ませんでした。 http://oshiete1.goo.ne.jp/qa1474735.html 回答者様が、良回答20ptで書かれている内容の、 >最終的に表示したい大きさのビットマップをメモリDCに割り当てて、 >そのメモリDCに対して10回のBitBltを行います。 の部分です。 最終的に表示したい大きさのビットマップ、というのが私の場合bmpback.bmpになると思いますが、例えばbmpback.bmpがSelectObject()でメモリDCに関連付けされているとして、そのメモリDCにbmp1.bmpをBitBltで転送する場合、bmp1.bmpに関連付けられるべきDC(デバイスコンテキスト)は何になるのでしょうか? (メモリDC→メモリDCかなあとも思ったのですが、それだとbmp1.bmpを紐付けした時点でbmpback.bmpが消えてしまうような気がして、ちょっと違うかなあと) 分かり辛い説明で申し訳ありませんが、知りたいことは、あるBitmapに別のBitmapをBitBltで転送して重ね合わせたい場合、コピー元のビットマップに関連付けるDCは何にすべきか、ということです。 本当は透過処理もしたいところですが、それは後で調べることにしてまずはBitBltで動作を見たいと思っています。 宜しくお願い致します。

  • windowsのAPIプログラミングでの差分描画?

    windows98でAPIでwindow内に持続的に描画(60回/秒とかで)しているのですが、毎回そんな描画する内容が変わらないので違う部分だけを書けば高速化出来るのではと思っています。よい方法はないでしょうか?? 具体的には折れ線グラフを連続的に表示するプログラムです。一回メモりDCに書いてからbitbltしてます。このbitbltでメモリdcの全部を転送しているので遅いと思うのですが、更新部分だけをどうにか(リュージョンとかを使って?)うまくできないかと思っています。お願いします。

  • ビットマップの描画方法

    こん○○は。 BCB5を使ってますが、 高速にビットマップを描画する方法はないでしょうか? TImage コンポーネントを使用し Picture->Bitmap->Canvas->Pixels[x][y] へ SDKから取得したカメラ画像データをTColor RGB(r,g,b)で設定しています。 フォームに画像が表示されるまで1秒ほどかかるためコマ送り状態になっています。

  • ピクチャーコントロールへの描画方法について

    お世話になります、fujitomoです。 現在、Visual Studio2005にてC++のダイアログベースのアプリケーションを作成しており、行き詰った箇所があったため質問させて頂きました。 アプリケーションの内容としては 現在、アプリケーションで、ダイアログベース上にピクチャーコントロールを2つ設置し、それぞれに波形を描画させています。 ピクチャーコントロールへの波形の描画にはメモリデバイスコンテキストを使い、それぞれ波形描画用のCStatic派生クラスを作成し、そのクラスを SubclassDlgItem でメインダイアダイアログのサブクラスとし、描画間隔として、それぞれの描画クラス内で SetTimer(1,10,NULL) でタイマーイベントを起こし、メモリデバイスコンテキストの描画更新をしています。 ここで質問させていただきたい事なのですが、 2つのピクチャーコントロールのうち、1つのピクチャーコントロールへのみ波形描画を実行させているときはピクチャーコントロールの端から端まで描画が約7秒かかるのに対し、 2つのピクチャーコントロールの描画を同時に実行させた場合には端から端までで約11秒もかかってしまいます。 これを何とか、1つのピクチャーコントロールへの描画時間と同じ時間まで早く出来ればなと思っているのですが、どの様に工夫すれば時間短縮をさせることが出来ますでしょうか? 2つのクラスでそれぞれ10msのタイマーを動かしているのが問題なのかと思い、メインダイアログで10msのタイマーイベントを発生させ、それぞれの描画クラスに描画更新のメッセージを送信させるようにコードを変更してみたのですが、やはり同じ結果となりました。 開発環境は Widows CE 6.0 Visual Studio 2005 です。 ご意見、ご回答をお待ちしております。よろしくお願い致します。

  • クライアント領域をCBitmapに取り込みたい

    VC6.0MFCで クライアント領域(みたまま)を CBitmapに取り込みたいのですがどうすればよいのでしょうか? ためしにダイアログの領域をクリップボードに取り込むコード OnPaint書いたのですが真っ黒の画像しか取り込めていませんでした。 根本的に使うAPIが違うのでしょうか? void CCaptureDlg::OnPaint() {  CPaintDC dc(this); // 描画用のデバイス コンテキスト  CRect cr;  GetClientRect(&cr);  dc.TextOut(0,0,"テスト");  CDC* pDC = new CDC();  pDC->CreateCompatibleDC(&dc);  CBitmap img;  img.CreateCompatibleBitmap(pDC, cr.Width(), cr.Height());  OpenClipboard();  ::EmptyClipboard();  ::SetClipboardData(CF_BITMAP, img.GetSafeHandle());  ::CloseClipboard();  pDC->DeleteDC();  delete pDC;  CDialog::OnPaint(); }

  • CImage::ReleaseDC()のエラーで困っています。

    CImage::ReleaseDC()のエラーで困っています。 ウインドウ上に複数の画像を表示し、それぞれ配置や大きさを マウスのD&Dで変えられるようなアプリを作っています。 Visual Studio 2005 C++, MFC 画像はCImageクラスのm_ImageへLoadしてあります。 GetDCでハンドルを取得しているので、ReleaseDCにて開放を 行っていますが、そこで下のエラーになります。 [Second Chance Assertion Failed: File c:\program files\microsoft visual studio 8\vc\atlmfc\include\atlimage.h, Line 1217] 何か解決のヒントになる事がありましたら教えてください。 void CImageButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { (前略) //ウィンドウDC互換Bitmap作成 CBitmap Bmp; Bmp.CreateCompatibleBitmap(pDC, nWidth, nHeight); //メモリDC作成 CDC MemDC; MemDC.CreateCompatibleDC(pDC); //メモリDCにBitmap選択 MemDC.SelectObject(&Bmp); //メモリDCにストレッチ描画 MemDC.SetStretchBltMode(HALFTONE); CDC* pImgDC = CDC::FromHandle(pBtnInfo->m_Image.GetDC()); HDC hImgDC = pImgDC->m_hDC; pBtnInfo->m_Image.StretchBlt(MemDC.m_hDC, 0, 0, nWidth, nHeight, SRCCOPY); pBtnInfo->m_Image.ReleaseDC(); (中略) //四角形を描画 CPen focusPen(PS_DOT, nPenWidth, RGB(nR, nG, nB)); CPen* OldPen = MemDC.SelectObject(&focusPen); MemDC.MoveTo(btnRect.left, btnRect.top); MemDC.LineTo(btnRect.left, btnRect.bottom); MemDC.LineTo(btnRect.right, btnRect.bottom); MemDC.LineTo(btnRect.right, btnRect.top); MemDC.LineTo(btnRect.left, btnRect.top); MemDC.SelectObject(OldPen); //メモリDCからウィンドウDCにビット転送 pDC->BitBlt(0, 0, nWidth, nHeight, &MemDC, 0 ,0, SRCCOPY); (後略)

  • C#で派生クラスから描画処理を行う

    C#を勉強しているのですが、GUIを作り初めて描画処理で分からない所があり、質問させて頂きます。 基本クラスの方で「Hello, world!」という文字列をDrawStringで表示させる事は出来たのですが、それを基本クラスを継承した派生クラスのメソッドで行うと何も表示されないんです。 以下が試したコードです。 //基本クラスSample1 using System; using System.Drawing; using System.Windows.Forms; public class Sample1 : Form {   protected Bitmap image; protected Graphics g; protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Sample2 s = new Sample2(); s.helloworld(); e.Graphics.DrawImage(image, 0, 0); } public Sample1() { SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); image = new Bitmap(600, 400); g = Graphics.FromImage(image); } static void Main() { Form form = new Sample1(); form.Text = "sample"; form.ClientSize = new Size(600, 400); form.BackColor = Color.FromArgb(0xff, 0xff, 0xff); Application.Run(form); } } //派生クラスSample2 using System; using System.Drawing; using System.Windows.Forms; public class Sample2 : Sample1 { Brush brush = new SolidBrush(Color.Black); public void helloworld() { g.DrawString("Hello, world!", this.Font, brush, 10, 10); } } なぜ表示されないのか分かる方いらしたら、ご教授願えないでしょうか。是非お願いします。