9

テクスチャを生成するスクリプトを見つけようとしています(その後、グレースケール画像を掛けて「適用」できます)。これまでの私の方法では、RNG をシードし、[0,3] の範囲の整数の 8x8 マトリックスをランダムに生成し、そのマトリックスをあるレベルの補間を使用して 256x256 画像にスケールアップします。

出力例を次に示します (シード値 24)。

サンプル
(出典: adamhaskell.net )

左側は、最近傍補間でスケーリングされた行列です。右側は、双一次補間での私の試みです。ほとんどの場合は問題ないように見えますが、左中央付近のように、斜めに隣接する 2 つのオレンジ色の正方形が対角線上に隣接する 2 つの赤い正方形に面しているような構造が得られます。その結果、その領域は補間されません。さらに、ヒートマップのように扱われているため (左上隅の豊富なオレンジ色で示されているように)、より多くの問題が発生しています.

「双一次補間」のコードは次のとおりです。

<?php
$matrix = Array();
srand(24);
$dim = 256;
$scale = 32;
for($y=0;$y<=$dim/$scale;$y++) for($x=0;$x<=$dim/$scale;$x++) $matrix[$y][$x] = rand(0,3);
$img = imagecreate($dim,$dim);
imagecolorallocate($img,255,255,255);
$cols = Array(
    imagecolorallocate($img,128,0,0),
    imagecolorallocate($img,128,64,32),
    imagecolorallocate($img,128,128,0),
    imagecolorallocate($img,64,64,64)
);
for($y=0;$y<$dim;$y++) {
    for($x=0;$x<$dim;$x++) {
        $xx = floor($x/$scale); $yy = floor($y/$scale);
        $x2 = $x%$scale; $y2 = $y%$scale;
        $col = $cols[round((
            $matrix[$yy][$xx]*($scale-$x2)*($scale-$y2)
            + $matrix[$yy][$xx+1]*$x2*($scale-$y2)
            + $matrix[$yy+1][$xx]*($scale-$x2)*$y2
            + $matrix[$yy+1][$xx+1]*$x2*$y2
        )/($scale*$scale))];
        imagesetpixel($img,$x,$y,$col);
    }
}
header("Content-Type: image/png");
imagepng($img);
exit;

実際には、これはちょっとした XY 問題かもしれません。私が具体的にやろうとしているのは、計画中のゲームでクリーチャーの「ファー パターン」を生成することです。特に、繁殖が2つの親からの要素(色やパターンの要素)を混合できるようにしたいので、ランダムなシードを持つだけでは実際にはうまくいきません。理想的には、ある種のベクトルベースのアプローチが必要ですが、私はそこから抜け出しているので、助けていただければ幸いです。

4

2 に答える 2

1

いくつかのことが思い浮かびます:

  1. 色の値を補間していません。zakinster のコメントを拡張するには、カラー インデックスを補間してから、最も近いものに丸めます。この影響の 1 つは、オレンジ色 (インデックス 1) と灰色 (インデックス 3) の領域の間に黄色 (インデックス 2) の帯ができてしまうことです。代わりに色の値を補間すると、おそらく灰色がかったオレンジになりますか?

  2. 最終的な画像では、黄色とオレンジが多くなり、赤と灰色が少なくなります。これは、round() を使用してカラー インデックスにスナップするためです。あなたの計算 (round() の前) は、0 から 3 の間で均等に分散された float を生成するかもしれませんが、丸めはそれを保持しません。

したがって、ここにいくつかの提案があります:

  1. 4 色に制限されていない場合は、より多くの色を使用してください。インデックスではなく、カラー値を補間します (つまり、(128,0,0) と (64,64,64) を混合すると (91,32,32) が生成されます)。

  2. これらの 4 色だけに制限されている場合は、何らかのディザリングを試してください。コードの変更を最小限に抑える簡単な方法は、選択したカラー インデックスにランダム性を追加することです。したがって、round(...) の代わりに、次のようにします。計算で値 1.7 が生成されるとします。次に、70% の確率で 2 に丸め、残りの 30% の確率で 1 に丸めます。これにより色がブレンドされますが、非常にノイズの多い画像が生成される場合があります。コードを大幅に変更する準備ができている場合は、Floyd-Steinberg ditheringを確認してください。

于 2013-04-25T21:46:32.230 に答える
1

私はそれが古い質問であることを知っています.@markku-kからの回答は正しいですが、とにかく私は同様の問題を抱えています.

いくつかの通知:

  1. 「元のマトリックス」と結果を表示するために、2つの画像を1つに生成します
  2. 結果を生成するために8x8マトリックスを使用しますが、実際のマトリックスは境界をカバーするために10x10です
  3. 単純なデルタに基づく色から色へのインデックスアルゴリズムを使用します。私にとっては問題なく機能します

コードは次のとおりです。

<?php
$matrix = array();
$dim = 256;
$scale = 32;

for($y=0; $y<=9; $y++)
{
    $matrix[$y] = array();
    for($x=0; $x<=9; $x++)
    {
        $same = false;
        do
        {
            $matrix[$y][$x] = mt_rand(0, 3); // do not use rand function, mt_rand provide better results
            if ( ($x>0) && ($y>0) ) // check for checkers siatuion, where no colors are preferable and produce 90 degree angles
            {
                $c1 = $matrix[$y-1][$x-1];
                $c2 = $matrix[$y][$x];
                $c3 = $matrix[$y-1][$x];
                $c4 = $matrix[$y][$x-1];
                $same = ( ($c1==$c2) && ($c3==$c4) );
            }
        } while ($same);
    }
}

$img = imagecreate($dim*2 + 32*4, $dim + 32*2);
$colorsRGB = array(0x800000, 0x804020, 0x808000, 0x404040);
$cols = Array(
        imagecolorallocate($img,128,0,0), // red
        imagecolorallocate($img,128,64,32), // orange
        imagecolorallocate($img,128,128,0), // yellow
        imagecolorallocate($img,64,64,64), // gray
        imagecolorallocate($img,0,0,0), // black, just to fill background
);

imagefilledrectangle($img, 0, 0, $dim*2 + 32*4 - 1, $dim + 32*2 - 1, $cols[4]);

function mulclr($color, $multiplicator)
{
    return array(($color>>16) * $multiplicator, (($color>>8)&0xff) * $multiplicator, ($color&0xff) * $multiplicator);
}

function addclr($colorArray1, $colorArray2)
{
    return array($colorArray1[0]+$colorArray2[0], $colorArray1[1]+$colorArray2[1], $colorArray1[2]+$colorArray2[2]);
}

function divclr($colorArray, $div)
{
    return array($colorArray[0] / $div, $colorArray[1] / $div, $colorArray[2] / $div);
}

function findclridx($colorArray, $usedColors)
{
    global $colorsRGB;

    $minidx = $usedColors[0];
    $mindelta = 255*3;
    foreach ($colorsRGB as $idx => $rgb)
    {
        if (in_array($idx, $usedColors))
        {
            $delta = abs($colorArray[0] - ($rgb>>16)) + abs($colorArray[1] - (($rgb>>8)&0xff)) + abs($colorArray[2] - ($rgb&0xff));
            if ($delta < $mindelta)
            {
                $minidx = $idx;
                $mindelta = $delta;
            }
        }
    }
    return $minidx;
}

for($y=0; $y<($dim+64); $y++)
{
    for($x=0; $x<($dim+64); $x++)
    {
        $xx = $x>>5;
        $yy = $y>>5;
        $x2 = ($x - ($xx<<5));
        $y2 = ($y - ($yy<<5));

        imagesetpixel($img, $x, $y, $cols[$matrix[$yy][$xx]]);

        if ( ($xx>0) && ($yy>0) && ($xx<=8) && ($yy<=8) )
        {
            $color1 = $colorsRGB[$matrix[$yy][$xx]];
            $color2 = $colorsRGB[$matrix[$yy][ ($xx+1) ]];
            $color3 = $colorsRGB[$matrix[ ($yy+1) ][$xx]];
            $color4 = $colorsRGB[$matrix[ ($yy+1) ][ ($xx+1) ]];

            $usedColors = array_unique(array($matrix[$yy][$xx], $matrix[$yy][ ($xx+1) ], $matrix[ ($yy+1) ][$xx], $matrix[ ($yy+1) ][ ($xx+1) ]));

            $a1 = mulclr($color1, ($scale-$x2)*($scale-$y2));
            $a1 = addclr($a1, mulclr($color2, $x2*($scale-$y2)));
            $a1 = addclr($a1, mulclr($color3, ($scale-$x2)*$y2));
            $a1 = addclr($a1, mulclr($color4, $x2*$y2));
            $a1 = divclr($a1, $scale*$scale);
            $clrIdx = findclridx($a1, $usedColors);

            $col = $cols[$clrIdx];
            imagesetpixel($img, $dim+$x+32*2, $y, $col);
        }
    }
}
header("Content-Type: image/png");
imagepng($img);
exit;

サンプル結果は次のとおりです。

ここに画像の説明を入力

于 2013-10-14T22:18:10.803 に答える