程序上生成纹理

时间:2013-02-14 19:42:49

标签: php image-manipulation

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

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

Sample http://adamhaskell.net/misc/texture/sample.png

左边是用最近邻插值缩放的矩阵。右边是我对双线性插值的尝试。在大多数情况下它似乎没问题,但是你得到的结构就像在中左边附近有两个对角相邻的橙色方块面对两个对角相邻的红色方块,结果是没有插入该区域。此外,它被视为更像热图(如左上角的橙色丰富所示),并且会导致更多问题。

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

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

2 个答案:

答案 0 :(得分:1)

有几件事情浮现在脑海中:

  1. 您没有插入颜色值。要扩展zakinster的注释,您要插入颜色索引,然后舍入到最接近的颜色索引。这样做的一个结果是你在橙色(索引1)和灰色(索引3)区域之间卷起一条黄色(索引2)。如果你插入了颜色值,那么你最终可能会变成灰橙色?

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

  3. 所以,这里有一些建议:

    1. 如果您不限于4种颜色,请使用更多颜色。插值颜色值(即(128,0,0)与(64,64,64)混合产生(91,32,32))而不是指数。

    2. 如果您仅限于这4种颜色,请尝试某种抖动。一种简单的方法,只需对代码进行最少的更改,就可以为所选的颜色索引添加一些随机性。所以,而不是圆(...),做这样的事情:说你的计算产生值1.7。然后,以70%的概率向上舍入到2,在另外30%的情况下向下舍入到1。这将混合颜色,但它可能会产生非常嘈杂的图像。如果您准备更充分地更改代码,请查看Floyd-Steinberg dithering

答案 1 :(得分:1)

我知道这是老问题,@ markku-k的回答是正确的,无论如何我有类似的问题,这里是我修改过的问题代码

几个通知:

  1. 它在一个中产生2个图像,以显示“原始矩阵”和结果
  2. 它使用8x8矩阵来产生结果,但实际矩阵是10x10以覆盖边界
  3. 它使用基于简单delta的颜色到颜色索引算法,它对我来说没问题
  4. 这是代码:

    <?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;
    

    这是样本结果:

    enter image description here