1

まず、以前の質問を参照していますピクセルごとに画像を変更してデータベースに保存します

ソース画像を秘密にしておくのは難しいため、html5 キャンバスは適していないことがわかりました。そのため、PHP GD ライブラリを使用して目標を達成しようとしています。私はこのライブラリを使ったことがないので、いくつかの問題があります。私は次の機能が必要だと思います

  • ブラウザで画像を作成するための imagecreatetruecolor
  • source-image から RGB を返すための imagecolorallocate
  • ランダムなピクセルを描画するための 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 関数で行き詰っています。あなたが私にスタートアップを与えてくれることを願っています

4

3 に答える 3

3

ランダム関数の「機能」の1つは、疑似ランダムであるということです。つまり、同じシードが与えられると、常に同じシーケンスが出力されます。

したがって、「画像」ごとに保存できます。

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ピクセルのパーセンテージが表示された状態で画像を出力するとします。アルファを使用する必要はありません。

// 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()各反復で、からi番目のピクセルを抽出し$pixelidます。

最後のオプションは、マニュアルページで詳しく説明されているようにarray_shuffle()使用を再実装するmt_randことです(leethost dot comのtimによる例を参照)。

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];
    ...

大きな画像

大きな画像の場合、配列の処理にはコストがかかりすぎ、メモリが不足します。したがって、同じピクセルを繰り返しヒットすることを避けるためにmt_rand()(画像が99%完成すると非常に問題になる可能性があるため、まだ実行可能な1%ピクセルの1つをランダムにヒットする確率はもちろん1%です)、このハックはインデックスとしての別の画像。

これにより、「配列」が2 ^ 24エントリ、つまり1辺が2 ^ 12、つまり4096ピクセルの画像に制限されます。

メモリの節約は非常に大きいです。各画像のピクセルのコストは、約176バイトではなく16バイトになりました(これは私のLinux 64ビットマシンでは)。これは、1024x1024ピクセルの画像に必要なRAMは約17Mのみであることを意味します。

私のシステムでは、このスクリプトは1秒あたり約180kピクセルを処理します(1024x1024の画像は7.4秒で100%処理され、そのうち約2つが画像の読み込みとセットアップに必要でした)。

$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);

最適化

上記のコードにコメント付きのセクションがあります。$position50%を超える場合、たとえば70%の場合、空のイメージを作成して、ピクセルの70%を適切なイメージから空のイメージにコピーすることは意味がありません。空のピクセルの30%を空の画像から適切な画像にコピーして、「黒く塗りつぶす」方が理にかなっています。$newこれは、を交換し$srcて調整するだけで実現できます$position。私はこのコードを完全にテストしていません。だからコメントを残しました。しかし、ぜひお試しください。

実装

PRNGを使用する利点は、画像を保存する必要がないことですがseedposition通常は全部で8バイトしか保存できません。

人物Aが位置1を受け取り、最大5の位置(つまり、画像の5%が表示される)を受け取るように要求し、シードとこの値5を保存して、人物Bに使用すると、人物Bは同じ5を見ることになります。 %その人Aが得た。

元の画像を除いて、画像が保存または読み込まれることなくすべて。

$ _GETパラメータでシードと位置を渡すことができる場合は、ブラウザにさまざまな段階で画像を表示できます(たとえばimage.php?seed=12345678&position=5、5%のピクセルが設定された画像を表示します。パーセンテージの代わりにピクセル数を指定することもできます。もちろん)。

これは、ピクセルがランダムに選択されている限り機能します。人物Aが希望する正確なピクセルを選択できる場合、このアプローチは無効であり、個々のピクセル位置を保存する必要があります。これは、いくつかの方法で実行できます。 (x、y)のカップルをバイナリ形式で保持するフラットファイルを使用するか、画像全体を保存します。後者のアプローチは理解しやすく、各ステップで1つのイメージ全体を保存する必要があるため、これがゲームであり、「再生」する場合は、膨大なディスク容量が必要になる可能性があります。最初のアプローチでは、ピクセルあたり6バイトが合理的に必要になる場合があります。つまり、同じ高さで元の画像の2倍の幅、またはピクセルあたりわずか4バイトの画像に相当します。

于 2012-11-27T17:16:26.330 に答える
0

鬼の助けを借りて、私はそれを部分的に機能させました。

私がしていることは、toplayer を操作することであり、操作後、それを関数 imagecopy でソース イメージとマージします。出力はjpg画像です。

toplayer の操作は、このコードで行われます

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 ではありません。

私を助けてくれる人。

于 2012-11-27T12:41:19.423 に答える
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);

ループで使用できます

于 2012-11-25T19:37:04.927 に答える