• ベストアンサー

Microsoft bmpファイルをラスタ順序逆にするには?

Microsoft の bmpファイルフォーマットというものがあります. このフォーマットは,格納順序が画像の底辺(画像で言うと,ボトム)ラスタからトップラスタ(画像で言うと上)に向けて格納されています. わけあって,トップのラスタからに並べ替えたいのですが,メモリがあまりありません. 全体を読み込んでから,逆順でファイルにはき出せば 良いと思いますが,これだと, たとえば1GBのデータだと1GBのメモリが必要です. メモリを使わずに, ファイルをシークして読み込んでから,書き込むとすると,かなり遅そうです. 実装されているメモリ容量の単位で区切って読み書きするなどの あまり複雑な事をせずに,スマートにラスタ順序を入れ替える方法をご存知でしたら,よろしくお願いします. アプリは,単純だけど,仮想記憶でOSが勝手にスワップ させるような方法も使いたくないです. なにかアルゴリズムやファイルシステムの特性を使って うまくできませんかね. 漠然としていると,まずいかもしれません. メモリが128MB程度あって,画像bmpファイルが1GBの大きさがあるときに,ラスタの順序を入れ替えるのが目的です. なるべく高速にやりたいです. ディスクへのスワップはさけたいです.

  • FM-8
  • お礼率93% (124/133)

質問者が選んだベストアンサー

  • ベストアンサー
  • jx-word
  • ベストアンサー率40% (38/94)
回答No.1

1ライン分ずつシークして処理すればいいんじゃないでしょうか。 ファイルポインタのシークはメモリ上のポインタを書き換えるだけだから、そのコストはほとんど無視できるレベルだと思います。 ラインの境目で多少のロスが出るでしょうが、これもOS側がディスクキャッシュで吸収します。 なんとなく考えすぎているだけのように思えますので、実際に簡単なコードを書いて試してみてはいかがでしょうか。

FM-8
質問者

お礼

ありがとうございます. >なんとなく考えすぎているだけのように思えますので、実際に簡単なコードを書いて試してみてはいかがでしょうか。 たとえば,1GBのデータとは, 24ビットフルカラーで,20000x20000 程度の画像を意味します. ディスク側のキャッシュがどの程度の大きさなのかも知らずに質問しております. ご回答は,「普通にプログラムすればいいのでは?」 ということですね. ご回答の方法は,私はたしかに試してはいません. ただし,仲間が,質問した内容でプログラムして, 「ものすごく遅かった」という評判だったので, なにかいい方法はないものかなぁと考えて質問しました. 自分のマシンは,高速(2.7GHz)で,メモリもたくさん(2GB)つんでいるので,たぶん,どちらの方法も高速にはなると思うのですが,非力なマシンに対しても,そこそこの性能を出す方法が知りたいわけです. 一度,自分でも,試してみたいと思います. しかし,非力なマシンは世の中たくさんありますし,アルゴリズムで速度が一変することも良くあります. マシンパワーにあまり依存しない「知恵」は無いものでしょうか? かなり前,アスキーという雑誌で, 画像を表現する容量として,16ビット×16ビットあれば大丈夫だろうという議論が,20年前にありました. これは,65536x65536ということです. 当時は,途方も無い大きさに感じましたが, わずか20年で,これに迫る大きさを末端のパソコンが 扱う時代になってきました. ありがとうございました.

その他の回答 (3)

  • rentahero
  • ベストアンサー率53% (182/342)
回答No.4

#2です。 #3の方法で問題ないと思います。(未検証) 一応#2の回答の補足への回答などを少し。 > 逆ラスタ順序での格納をファイルのシークでやるとしたら, > ディスクを逆さまに読んでいくことになり,へたをすると > ディスクが1回転してくる待ち時間が,毎ラスタごとに > 入るのではないかと心配してました.そんなにディスク > キャッシュが小さいことはないと思いますけど. 実のところ、今のHDDのシリンダ構成(http://e-words.jp/w/ZCAV.html)とか、LBA(http://e-words.jp/w/LBA.html)がなぜできたかとかそういうのを考えると、もうシリンダ面にどうセクタが並んでいるのかなんて、予測できないんですよ。だから、シリンダ1回転の間のギャップウェイトとかは、今は考慮しなくてもいい(本当のところは考慮できないが正しい)んです。 もちろんヘッドシークの時間は関係あるんですが、それを考慮するしてもやっぱり物理メモリを調べて空きメモリの何割かを利用してバッファリングするぐらいしかできないです。これは試してないので、何割とれば最適化はわかりません。 ヘッドシークを最小限にするために読み&書きのファイル位置の切り替えを最小限にすることと、先読みキャッシュ&書き込みキャッシュを最大限に利用するためにキャッシュ容量を最大限に確保することは相反するためです。 > このあたり,なんとなく昔の64KByteセグメントの時代を > 思い出しました.スモールモデルとかラージモデルとか > あったときの話です. わかります。私がPCでプログラム書き始めたころ(も15年近く前)でもまだDOS時代でした。最初に使ったCコンパイラはLSI-C86 試食版でした。 フロッピの場合、回転速度を考慮しないと最速アクセスはできないんでしたよねえ。 弁解&ヨタ話でした。

参考URL:
http://e-words.jp/w/ZCAV.html, http://e-words.jp/w/LBA.html
FM-8
質問者

お礼

たびたびありがとうございます. >シリンダ1回転の間のギャップウェイトとかは、今は考慮しなくてもいい(本当のところは考慮できないが正しい)んです。 「そこのところをぜひ考慮したい」という質問だったのですが,伝わらなかったみたいですね. 申し訳ありません. >先読みキャッシュ&書き込みキャッシュを最大限に利用するためにキャッシュ容量を最大限に確保することは相反するためです。 それは,どこをアクセスするか分からない場合ですね. かならずアクセスするところだけキャッシュに入れれば,キャッシュは大きい方が良いと思いますよ. CPUのキャッシュとは違いますから. 実際,そんなに簡単なことを質問したつもりはありません.頭を絞らないと,質問にも書いた,シンプルだけど高速で逆ラスタで格納できるアルゴリズムはできないでしょう.そこがまた面白いところでもあります. しばらく楽しめそうです. ありがとうございました.

  • jx-word
  • ベストアンサー率40% (38/94)
回答No.3

#1です。 あのあとよく考えてみたら、1ラインごとに処理をしていたらHDDのヘッドシークの時間がかかることに気がつきました。申し訳ありません。 で、高速化の方法ですが、基本は1ラインごとに交換するとして、バッファを数ライン分用意してReadFileとWriteFileをまとめて処理してはいかがでしょうか。 この場合、バッファがスワップアウトされたら本末転倒ですので、バッファはスワップ禁止にします。 1. GlobalMemoryStatusで物理メモリの空き容量を取得し、バッファ容量をどのぐらいにするか決める。 2. VirtualAllocでバッファを確保する。 3. VirtualLockでバッファをスワップ禁止にする。 4. このバッファを使ってラインの交換をする。 5. VirtualUnlock, VirtualFreeで後始末。 VirtualLockは使ったこと無いんですが、MSDNを見る限りこれでいけそうな気がします。

FM-8
質問者

お礼

たびたびありがとうございます. >1. GlobalMemoryStatusで物理メモリの空き容量を取得し、バッファ容量をどのぐらいにするか決める。 物理的にとれるだけのメモリをまず,調査して,それを最大限に生かすようにすると言うわけですね. このあたり,なんとなく昔の64KByteセグメントの時代を思い出しました.スモールモデルとかラージモデルとかあったときの話です.現在は,リニアな空間をつかった単純なプログラムの時代かと思っていたのですが, そうも行かないようですね. 問題が単純なだけに,クリアーな解はなくて, ゴシゴシと書かなくてはならないということがだんだん分かってきました. bmpファイルのラスタは,32ビットバウンダリに合わせてあるので,4バイト単位で取得すればいいですね.

  • rentahero
  • ベストアンサー率53% (182/342)
回答No.2

え~っと。 非圧縮のBMPの処理ですよね。 1GB読んで1GB書かないといけないということは わかりますよね? ということは、最低でも画像のフルコピーをやるのと同じコストは確実にかかります。 フルコピーに係る処理は 1.ヘッダのメモリを確保して読み込み。 2.コピー先にヘッダを書き込み 3.ヘッダにあるライン容量分のメモリ確保 4.ライン数分くりかえし 5.コピー元から1ライン読み込み 6.コピー先に1ライン書き込み 7.4にもどる 8.おわり 逆順のフルコピーに係る処理は 1.ヘッダのメモリを確保して読み込み。 2.コピー先にヘッダを書き込み 3.ヘッダにあるライン容量分のメモリ確保 4.ライン数分くりかえし 5a.コピー元の未読み出し中最後のラインの先頭へシーク 5.コピー元から1ライン読み込み 6.コピー先に1ライン書き込み 7.4にもどる 8.おわり 上記に5aの処理が追加されただけです。 遅いPCで1GBのフルコピーをやるとそれだけで1秒単位のかなりの時間がかかります。 そこは、アルゴリズムで何とかなるような構造ではないです、というかほとんどディスクとPCIバスのベンチマークの世界です。 ファイルシステムの特性という部分では、DOS時代でかつ、クラスタ単位で1ラインのデータが入ってると確定しているのであれば、クラスタのつなぎ変えで処理できたかもしれないけど、クラスタ長が固定のFAT上ではwindows bmp(に限らずたいていの汎用画像フォーマット)ではありえないです。ヘッダもあるし、縦横のdot数もデータサイズも可変だし。

FM-8
質問者

お礼

ありがとうございます. >ということは、最低でも画像のフルコピーをやるのと同じコストは確実にかかります。 もともと,ラスタ順序を変えずにフルコピーするのよりも速くなるとは思っていません. 基本的に,ディスクの回転時間で,格納されているデータを単に読み出す時間はかかります. 書く時間も当然必要です. この際,キャッシュの容量や,バスの速度が遅ければ, さらにかかるでしょうね. 通常,メモリが潤沢にあれば,この差はほとんどゼロに等しくなり,ディスクの回転時間による読み出し時間に近くなると思います. 逆ラスタ順序での格納をファイルのシークでやるとしたら,ディスクを逆さまに 読んでいくことになり,へたをするとディスクが1回転してくる待ち時間が,毎ラスタごとに入るのではないかと心配してました.そんなにディスクキャッシュが小さいことはないと思いますけど. >そこは、アルゴリズムで何とかなるような構造ではないです、というかほとんどディスクとPCIバスのベンチマークの世界です。 そうなんですか. どうやら,自分でいくつかコードを書いて, 実験した方が良いようですね. ありがとうございました.

関連するQ&A

  • bmpファイルについて

     bmpファイルを「マイピクチャ」に保存して、縮小版で表示する時にサムネイル画像が表示されるまでものすごく時間がかかってしまいます。  以前は画像が入っているフォルダを開けるとすぐに全部の画像が表示されていました。  「IrfanView」や「ViX」で閲覧する時は瞬時に表示されます。  PCのメモリは512MBでIE6を使っています。宜しくお願いします。

  • 「開く」ダイアログなどでのファイルの表示順序

    アプリケーションの「開く」や「保存する」のダイアログで表示されるファイルの表示順序が名前順でなく、更新順や名前の逆順になったりしてしまっています。 このアプリケーションの場合はこう、という規則性もなく、すべてのアプリケーションで症状が出るので困っています。 一応過去ログを調べてみると、同様の質問はあったのdすが、解決されないまま終了していました。 修復方法をご存じでしたらお教えください。 よろしくお願いします。 環境:WindowXP SP2,IBM NetvistaA41,メモリ1GB,ハードディスク40GB 使用ソフト:Adobe、マクロメディアなどのデザイン系アプリケーション

  • 画像(bmp等)の保存形式について

    画像(bmp等)の保存形式について 画像の保存のフォーマットについて質問です。 bmpの形式についてのwebページをみてみたんですが、 structを書いてメンバをかいていたりするんですが、 bmpのファイルをテキストエディタでみてみてもうまくみれないし、 やっぱりバイナリエディタでみると数字の羅列なんですが、 実際に作る場合にはstructとかを書いた後に使うコンパイラみたいなものがあるんでしょうか? struct等C言語のプログラミングの知識はあります。 よろしくお願いします。

  • C言語でBMPファイルの内容を表示 その2(Unix使用)

    こんにちは。私は30代の男性です。 以前、コマンドラインで指定したBMPファイルの中身をバイナリ形式で読み込むということにチャレンジして、とりあえずBITMAPFILEHEADER構造体の中の情報を引き出すことには成功しました。 ※以前の質問とご回答 → http://okwave.jp/qa2837931.html fread関数を使ってoffsetという情報(ファイル先頭から画像データまでのバイト数)を取り出すことができたので、あとはBMPファイルの先頭アドレスからoffsetのバイト数分だけ進んだ箇所からデータを取り出して出力すれば、数値として格納されている画像データが引き出せると思ったのですが、うまくいきません。 どのようにアドレスを指定すれば、バイナリ形式の画像データを表示できるのでしょうか?宜しくお願い致します。

  • 特定の画像だけBMP保存になってしまいます

    よく、IE上でjpgがBMPで保存になってしまうのは PCが疲れてるからだとか、一時ファイルがたまってるからだとか、ありますが、 一時ファイルはクリアーしてますし pen2.6G メモリ1G、光回線のPCが二台とも ttp://4travel.jp/img/tcs/t/album/1004/src_10044072.jpg の画像をIEで保存しようとすると ダイアログ上bmpになってしまいます。 jpgで保存できません。ファイル名をjpgに変える 方法はなしでお願いします、 最初から本当のjpg形式で保存したいんですし、 なによりこの画像だけっていうのが気になります。 このサイトのっていうか・・ 他のサイトの新しい画像をクリックしてもBMPの ダイアログはでないので・・

  • Mac版IEでWeb上のWindowsのbmp画像を表示させられるか

    Mac版IEのデフォルト設定では、Webページに埋め込まれたbmp画像を表示できませんよね。これを表示させる設定は可能でしょうか。 もちろんWeb上での画像フォーマットとしてbmpを使うべきでないことは承知しています。Netscapeでは表示されることもわかっています。また、IEでも、サーバにbmp画像を単体でアップして、それを表示させるのはファイルヘルパーの指定を変更して可能になりました。ただ、htmlに埋め込まれたbmpの表示は、どう設定を変えてみてもできないのです。これは可能かどうかお聞きしたいと思います。IE初期設定のファイルヘルパー設定ダイアログで、「Windows bmp 画像」というのを変更すれば出来るように思うのですが、うまく行きません。そして変更画面ででてくるファイルの種類で、BMP, BMPf, BMPpと3種類ありますが、この違いがわかりません。クリエーターもogleでよいのかどうか… ただ単に、できないのかなと疑問に思ってお尋ねしているだけですので、もしご存知でしたらお教えいただきたいと思います。

    • ベストアンサー
    • Mac
  • 大容量のファイルがコピーできません

    ブルーレイに格納したファイル、約44Gのファイルをコピーしようとすると、途中で「無効なMS-DOSファインクションです」と表示されて止まってしまいます。PCのリソースは問題ないと思うのですがお分かりになる方教えてください。 PCメーカー:DELL OS:Windows7 64bit es7 64bit CPU:インテル i7 メモリ:12GB ディスク:1TB(Cドライブには300GB割り当て、空き領域105GB)       回転数:7200 ディスクフォーマット:NTFS

  • 画像を保存するとBMPになってしまう、その後もダメ

    ブラウザでサイトを見ているとき、 画像を自分のパソコンに保存しておこうとすると、 それがjpgでもgifでもpngでも、どんな画像でも 「無題 bmp」となってしまいます。 それを直すためにはインターネットオプションからインターネット一時ファイルの削除、とやったらいいと言われて、そのようにすれば問題は解決していました。 それが、最近は一時ファイルの削除をすると、そのままブラウザの動作がとまってしまい、タイトルバーをクリックすると「応答なし」とでて、動かなくなってしまいます。 その後もう一度ブラウザを起動すると、今度は画像を正しい拡張子で保存できるので、問題はないのですが、面倒なのです。 この件について、何か原因のわかる方、 また、対策のわかるかた、ご教授ください。 パソコンは、 メモリ1024MB HDD 160GB OSはWinXP インターネット一時ファイルの中身は空です。

  • fread エラー C Xcode bmpファイル

    こんにちは。プログラム初心者の大学生です。 現在研究室で作成しているプログラムについて、自身で解決できないエラーが出たため、 お詳しい方に教えていただけないものかと思い投稿しました。 以下のプログラムで、32ビットbmpファイルのヘッダ情報を読み込み、表示させようとしています。 展望としてはヘッダ情報を誘致しておき、後々参照する予定です。 プログラムはMacのXcode(C言語)で作成しているのですが、 fread(PictureHeadBuf, sizeof(unsigned char), 54 ,fpIN); の行で EXC_BAD_ACCESS と表示され、うまく動作しません。 配列のメモリ管理がどうも怪しそうですが、具体的な解決方法がわからない状態です。 なかなか先に進めずに困っています。もし原因のわかる方がいらっしゃれば教えてください。 ぜひよろしくお願い致します。 #include <stdio.h> #include <stdlib.h> /* 入力画像ファイル関連 */ #define FILE_NAME "test.bmp" /* 元データのファイル名 */ int main(void){ int i; /* 入力画像ファイル関連変数 */ FILE *fpIN; unsigned char PictureHeadBuf[54]; /* ヘッダ用バッファ */ unsigned char Header[54]; /* ヘッダの誘致先 */ /*入力画像ファイルをオープン*/ fpIN = fopen(FILE_NAME, "rb"); /*ヘッダ(ファイルヘッダ,情報ヘッダ)の格納 */ fread(PictureHeadBuf, sizeof(unsigned char), 54 ,fpIN); for(i = 0; i < 54; i++){ Header[i] = PictureHeadBuf[i]; printf("%d\n", Header[i]); } /* 入力画像をクローズ */ fclose(fpIN); return(0); }

  • BMPのフォーマットの詳細について教えてください!

    BMP(といってもいくつかありますねぇ・・) とりあえず、Windowsの独立DIBのBMPで、 RLE圧縮されていないバージョンのBMPのフォーマット(というか仕様?)、 に関する情報、を探しています。 例えば、私がGIF連結システムを作ったときに 参考にさせていただいた仕様は次のようなものでした。 GIF Header Offset Length Contents 0 3 bytes "GIF" 3 3 bytes "87a" or "89a" 6 2 bytes <Logical Screen Width> 8 2 bytes <Logical Screen Height> 10 1 byte bit 0: Global Color Table Flag (GCTF) bit 1..3: Color Resolution bit 4: Sort Flag to Global Color Table bit 5..7: Size of Global Color Table: 2^(1+n) 11 1 byte <Background Color Index> ・・・などなどなど でした。 こういう感じで、BMPのフォーマット仕様書ってネット上にころがってないでしょうか? とりあえず必要なのは、どこのバイナリデータが何を示しているのか? という情報です。 やりたいことは、BMPのパレット番号を(画像を維持したまま) 切りかえるコマンドツールの作成、もしくは同様のコマンドラインツールの入手です。 (今は普通のWindowsツールで、そのツールでは、操作の都合上、連続処理することが出来ないのです) 数百個のBMP画像ファイルのパレット番号を機械的に入れ替えたいので そのようなツールの作成、もしくは入手をもくろんでいます。 いろいろな角度からの解決法を提供していただいても結構です。 Perlで、GDなどを使って簡単に解決できるよ!というご意見や、 C/C++ライブラリでこのように書けば・・・というご意見、 などなどでも結構です。 よろしくお願いします m(_ _)m

専門家に質問してみよう