ページ 11

画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 14:37
by いちこ
こんにちは。
本日もよろしくお願いします。

1600x1600画素のraw画像をfread()関数で読み込み、1画素ずつ処理を行ってから、fwrite()関数で書き出します。
処理速度をあげたいと思い、1回で1600x1600画素読み込んでいるのですが、1画素ずつ読み込んで適宜処理を行った場合とプログラムスピードが変わりません。
改善できる点を教えていただきたいです。
よろしくおねがいします。

※ソースコード全体は長いので、割愛します。知りたい部分がありましたら、ご指摘いただけるとうれしいです。
下のコードは、画像を読み込んで、処理をして書き出す部分です。
buf,buf2は1600x1600の要素を持つ符号なし文字型の配列です。
maxとminには、画素の最大レベルと最小レベルを指定しており、画像の画素値がmax以上だと255に、min以下だと0に無理やり値を持っていきます。
それ以外であれば数式により補正を行います。

コード:

  fread(buf,1,1600*1600,fp);
  
  for(i=0; i<1600*1600; i++){ 
    if(buf[i]>max) buf2[i]=255;
    else if(buf[i]<min) buf2[i]=0;
    else{
      buf2[i]=(char)((255*sqrt(buf[i]-min))/sqrt(max-min)); //補正
    }    
  }

  fwrite(buf2,1,1600*1600,fp_adjusted);
  

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 14:46
by h2so5
ループ内でmaxとminは変化していないので、sqrt(max-min) を毎回計算するのは無駄じゃないですか?

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 15:02
by いちこ
>>h2so5さん
返信ありがとうございます。
確かにそうですね。

int型のcを宣言し、
はじめにc=sqrt(max-min); としておいてから、cに置き換えてみました。

コード:

      buf2[i]=(char)((255*sqrt(buf[i]-min))/c); //補正
少し実行速度が上がりました!
ありがとうございます(^-^)

しかし、今までの補正の式で一番白く表示されていたところが、黒飛びしてしまいました。
試しにcを、unsigned int型で宣言してみたのですが、変わりません。
原因が分からないのですが、よろしければ教えていただけるとうれしいです。

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 15:18
by h2so5
sqrtの戻り値は小数ですから、cをdouble型で宣言してみてください。

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 15:25
by いちこ
>>h2so5さん
返信ありがとうございます!
無事黒飛びを直すことができました…!

1番始めの質問の補足なのですが…
上の処理(1枚読み込んで、1枚書き出す)と、下の処理(1画素読み込んで、1画素書き出す)との処理速度がほとんど変わりません。
1枚いっきに読み込み書き出す方が、処理速度は早いと思っていたのですが、これはなぜなのでしょうか。
上のプログラムの方で改善できる点を教えていただけるとうれしいです。
よろしくおねがいします。

※a,bはunsigned char型の変数です。

コード:

  for(i=0; i<1600*1600; i++){
    
    a=fgetc(fp);
    
    if(a>max) b=255;
    else if(a<min) b=0;
    else{
      b=(char)((255*sqrt(a-min))/c); //補正 
    }
    
    fputc(b,fp_adjusted);
  }

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 15:36
by softya(ソフト屋)
OSに依存(WindowsとLinuxでやり方が違います)しますがファイルを非同期アクセスしたほうが処理速時間は短くなる可能性があります。
ただ、コードの難易度とCPU使用率が上がります。

[今の処理]
(1)読み込み→(2)処理→(3)書き出し
それぞれの時間が(1)(2)(3)の合計として必要。

[非同期アクセス]
(1)読み込み
(2)処理
(3)書き出し
がブロック単位で(1)(2)(3)で同時に可能。ただし、最初のブロックは読み出しだけ、最後のブロックは書き出しだけが必要。
読み込みと書き出しが同じディスクだと多少読み込みと書き出しが遅くなるかも。

こんなイメージ

コード:

ブロック1	(1)読み込み	→	(2)処理		→	(3)書き出し
ブロック2					(1)読み込み	→	(2)処理		→	(3)書き出し
ブロック3									(1)読み込み	→	(2)処理		→(3)書き出し
 ・
 ・

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 15:48
by h2so5
補正値が最大で256通りしかないので、予め計算して配列に入れておくのも良いかもしれません。

コード:

  char table[256];
  const double c = sqrt(max-min);
  for (i = 0; i < 256; i++) {
      table[i] = (char)((255*sqrt(i-min))/c);
  }

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 15:49
by いちこ
>>softyaさん
返信ありがとうございます。
非同期アクセスですか…なるほどです。
座学としては習ったことがあるのですが、実際にプログラムを組んだことがまだないので、理解できるまでにとても時間がかかると思いますが、挑戦してみたいと思います。
ただ、現時点では、上のような処理を考えるので手一杯でしたので、もう少し整理してから、非同期アクセスの処理方法について勉強します。
せっかくアドバイスを下さったのに申し訳ございません。
精進いたします。

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 16:03
by いちこ
>>h2so5さん
返信ありがとうございます。
なるほどです!
それならば1600*1600回も計算しなくてもいいですね!
実際にプログラムを作成してみました。
実行結果は正しかったですし、処理速度もかなり上がりましたが、h2so5さんが考えておられる処理と一致しているかどうか確認していただけるとうれしいです。

コード:

  for(i=0; i<256; i++){
    if(i>max) table[i]=255;
    else if(i<min) table[i]=0;
    else{
      table[i]=(char)((255*sqrt(i-min))/c);
    }
  }
  
  fread(buf,1,1600*1600,fp);
  
  for(i=0; i<1600*1600; i++){ 
    buf2[i]=table[buf[i]];
  }
  
  fwrite(buf2,1,1600*1600,fp_adjusted);

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 16:59
by h2so5
はい、そのとおりです。
さらに高速化しようとすると処理が複雑になったりハードウェアに依存するプログラムになってしまうので、
基本的にはこれで限界ではないかと思います。

Re: 画像処理プログラムの、処理の改善点を教えて下さい。

Posted: 2012年12月02日(日) 17:10
by いちこ
>>h2so5さん
返信ありがとうございます!
良かったです(^-^)
丁寧に答えてくださって有難うございました。

では、次からはsoftyaさんがおっしゃっていたようなことを考えなければいけないですね。勉強したいと思います。
これで、このトピックは解決済みということにさせていただきます。
有難うございました!