ホワイトノイズ画像を作成するには?


0779  2003-11-06 19:11:10  No: 52410  IP: [192.*.*.*]

C言語にて、ホワイトノイズ画像を作成するにはどのようにしたらいいでしょうか??
画像サイズは64*64,128*128等の縦横が同じサイズです。
どなたかヒントを下さい!

編集 削除
なーめ  2003-11-29 17:19:26  No: 52411  IP: [192.*.*.*]

ホワイトノイズを録音したファイルのWaveヘッダを取り除き、
BMPヘッダをくっつけて出来上がりというのではダメ?

rand() を使ってもできそうだが、乱数系列には限りがありそう。

編集 削除
AUT`s  2003-12-01 11:58:09  No: 52412  IP: [192.*.*.*]

正確さが必要(画像処理用などに)ならば、FFTなどを使用しなくちゃダメんだろうけど、数学者じゃないので解説はできんに。
まぁ、実際には人間の目がホワイトノイズとランダムの違いを見出しづらいという特性を生かして、適当に作っちゃうけどね。

関係ないけど、RIFFのフォーマットじゃかなりムリがあると思うが。
*PEG系などのDCTが掛かったデータならまだわかるけど。

編集 削除
0779  2003-12-01 16:11:19  No: 52413  IP: [192.*.*.*]

皆さんありがとうございます!
rand()を使用して作成することにしてみます。
いろいろなヒントを頂いたので、それらも試してみようと思います!!

編集 削除
なーめ  2003-12-04 03:28:43  No: 52414  IP: [192.*.*.*]

解決ボタンが押されていないので追加発言。
眠いのでだらだらと、書いています。
文章がきっちり整理できていませんが、ご了承ください。

rand() の限界とは。

ダイアログアプリで OnOK() を以下のようにつくり、
OK ボタンを押します。(エディットコントロール1個、m_csEdit1 追加)

void CT01Dlg::OnOK() 
{
  UpdateData(TRUE);
  srand(1);
  int n = rand();
  m_csEdit1.Format("%d",n);
  UpdateData(FALSE);  
//  CDialog::OnOK();
}

何度 OK を押しても同じ値(私のところでは41だった)が出てきます。
この理由をちゃんと把握したうえで、rand() を使用してください。

何が言いたいかというと、
rand() で得られる値はシステムに存在するランダムな数値の表を
取り出しているにすぎないということです。
表の1番目の値は常に同じです。srand() は何番目の表を使うか
を指定するだけだと考えてください。(もしかしたら開始位置を
変えているだけかもしれません)だから、異なるホワイトノイズ
画像を何枚も必要とする場合には不適当です。rand() で得られる
値が表の最後になると再び最初から取り出すことになります。
こうなると周期性が現れてきます。
ゲームなどで少数のランダム値がほしい場合は srand( time(NULL));
で間に合いますが、連続して多数のランダム値を必要とする場合には
不適当だと考えるわけです。

>> 関係ないけど、RIFFのフォーマットじゃかなりムリがあると思うが。
ホワイトノイズの wave のことかな?
だとしたら、誤解なんですが、
別に wave はホワイトノイズにこだわらないのです。
wave の 4 bytes 単位のデータをそのまま 3 bytes R/G/B 単位
として扱うことで、
>> ホワイトノイズとランダムの違いを見出しづらいという特性を生かして、
>> 適当に作っちゃう
という意味です。
確かに無理があります、各RGBダイナミックレンジ 0-0xFF にきれいに
分散してくれるかどうかですね。

情報理論的お手軽解決法としては、
あるファイルを zip で何回か圧縮し、
これ以上圧縮できないくらい圧縮したファイルに対して、
上記ヘッダ差し替えを行う手もあります。
これなら、圧縮するファイルを交換することによりいくらでも
異なる画像が得られます。

.... って1枚だけでよかったのかしら.....

なお、
DCT : ディスクリートコサイントランスフォーム
FFTの実部だけの処理ってこと。
exp(j*w*t) = cos(w*t) - j*sin(w*t)
ね。
(j: 高校の数学なら i を使う、虚数単位。私、元電子工学専攻なので j です)

実際、やってみましょうか。

上のダイアログアプリにボタン1個追加、
もろ、rand() による回答。

void CT01Dlg::OnButton1() 
{
  BITMAPFILEHEADER fh;
  BITMAPCOREHEADER ch;
  BYTE data[640*480*3];
  FILE * fp;
  int c;

  srand(1);
  for( c = 0; c < 640*480*3; c ++ )
  {
    data[c] = (BYTE)( rand() % 0xFF );
  }
  fh.bfType = *(WORD*)"BM";
  fh.bfReserved1 = fh.bfReserved2 = 0;
  fh.bfOffBits = (sizeof(fh) + sizeof(ch));
  fh.bfSize = fh.bfOffBits + sizeof(data);
  ch.bcBitCount = 24;
  ch.bcWidth = 640;
  ch.bcHeight = 480;
  ch.bcPlanes = 1;
  ch.bcSize = sizeof(ch);
  if( fp = fopen( "I:\\Projects\\test\\T01\\img1.bmp","wb" ))
  {
    fwrite( &fh, 1, sizeof(fh), fp );
    fwrite( &ch, 1, sizeof(ch), fp );
    fwrite( &data, 1, sizeof(data), fp );
    fclose( fp );
  }
}

これで見かけ上、きれいなランダムなファイルが1枚得られました。
何度 OK を押しても同じ画像しか得られません。
微妙に紫色に見えるのは気のせい?
当然のことではありますが jpeg で保存するとランダム性が失われます。
ある画像ソフトでロードして、jpeg(75%)で保存し、再度開いてみたら、
溶けてました。(^^;;

ついでだから zip 圧縮ファイルの方法もやってみます。
上のダイアログアプリにさらに
ドラッグアンドドロップの許可を与え、
WM_DROPFILES ハンドラを追加した。


#include <sys/types.h>
#include <sys/stat.h>

void CT01Dlg::OnDropFiles(HDROP hDropInfo) 
{
  struct stat st;
  char s[272];
  BITMAPFILEHEADER fh;
  BITMAPCOREHEADER ch;
  BYTE data[640*480*3];
  FILE * fp;

  if(! hDropInfo ) return;  //  for the 念
  DragQueryFile( hDropInfo, 0, s, 272 );
  if( stat( s, &st )) return;  //  for the 念
  //  ↓落とした(Drop)ファイルが小さすぎる
  if( st.st_size < 921626 + 256 - 26 ) return;
  if( fp = fopen( s, "rb" ))
  {
    fread( &data, 1, 256, fp );
    fread( &data, 1, sizeof(data), fp );
    fclose( fp );
  }
  fh.bfType = *(WORD*)"BM";
  fh.bfReserved1 = fh.bfReserved2 = 0;
  fh.bfOffBits = (sizeof(fh) + sizeof(ch));
  fh.bfSize = fh.bfOffBits + sizeof(data);
  ch.bcBitCount = 24;
  ch.bcWidth = 640;
  ch.bcHeight = 480;
  ch.bcPlanes = 1;
  ch.bcSize = sizeof(ch);
  if( fp = fopen( "I:\\Projects\\test\\T01\\img2.bmp","wb" ))
  {
    fwrite( &fh, 1, sizeof(fh), fp );
    fwrite( &ch, 1, sizeof(ch), fp );
    fwrite( &data, 1, sizeof(data), fp );
    fclose( fp );
  }
}

顛末:
スキャナで取った写真の圧縮ファイルで試す。
前言撤回したくなる画像が得られた。
rand() の場合のような紫色っぽいランダム画像なのですが
妙に横に線が走ってます。
圧縮したファイルにもよるかもしれません。
このプロジェクトの bsc の圧縮ファイルで挑戦
上半分はきれいなランダムだが、下半分がやはり横線入り。

うーむうまい手はないものか。
そうだ、rand() 値と組み合わせれば ...
ファイルから得たランダムになりきらない(?)値に
rand() から得た値で XOR をとってみる。
ファイル読み込み直後に以下を追加。

  for( c = 0; c < 640*480*3; c ++ )
  {
    data[c] ^= (BYTE)( rand() % 0xFF );
  }


顛末:
まあ、OKです。
落とすファイルにより異なるランダム画像が得られました。
これで、落とすファイルごとにおおむね相関のないランダム画像が
得られていると思います。
画像をお見せできないのが残念ですが、非常に簡単ですのでやってみてください。

... でもなんかすっきりしないなー。(鬱);;

編集 削除
tetrapod  2003-12-04 08:27:07  No: 52415  IP: [192.*.*.*]

rand() の限界については御意。
この種の「真の乱数」に出来る限り近い擬似乱数が欲しいときは
MT (mersenne twister) が良いです。
http://www.math.keio.ac.jp/~matumoto/mt.html

編集 削除