1

PHP を使用して双一次アルゴリズムをテストしています。わかりやすくするために、コードは最適化されていません。

以下のコードが行っていることは次のとおりです。

  1. 2x2 イメージの元のピクセルを 10x10 の宛先イメージにプロットします。これらは空白のピクセルを残します。

注: ここの画像は、見やすくするために 10x10 から 100x100 にサイズ変更されています。

サイズ変更

  1. ピクセルの行を補間します。

ここに画像の説明を入力

  1. ステップ 2 のピクセルの行を使用して、残りのピクセルを左から右、上から下に補間します。

ここに画像の説明を入力

ただし、バイリニア リサンプリングを使用して Photoshop で取得した結果とは一致しません。

ここに画像の説明を入力

完全なソース コード:

<?php
$image1 = imagecreatefrompng( 'test.png' );

$w1 = imagesx( $image1 );
$h1 = imagesy( $image1 );

$w2 = 10;
$h2 = 10;
$image2 = imagecreatetruecolor( $w2, $h2 );

imagefill($image2, 0, 0, imagecolorallocate($image2, 0x4c, 0x4c, 0x8e)); // added bg for pixels to stand-out

function lerp($v0, $v1, $t) {
    return $v0 + $t*($v1-$v0);
}

function getPixel($image, $x, $y){
    $rgb = imagecolorat( $image, $x, $y );
    $r     = ($rgb >> 16) & 0xFF;
    $g     = ($rgb >> 8) & 0xFF;
    $b     = $rgb & 0xFF;
    return array($r,$g,$b);
}

$maxY1 = $h1 - 1;
$maxX1 = $w1 - 1;
$maxY2 = $h2 - 1;
$maxX2 = $w2 - 1;

// plot original pixels from source to destination
for($y = 0; $y <= $maxY1; $y++) { // loop thru src height

    $newY = floor(($y/$maxY1) * $maxY2);

    for ($x = 0; $x <= $maxX1; $x++) { // loop thru src width

        $newX = floor(($x/$maxX1) * $maxX2);
        $rgb = imagecolorat( $image1, $x, $y );
        $r1     = ($rgb >> 16) & 0xFF;
        $g1     = ($rgb >> 8) & 0xFF;
        $b1     = $rgb & 0xFF;

        imagesetpixel( $image2, $newX, $newY, imagecolorallocate( $image2, $r1, $g1, $b1 ) );

    }
}
imagepng( $image2, 'out1.png' );

// interpolate pixels from pixel[1,0] to pixel[8,0]
$y = 0;
$rgb = imagecolorat( $image2, 0, $y );
$r0     = ($rgb >> 16) & 0xFF;
$g0     = ($rgb >> 8) & 0xFF;
$b0     = $rgb & 0xFF;

$rgb = imagecolorat( $image2, 9, $y );
$r1     = ($rgb >> 16) & 0xFF;
$g1     = ($rgb >> 8) & 0xFF;
$b1     = $rgb & 0xFF;
for($x=1; $x <= 8; $x++){
    $t = $x / 9;
    $r = lerp($r0, $r1, $t);
    $g = lerp($g0, $g1, $t);
    $b = lerp($b0, $b1, $t);
    imagesetpixel( $image2, $x, $y, imagecolorallocate( $image2, $r, $g, $b ) );
}
imagepng( $image2, 'out2.png' );

// interpolate pixels from pixel[1,9] to pixel[8,9]
$y = 9;
$rgb = imagecolorat( $image2, 0, $y );
$r0     = ($rgb >> 16) & 0xFF;
$g0     = ($rgb >> 8) & 0xFF;
$b0     = $rgb & 0xFF;

$rgb = imagecolorat( $image2, 9, $y );
$r1     = ($rgb >> 16) & 0xFF;
$g1     = ($rgb >> 8) & 0xFF;
$b1     = $rgb & 0xFF;

for($x=1; $x <= 8; $x++){
    $t = $x / 9;
    $r = lerp($r0, $r1, $t);
    $g = lerp($g0, $g1, $t);
    $b = lerp($b0, $b1, $t);
    imagesetpixel( $image2, $x, $y, imagecolorallocate( $image2, $r, $g, $b ) );
}
imagepng( $image2, 'out3.png' );

// interpolate remaining pixels
for($x=0; $x <= 9; $x++){
    $rgb = imagecolorat( $image2, $x, 0 );
    $r0     = ($rgb >> 16) & 0xFF;
    $g0     = ($rgb >> 8) & 0xFF;
    $b0     = $rgb & 0xFF;

    $rgb = imagecolorat( $image2, $x, 9 );
    $r1     = ($rgb >> 16) & 0xFF;
    $g1     = ($rgb >> 8) & 0xFF;
    $b1     = $rgb & 0xFF;
    for($y = 1; $y <= 8; $y++){
        $t = $y / 9;
        $r = lerp($r0, $r1, $t);
        $g = lerp($g0, $g1, $t);
        $b = lerp($b0, $b1, $t);
        imagesetpixel( $image2, $x, $y, imagecolorallocate( $image2, $r, $g, $b ) );
    }
}
imagepng( $image2, 'out4.png' );

header('Content-type: image/png');
imagepng( $image2);
imagedestroy( $image1 );

私は何が欠けていますか?

4

2 に答える 2

1

フォトショップは正しいです。お使いのバージョンでは、元の 4 ピクセル値は新しい画像の極端な隅に配置されますが、正しいバイリニア補間では、新しい画像の 4 つの象限の中心に配置されます。元の画像の端を超える情報はないため、Photoshop は端で一定の外挿を行います。

2x2:

ここに画像の説明を入力

補間前の 10x10:

ここに画像の説明を入力

2x2 ではなく 3x3 の画像から始めた場合、この方法では、元のエッジ ピクセルが最終的な画像に与える影響が中央のピクセルに比べて減少し、結果に偏りが生じます。

于 2016-10-05T14:43:07.853 に答える
-1

PS の結果をよく見ると、補間前に角のピクセルが 9 倍にサイズ変更されていることがわかります (画像の角で 3x3 を占めています)。これは明らかに、良くも悪くも、よりシャープなエッジを得るために行われます。

補間前に中間画像を生成するロジックを追加すると、次のようになります。

中間イメージ

...そして補間アルゴリズムを変更して角のピクセル ブロックを省略しても、同じ結果が得られるはずです。

于 2016-10-05T14:43:16.613 に答える