1. ホーム
  2. c

[解決済み] rand()を使用すると、なぜこのような特殊な色パターンになるのですか?

2022-04-23 23:20:44

質問

このような画像ファイルを作成しようとしました。

uint8_t raw_r[pixel_width][pixel_height];
uint8_t raw_g[pixel_width][pixel_height];
uint8_t raw_b[pixel_width][pixel_height];
uint8_t blue(uint32_t x, uint32_t y)
{
    return (rand()%2)? (x+y)%rand() : ((x*y%1024)%rand())%2 ? (x-y)%rand() : rand();
}
uint8_t green(uint32_t x, uint32_t y)
{
    return (rand()%2)? (x-y)%rand() : ((x*y%1024)%rand())%2 ? (x+y)%rand() : rand();
}
uint8_t red(uint32_t x, uint32_t y)
{
    return (rand()%2)? (y-x)%rand() : ((x*y%1024)%rand())%2 ? (x+y)%rand() : rand();
}

for (y=0; y<pixel_height; ++y)
{
    for (x=0; x<pixel_width; ++x)
    {
        raw_b[x][y]=blue(x, y);
        raw_g[x][y]=green(x, y);
        raw_r[x][y]=red(x, y);
    }
}

ランダムなもの(ホワイトノイズ)が出てくると思っていました。しかし、出力は面白い。

その理由をご存知ですか?


編集

とは何の関係もないことが、今、明らかになりました。 rand() .

また、次のコードも試してみてください。

for (x=0; x<pixel_width; ++x)
    for (y=0; y<pixel_height; ++y)
    {
        r[x][y] = (x+y);
        g[x][y] = (y-x);
        /* b[x][y] = rand()%2? x : y; */
    }

解決方法は?

私は当初、他の皆さんと同じ答えになるつもりでした。 rand() . しかし、私はそうすることを考え、代わりにあなたの数学が実際に生成している分布を分析しました。

TL;DR:このパターンは乱数発生器とは関係なく、単にプログラムが数字を操作していることに起因しています。

どれも似たようなものだから、あなたの青い関数にこだわります。

uint8_t blue(uint32_t x, uint32_t y) {
    return (rand() % 2)                  ? (x + y) % rand() :
           ((x * y % 1024) % rand()) % 2 ? (x - y) % rand() :
                                           rand();
}

各画素の値は3つの関数から選択される。 (x + y) % rand() , (x - y) % rand() および rand() ;

それぞれ単独で生成される画像を見てみましょう。

  • rand()

これは期待通りのもので、ただのノイズです。これをイメージCと呼びます。


  • (x + y) % rand()

ここでは、ピクセル座標を足し合わせて、乱数で割った余りを取っています。画像のサイズが1024x1024の場合、合計値は[0-2046]の範囲になります。乱数は [0,RAND_MAX] の範囲にあり、RAND_MAX は少なくとも 32k で、システムによっては 20 億になるものもあります。言い換えれば、余りが単に「0」でない確率はせいぜい16分の1です。 (x + y) . したがって、この関数は、ほとんどの場合、+x +y方向に向かって青色が増加するグラデーションを生成するだけです。

しかし、あなたは下位8ビットしか使っていません。 uint8_t そのため、256ピクセル幅のグラデーションのストライプができます。

これをquot;画像A"と呼びます。


  • (x - y) % rand()

ここでは、似たようなことを引き算で行っています。xがyより大きい限り、前の画像と似たようなものになります。しかし、yの方が大きい場合、結果は非常に大きな数字になります。 xy は符号なし(負の結果は符号なし型の範囲の一番上まで回り込む)、次に % rand() が効いて、実際にノイズが出る。

これを「イメージB&Q」と呼びます。

最終的な画像の各ピクセルは、関数を使用してこれら3つの画像のうちの1つから取得されます。 rand() % 2((x * y % 1024) % rand()) % 2 . このうち最初のものは、50%の確率で選ぶと読み取れます( rand() とその低次のビットがあります)。

のクローズアップです。 rand() % 2 が真(白いピクセル)であるため、画像Aが選択されます。

2つ目の機能 ((x * y % 1024) % rand()) % 2 にも問題があります。 rand() は通常、分割するものよりも大きい。 (x * y % 1024) であり、最大でも1023である。そうすると (x*y%1024)%2 は0と1を同じ頻度で生成するわけではありません。奇数と偶数の掛け算は偶数である。偶数と偶数の掛け算も偶数です。奇数に奇数を掛けたものだけが奇数です。 %2 の場合、4分の3が偶数なら、4分の3が0になる。

のクローズアップです。 ((x * y % 1024) % rand()) % 2 が真になり、画像Bが選択されるようになりました。両方の座標が奇数であるところが正確に選択されています。

そして、画像Cを選択できる場所のクローズアップです。

最後に条件を組み合わせると、ここで画像Bが選択されます。

そして、画像Cが選択されているところ。

出来上がった組み合わせは、次のように読むことができます。

50%の確率で画像Aの画素を使用し、残りは画像Bと画像Cから選び、両方の座標が奇数の場合はB、どちらかが偶数の場合はCとする。

最後に、3色で同じことをしても、向きが違うので、パターンはそれぞれの色で異なる向きになり、あなたが見ているような交差した短冊や格子模様ができます。