Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a fisheye effect with PHP GD

Tags:

php

gd

fisheye

Is there a way to do a FishEye (or Barrel transformation) effect on a image with PHP-GD? I found this with some code, but I have a hard time porting it to PHP.

How can I implement a fisheye lens effect (barrel transformation) in MATLAB?

like image 829
Daantje Avatar asked Dec 09 '10 15:12

Daantje


2 Answers

PHP with GD can't do such a thing in an acceptable way, processing an image pixel-by-pixel will be really slow...

Imagick does support a function that enable you to write your own expression (fximage), after that everything will be handled internally within Imagick.

So I've find a way to do what you've requested in Imagick, I've taked the expression from "Scott builds Software" blog - fisheye effect in imagick. You can read the full explanation of the expression in his blog. Further documentation of this function is available at the official ImageMagick site, you can learn there how you can build your own expressions.

Please note that the PHP documentation about the return value is incorrect, I've also commented there. The function return the actual Imagick object.

So here is your code:

<?php
/* Create new object */
$im = new Imagick();
/* Create new checkerboard pattern */
$im->newPseudoImage(100, 100, "pattern:checkerboard");
/* Set the image format to png */
$im->setImageFormat('png');
/* Fill background area with transparent */
$trans = Imagick::VIRTUALPIXELMETHOD_TRANSPARENT;
$im->setImageVirtualPixelMethod($trans);
/* Activate matte */
$im->setImageMatte(true);

/* This is the expression that define how to do the fisheye effect */
$distort_expression = 
'kk=w*0.5;
ll=h*0.5;
dx=(i-kk);
dy=(j-ll);
aa=atan2(dy,dx);
rr=hypot(dy,dx);
rs=rr*rr/hypot(kk,ll);
px=kk+rs*cos(aa);
py=ll+rs*sin(aa);
p{px,py}';

/* Perform the distortion */ 
$im = $im->fxImage($distort_expression);

/* Ouput the image */   
header("Content-Type: image/png");
echo $im;
?>

Anyway, keep in mind that this is still slow, be careful with whatever you do with that...

like image 194
dvb Avatar answered Sep 21 '22 17:09

dvb


But - It is possible with GD and fast!! in comparison with ImageMagick
enter image description here Create a new image with the size of (2*SourceWidth)/PI.
Walk trough each pixel of the new image and find the distance from the center. dsource=hypot(x-centerX,y-centerY)
Find the corresponding distance in the source image by ddest.=2*r*asin(dsource/r)/2
r is the half width of the destination image.
See examples with bench mark: http://meindesign.net/picture2bubble/picture2bubble.php

function fisheye($infilename,$outfilename){
     $im=imagecreatefrompng($infilename);
     $ux=imagesx($im);//Source imgage width(x) 
     $uy=imagesy($im);//Source imgage height(y) 
     $umx=$ux/2;//Source middle
     $umy=$uy/2;
     if($ux>$uy)$ow=2*$uy/pi();//Width for the destionation image
     else $ow=2*$ux/pi();
     $out=imagecreatetruecolor($ow+1,$ow+1); 
     $trans=imagecolortransparent($out,ImageColorAllocate($out,0,0,0));
     imagefill($im,1,1,$trans); 
     for($c=0;$c<imagecolorstotal($im);$c++){//Copy palette
        $col=imagecolorsforindex($im,$c);
        imagecolorset($out,$c,$col[red],$col[green],$col[blue]);
        }
     $om=$ow/2;//destination middle
     for($x=0;$x<=$ow;++$x){//Loop X in destination image
        for($y=0;$y<=$ow;++$y){//Loop y in destination image
           $otx=$x-$om;//X in relation to the middle
           $oty=$y-$om;//Y in relation to the middle
           $oh=hypot($otx,$oty);//distance
           $arc=(2*$om*asin($oh/$om))/(2);
           $factor=$arc/$oh;
           if($oh<=$om){//if pixle inside radius
             $color=imagecolorat($im,round($otx*$factor+$umx),round($oty*$factor+$umy));
             $r = ($color >> 16) & 0xFF;
             $g = ($color >> 8) & 0xFF;
             $b = $color & 0xFF;
             $temp=imagecolorexact($out, $r, $g, $b);
             imagesetpixel($out,$x,$y,$temp);
             }
           }
        }
     imagepng($out,$outfilename);
     }
like image 20
B.F. Avatar answered Sep 23 '22 17:09

B.F.