首先,我指的是上一个问题Change image per pixel and save to db
我发现html5画布不合适,因为很难保密源图像。这就是我试图用PHP GD库实现目标的原因。我从没与这个图书馆合作过,所以我遇到了一些困难。我想我需要以下功能
用于绘制随机像素的imagesetpixel
$x = 200; //width of image
$y = 200; //height of image
$gd = imagecreatetruecolor ($x, $y);
$color = imagecolorallocate($gd, $r, $g, $b) //not sure how to retrieve the rgb from the source image
Then I need a function for drawing random pixels with imagesetpixel.
imagesetpixel($gd, $posx,$posy, $color); // not sure how to retrieve the x and y position of each pixel.
我不是PHP的明星,这就是我的搜索坚持使用这些GD功能的原因。希望你能给我一个初创公司
答案 0 :(得分:3)
随机函数的一个“特征”是它是伪随机的,即,它将始终输出给定相同种子的相同序列。
所以你可以存储每个“图像”:
sourcefile - the name of the source image
seed - integer, maybe the start time of this sequence
position - number of pixels that need to be shown, or maybe % completion
所以说你要输出图像$sourcefile
,其中种子$seed
和$position
像素百分比可见。你甚至不需要使用alpha:
// Load image
$src = imageCreateFromPNG($sourcefile); // Assume image is PNG
// Create work image
$new = imageCreateTrueColor(ImageSX($src), ImageSY($src)); // new image of same size
mt_srand($seed); // Seed the Mersenne Twister generator
// Number of pixels to set: $position = 0: NONE, $position = 100: ALL
$pixels = round($position*imageSX($src)*imageSY($src)/100);
// Now we have a problem: if we do $pixels attempts, mt_rand might sometimes
// return the same pixel again. So we end up setting less than $pixels pixels.
// So we do this the expensive way, saving an array of yet-to-be-used pixels.
$max = ImageSX($src)*ImageSY($src);
$pixelid = array();
for ($i = 0; $i < $max; $i++)
$pixelid[] = $i;
$W = ImageSX($src);
while($pixels--)
{
// Extract one pixel
$chosen = $pixelid[$idx = mt_rand(0, $pixels)];
array_splice ($pixelid, $idx, 1); // Remove extracted pixel from array
$x = $chosen % $W;
$y = ($chosen - $x)/ $W;
$rgb = imagecolorat($src, $x, $y);
$pix = imagecolorsforindex($src, $rgb);
$rgb = imageColorAllocate($new, $pix['red'], $pix['green'], $pix['blue']);
imageSetPixel($new, $x, $y, $rgb);
}
ImageDestroy($src);
// $new has now exactly $pixels set to the same pixels of $src,
// the rest are undefined (you can fill $new with white beforehand...)
Header("Content-Type: image/png");
ImagePNG($new);
除了拼接数组之外,你可以将“使用过的”像素涂抹掉,即使这不会给出均匀的分布:
$cnt = count($pixelid);
while($pixels--)
{
// Extract one pixel
$idx = mt_rand(0, $cnt);
// If the extracted pixel is null, find next pixel that is unextracted
// and if there are none, restart from the beginning of the array.
while (-1 == ($chosen = $pixelid[$idx]))
if ($cnt == ++$idx)
$idx = 0;
$chosen = $pixelid[$idx];
$pixelid[$idx] = -1;
或者你可以......重试。但是当图像几乎完成时,这可能会很昂贵。
$cnt = count($pixelid);
while($pixels--)
{
// Extract one pixel
for ($idx = mt_rand(0, $cnt); $pixelid[$idx] != -1; $idx = mt_rand(0, $cnt))
;
$chosen = $pixelid[$idx];
$pixelid[$idx] = -1;
如果你不关心图像是否总是以不同的方式重建,你可以使用array_shuffle()
代替mt_rand()
,并且在每次迭代时我从{{1}中提取第i个像素}。
最后一个选项是使用$pixelid
重新实现array_shuffle()
,详见手册页(详见le letiost dot com的示例):
mt_rand
因此,您可以使用function array_new_shuffle(&$items, $seed)
{
mt_srand($seed);
for ($i = count($items) - 1; $i > 0; $i--)
{
$j = @mt_rand(0, $i);
list($items[$i], $items[$j]) = array($items[$j], $items[$i]);
}
}
针对array_new_shuffle()
致电$pixelid
,然后按顺序从混洗数组中提取元素:
$seed
对于大图像,处理数组太贵而且内存不足。因此,为了避免for ($idx = 0; $idx < $pixels; $idx++)
{
$chosen = $pixelid[$idx];
...
重复击中相同的像素(当图像完成99%时可能会出现问题,因此随机击中的可能性之一仍是可行的1%像素当然是1% ),这个hack使用另一个图像作为索引。
这会将“数组”限制为2 ^ 24个条目,即边长为2 ^ 12或4096像素的图像。
节省的内存是巨大的:每个图像像素现在花费16个字节,而不是大约176个(这在我的Linux 64位机器上)。这意味着1024x1024像素的图像只需要大约17M的RAM。
在我的系统上,此脚本每秒处理大约180k像素(1024x1024图像在7.4秒内100%处理,其中大约需要2张图像加载和设置)。
mt_rand()
您会注意到上面代码中的注释部分。如果恰好$seed = 0;
$position = 2;
$sourcefile = '/home/lserni/Lena19721024-filtered.png';
mt_srand($seed); // Seed the Mersenne Twister generator
// Load image
$src = ImageCreateTrueColor(512,512);
// $src = imageCreateFromPNG($sourcefile); // Assume image is PNG
$W = ImageSX($src);
$H = ImageSY($src);
// Total number of pixels
$size = $W*$H;
if (($W > 4095) || ($H > 4095))
die("Image too big");
// Create work image
$new = imageCreateTrueColor($W, $H); // new image of same size
/*
if ($position > 50)
{
$position = 100-$position;
$tmp = $src;
$src = $new;
$new = $tmp;
}
*/
// Number of pixels to set: $position = 0: NONE, $position = 100: ALL
$pixels = round($position*$size/100.0);
// Create a temporary buffer image of the same size
$fix = imageCreateTrueColor($W, $H);
for ($i = 0; $i < $size; $i++)
{
$b = $i & 0xFF;
$g = ($i >> 8) & 0xFF;
$r = ($i >> 16) & 0xFF;
imageSetPixel($fix, $i % $W, floor($i / $W), imageColorAllocate($fix, $r, $g, $b));
}
while($pixels--)
{
// Recover one of the available pixel indexes
$idx = mt_rand(0, $size--);
// Recover index from image
$y = floor($idx / $W);
$x = $idx % $W;
$idx = imageColorAt($fix, $x, $y);
$lst = imageColorAt($fix, $size % $W, floor($size / $W));
$b = $lst & 0xff; $lst >>= 8;
$g = $lst & 0xff; $lst >>= 8;
$r = $lst & 0xff;
imageSetPixel($fix, $x, $y, imageColorAllocate($fix, $r, $g, $b));
// Whew. Now recover true x and y from new $idx
$y = floor($idx / $W);
$x = $idx % $W;
$rgb = imagecolorat($src, $x, $y);
$pix = imagecolorsforindex($src, $rgb);
$rgb = imageColorAllocate($new, $pix['red'], $pix['green'], $pix['blue']);
imageSetPixel($new, $x, $y, $rgb);
}
ImageDestroy($src);
// $new has now exactly $pixels set to the same pixels of $src,
// the rest are undefined (you can fill $new with white beforehand...)
// die("Memory: " . memory_get_peak_usage());
Header("Content-Type: image/png");
ImagePNG($new);
超过50%,比如说70%,那么创建一个空图像并将70%的像素从好图像复制到空图像是没有意义的。将30%的空像素从空图像复制到好图像更有意义,将其“黑化”。只需交换$position
和$new
并调整$src
即可实现此目的。我还没有真正彻底测试过这段代码;这就是我离开它评论的原因。但是欢迎你试一试。
使用PRNG的优势在于您不需要保存任何图像,但只有$position
和seed
- 通常是8个字节。
如果A人收到位置1,并要求接收最多5个位置(即可见图像的5%),并保存种子和该值5,并将其用于B,那么B人将会看到与A相同的5%。
除原始图像外,没有任何图像被保存或加载。
如果你可以在$ _GET参数中传递种子和位置,你可以在浏览器中显示不同阶段的图像(例如position
会显示设置了5%像素的图像。你也可以指定当然,像素数而不是它们的百分比。
只要像素是随机选择的,就可以:如果人A获得选择他或她想要的确切像素,那么这种方法是无效,您需要保存单个像素位置,这可以通过多种方式完成:使用以二进制格式保存(x,y)对的flatfile,或保存整个图像。后一种方法更容易理解,并且需要在每一步都存储一个完整的图像,所以如果这是一个游戏并且你想“重放”它,你可能需要巨大的磁盘空间。第一种方法可能合理地要求每个像素六个字节,即相当于具有相同高度并且是原始宽度的两倍的图像,或者相当于每个像素四个字节的图像。
答案 1 :(得分:0)
将RANDOM_COLOR替换为随机颜色值
这将替换所有像素,
for($i=0;$i < $x;$i++) {
for($e = 0;$e < $y;$e++) {
imagesetpixel($gd, $i,$e, $RANDOM_COLOR);
}
}
如果您只想设置几个随机像素,请确保将它们设置为0和宽度-1,0和高度-1范围
例如
$i = rand(0,$width-1);
$e = rand(0,$height - 1);
imagesetpixel($gd, $i,$e, $RANDOM_COLOR);
你可以在循环中使用它
答案 2 :(得分:0)
在食人魔的帮助下,我得到了部分工作。
我所做的是操纵一个顶层玩家,在操作之后,将它与功能图像复制一起与源图像合并。输出是jpg图像。
使用此代码
完成对玩家的操纵for ($y = 0; $y < imagesy($img); $y++) {
for ($x = 0; $x < imagesx($img); $x++) {
$img = imagecreatefrompng("thecover.png");
imagealphablending($img, false); // Turn off blending
$white_color_transparent = imagecolorallocatealpha($img, 255, 255, 255, 127);
$rgb = imagecolorat($img, $x, $y);
$pixel_color = imagecolorsforindex($img, $rgb);
if ($pixel_color['red'] == 255 && $pixel_color['green'] == 255 && $pixel_color['blue'] == 255){
for ($i = 0; $i < 200; $i++) {
imagesetpixel($img, rand(0,300), rand(0,300), $white_color_transparent);
}
}
}
}
顶层玩家的颜色为白色,RGB(0,0,0)。脚本检查该颜色,并在此时将200个随机像素设置为透明。
它将大量像素设置为透明,但不是给定的200。
可以帮助我的人。