9

我正在尝试找出一个将生成纹理的脚本(然后可以将其乘以灰度图像以“应用”它)。到目前为止,我的方法包括播种 RNG,然后随机生成 [0,3] 范围内的整数的 8x8 矩阵,然后使用某种级别的插值将该矩阵放大到 256x256 图像。

这是一个示例输出(种子值 24):

样本
(来源:adamhaskell.net

左侧是使用最近邻插值缩放的矩阵。右边是我对双线性插值的尝试。在大多数情况下,它看起来还不错,但是你会得到像左中附近这样的结构,其中有两个对角相邻的橙色正方形面对两个对角相邻的红色正方形,结果是该区域没有插值。此外,它被更多地视为热图(如左上角大量橙色所示),这会导致更多问题。

这是我的“双线性插值”代码:

<?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 问题。我特别想做的是为我正在计划的游戏中的生物生成“毛皮图案”。特别是我希望能够拥有它,以便繁殖混合来自两个父母的元素(无论是颜色还是图案元素),所以仅仅拥有一个随机种子并不会真正削减它。理想情况下,我需要某种基于矢量的方法,但我已经超出了我的深度,因此非常感谢任何帮助。

4

2 回答 2

1

我想到了几件事:

  1. 您没有插入颜色值。为了扩展 zakinster 的评论,您正在对颜色索引进行插值,然后四舍五入到最接近的值。这样做的一个效果是,您最终会在橙色(索引 1)和灰色(索引 3)区域之间出现一圈黄色(索引 2)。如果您改为插入颜色值,您可能会得到灰橙色?

  2. 最终图像中的黄色和橙色较多,红色和灰色较少。这是因为使用 round() 捕捉到颜色索引。您的计算(在 round() 之前)可能会产生均匀分布在 0 到 3 之间的浮点数,但舍入不会保留它。

所以,这里有一些建议:

  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 个图像,以显示“原始矩阵”和结果
  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 回答