• ベストアンサー

より高速な画像の表示法

医療画像(DICOM)のバイナリデータを読み込んで表示させるプログラムを作っているのですが、非常に遅い(約4秒)ので改善したいのです。 おそらく、ループ中での、エンディアンの変換とPixelへの張付けが原因と思うのですが、改善方法が判りません。宜しくお願いします。 BolandC++Builder6,Pentiam4,1Gメモリ,XPの環境です。 DICOMO画像のファイルサイズは約2053kB 画像データは1024*1024の16ビットです。 __________________________________ Byte bb[2097152]; int iImage[512][512]; word c,wData; fp=fopen("filename","rb"); setvbuf(fp,NULL,_IOFBF,4096*1024*1024); while(gData!=0xE07F) //グループタグの検索// fread(& gData,2,1,fp); while(eData!=0x1000) //エレメントタグの検索// freadd(& eData,2,1,fp); fread(&wData,2,4,fp); //空読み// fread(bb,1,2097152,fp); //画像データ// fclose(fp); for(y=0;y<=512;y++){ for(x=0;x<=512;x++){ wData=256*bb[4*x+4096*y]+bb[4*x+4096*y+1]; c=wData*256/4096; iImage[x][y]=c; Image->Canvas->Pixels[x][y]=(TColor)((c<<16)|(c<<8)|c); c=0; } }

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

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.8

原因は幾つか推測できるだろうと思います。 が、ここでやるべきは闇雲にここが怪しいからいじってみよう という場当たり的な対処ではなく、 きちんとプロファイリングをして、どこがホットスポットなのかを 見極めることだと思います。 もっともC++ Builderだとまともに使えるプロファイラがあるのかどうか わかりません(無責任ですみません)。 少なくとも無料で使えるものはないかも知れません。

t0103
質問者

お礼

その後、ダブルバッファの様な処理をさせたところ、0.4sと約7倍速くなりました。貴重なご意見ありがとうございました。

t0103
質問者

補足

遅くなりましたがご意見を参考にしてclockで処理時間を計測しました default 3.00s 配列を[y][x] 2.47s #16#17 2.49s Canvas->Pixel[x][y]を外し、新たな配列に入れた場合 0.062s となりました。 Canvas->Pixel[x][y]の処理が遅い原因のようですが、ループ内ではBitmapの画素値の計算だけにして、ループ外でBItmapの配列を直接imageに貼付ける処理を試してようと思いますが、方法が判りません。 

すると、全ての回答が全文表示されます。

その他の回答 (17)

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.7

>★fread の部分が遅くなっている気がします。 >・fopen() 後のループである fread() をしない方が良いでしょう。 >freadをせずにメモリの確保しメモリ上で検索するには メモリ上で検索しても余り意味がない。 Cのライブラリルーチンは内部的にバッファを持っていて、バッファリングされてメモリ上にあるデータは、IO操作せずにメモリ操作しかしない。 freadの関数のオーバーヘッドが多少減るのみで、高速化は期待出来ない。 「スキップするヘッダのサイズが数キロバイトで、freadが数千のオーダーで呼ばれる」とかなら、最適化も充分に意味があるが、「患者氏名」とかが入ってるなら、せいぜい繰り返しても数十回であろう。

t0103
質問者

お礼

回答ありがとうございます。 freadの回数は2000回オーバーですので、期待はできるかもしれません。 ただ、やり方がよく判らないのです。

すると、全ての回答が全文表示されます。
noname#39970
noname#39970
回答No.6

ええともう片方はこうかな wData=256*bb[4*x+4096*y]+bb[4*x+4096*y+1]; ↓ //演算回数の削減 a= (x<<2) + (y<<12); wData= (bb[a]<<8)|bb[++a];

すると、全ての回答が全文表示されます。
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.5

>wData=256*bb[4*x+4096*y]+bb[4*x+4096*y+1]; >c=wData*256/4096; ここ、何か変ですね。上位、下位で2バイト持って来ておきながら Wordのデータを256倍して上位バイトを捨て、12ビット分の除算で、下位側の4ビットだけ残してる。 >Image->Canvas->Pixels[x][y]=(TColor)((c<<16)|(c<<8)|c); 最終的には、cが8ビットで、それをRGBの24ビットのR,G,B同じモノクロにしているつもりになっている。 もし「1画素16ビットの1024×1024を、間引きして、8ビット256階調の512×512にする」んで正しければ、以下のようになる。 -------------- Byte bb[2097152]; Byte *p; int iImage[512][512]; word c,wData; fp=fopen("filename","rb"); setvbuf(fp,NULL,_IOFBF,4096*1024*1024); while(gData!=0xE07F) //グループタグの検索// fread(& gData,2,1,fp); while(eData!=0x1000) //エレメントタグの検索// freadd(& eData,2,1,fp); fread(&wData,2,4,fp); //空読み// fread(bb,1,2097152,fp); //画像データ// fclose(fp); p=bb; for(y=0;y<=512;y++){ for(x=0;x<=512;x++){ c=*p++;//cは16ビットの上位バイト iImage[x][y]=c*256+*p;//iImageには16ビット分を格納 Image->Canvas->Pixels[x][y]=(TColor)(c*0x010101); p+=3; } p+=2048; } -------------- >c=wData*256/4096; の意味が良く判らないが、元ソースのまま、同じ動作にするなら -------------- Byte bb[2097152]; Byte *p; int iImage[512][512]; word c,wData; fp=fopen("filename","rb"); setvbuf(fp,NULL,_IOFBF,4096*1024*1024); while(gData!=0xE07F) //グループタグの検索// fread(& gData,2,1,fp); while(eData!=0x1000) //エレメントタグの検索// freadd(& eData,2,1,fp); fread(&wData,2,4,fp); //空読み// fread(bb,1,2097152,fp); //画像データ// fclose(fp); p=bb; for(y=0;y<=512;y++){ for(x=0;x<=512;x++){ wData=*p*256+p[1]; c=wData*256/4096; iImage[x][y]=c; Image->Canvas->Pixels[x][y]=(TColor)(c*0x010101); p+=4; } p+=2048; } -------------- になる。「c=wData*256/4096;」の意味が理解不可能なので、ここは最適化せずにそのまま残している。

t0103
質問者

お礼

回答ありがとうございます。 もし「1画素16ビットの1024×1024を、間引きして、8ビット256階調の512×512にする」んで正しければ、以下のようになる。 この解釈でよいのですがうまく動きませんでした。

すると、全ての回答が全文表示されます。
noname#39970
noname#39970
回答No.4

ごめん 違った c=wData*256/4096; は 単純に上の桁を8bit排除する物なのかな c=wData>>4; //排除しないならこうだと思う。(通分)

すると、全ての回答が全文表示されます。
  • noocyte
  • ベストアンサー率58% (171/291)
回答No.3

> setvbuf(fp,NULL,_IOFBF,4096*1024*1024); 4GB のバッファですか!? しかも,メモリが 1GB しかないのに. これは確保に失敗しているでしょう. いや,それ以前に,size_t が32ビット以下ならば, 4096 * 1024 * 1024 はオーバーフローして0になっているはずです. (コンパイル時に警告とかエラーになりませんでしたか?) いずれにしても setvbuf() はエラーを返しており, バッファは確保されていないはずです.それが遅さの原因と思われます. ちゃんとエラーチェックをする習慣をつけてください. (fread() についても.)

t0103
質問者

お礼

回答ありがとうございます。 setvbufについて。PCはネットに繋いでいないので、Macから質問しているのですがタイプするときに*1024を1回間違いました。 私のタイプミスで余計なお時間を取らせてしまいました。 (fread() についても.)はどういう意味でしょうか?

すると、全ての回答が全文表示されます。
noname#39970
noname#39970
回答No.2

うーん 見てぱっと考えつくのは 2の乗数による乗除算を論理演算・ビット演算に置き換えていく事かな 例えば c=wData*256/4096; //↓(これは下8bitをちょん切って更に3bitずらす作業だと思う) c=(wData&0xfff8)<<3; //型の大きさで0xfff8は適当に。 //手を抜くなら (!((!wData)|0x7))<<3 とか。ステップ数多いから遅いかも

すると、全ての回答が全文表示されます。
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.1

★fread の部分が遅くなっている気がします。 ・fopen() 後のループである fread() をしない方が良いでしょう。  つまり、画像全体が収まるメモリを確保して、その画像ファイルすべてを  メモリに読み込みます。そして、メモリ上で『グループタグの検索』や  『エレメントタグの検索』を検索してみます。メモリが多いなら出来るかな。 ・あと別の方法で一度、画像データから『グループタグの検索』や『エレメントタグの検索』を  検索して画像の読み込む位置を別のファイルに保存しておきます。  そして、その位置ファイルを先に読み込み、fseek() 関数で位置を移動してから  瞬時に画像データを 2097152 バイト分読み込む方式を取ればもっと高速になります。  また、メモリも画像データを読み込む 2097152 バイト分で済みます。 ・以上。参考に。

t0103
質問者

お礼

回答ありがとうございます。 freadをせずにメモリの確保しメモリ上で検索するには具体的にどうやるのでしょうか? DICOMはタグの位置は画像毎に異なる(患者名の長さ等)ようなので後者は難しいです。

すると、全ての回答が全文表示されます。

関連するQ&A