我的双线性插值算法有什么问题?

时间:2016-10-05 14:08:56

标签: php algorithm image-processing gd bilinear-interpolation

我正在使用PHP来测试我的双线性算法。为清晰起见,代码未经过优化。

以下是以下代码的作用:

  1. 将原始像素从2x2图像绘制到10x10目标 图片。这些将留下空白像素。
  2. 注意:此处的图像大小调整为10x10到​​100x100,以便更好地查看。

    resized

    1. 插入像素行。
    2. enter image description here

      1. 使用步骤2中的像素行插值从左到右,从上到下的剩余像素:
      2. enter image description here

        但是,它与我在Photoshop中使用双线性重采样得到的结果不匹配:

        enter image description here

        完整源代码:

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

        我错过了什么?

2 个答案:

答案 0 :(得分:1)

Photoshop是正确的。在您的版本中,原始的4个像素值最终位于新图像的极角处,但在正确的双线性插值中,它们最终位于新图像的4个象限的中心。没有超出原始图像边缘的信息,因此photoshop会在边缘进行不断的外推:

2×2:

enter image description here

插值前

10x10:

enter image description here

如果你开始使用3x3图像而不是2x2,那么你的方法会导致原始边缘像素相对于中心像素对最终图像的贡献减少,从而偏向结果。

答案 1 :(得分:-1)

如果仔细观察PS结果,您会注意到在插值之前,像素的大小已经调整了9倍(它们占据了图像角落的3x3)。这显然是为了获得更好或更差的边缘。

如果在插值之前添加用于生成中间图像的逻辑:

intermediate image

...并修改插值算法以省略角落像素块,然后你应该得到相同的结果。