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.
<?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;
?>
无论如何,请记住这仍然很慢,无论你做什么,都要小心......
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...
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);
}
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);
}
发布评论
评论(2)
PHP 和 GD 无法以可接受的方式完成这样的事情,逐像素处理图像会非常慢...
Imagick 确实支持一个函数,使您能够编写自己的表达式(fximage),之后一切都将在 Imagick 内部处理。
所以我找到了一种方法来完成您在 Imagick 中所要求的操作,我从 “Scott 构建软件”博客 - imagick 中的鱼眼效果。您可以在他的博客中阅读该表达式的完整解释。有关此功能的更多文档可在官方 ImageMagick 站点上找到,您可以在那里了解如何可以构建自己的表达式。
请注意,关于返回值的 PHP 文档是不正确的,我也在那里发表了评论。该函数返回实际的 Imagick 对象。
所以这是你的代码:
无论如何,请记住这仍然很慢,无论你做什么,都要小心......
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:
Anyway, keep in mind that this is still slow, be careful with whatever you do with that...
但是 - 与 ImageMagick 相比,可以使用 GD 并且速度更快!!
http://meindesign.net/picture2bubble/picture2bubble.php
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