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?
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...
But - It is possible with GD and fast!! in comparison with ImageMagick
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With