如何裁剪多边形外的区域?
Posted
技术标签:
【中文标题】如何裁剪多边形外的区域?【英文标题】:Howto crop area outside polygon? 【发布时间】:2012-03-06 08:33:34 【问题描述】:我想在 php 中使预定义多边形之外的任何东西都透明。比方说,你有你的头的形状,那么图像的其他任何东西都应该被分箱。 提前非常感谢! 为了让自己清楚,这是我一直在处理的一些代码:
$dat = dirname(__FILE__)."/foto_".time().".png";
$img = imagecreatefrompng("foto.png");
$points = array(93,36,147,1,255,-5,294,37,332,114,327,189,315,249,303,291,290,327,260,360,205,404,165,407,131,376,86,325,62,236,61,155,66,96,77,57,87,45);
$schwarz = ImageColorAllocate ($img, 0, 0, 0);
imagefilledpolygon($img, $points, count($points)/2, $schwarz);
imagepng($img, $dat);
原图在here,结果在here。所有除了黑色区域都应该被丢弃。
【问题讨论】:
请尝试启动,当卡住邮政编码时。 鉴于 PHP 不是图形语言,您需要告诉我们您是如何尝试显示这个“多边形”的。您是否正在尝试生成图像?如果是这样,您使用的是哪个扩展程序?你想用 CSS 做这个吗?请详细说明您期望的最终结果是什么以及您期望它在哪里可见。 好的,请考虑以下示例:chipwreck.de/blog/software/cwcrop/cwcrop-demo。现在我不希望光区被裁剪,而是变暗。此外,这不应该是一个矩形,而是一个多边形。然后将结果与另一个图像合并(我已经知道该怎么做)。 那么您是说要从图像中删除突出显示的正方形,还是删除所有除了突出显示的正方形? 我想删除除突出显示区域之外的所有内容(不必是正方形) 【参考方案1】:我知道这有点晚了,但我在整个网络上寻找解决此问题的方法,但找不到一体化解决方案。我发现的许多帖子都涉及按像素编辑图像,我不太喜欢这样做。在将来自多个站点的多个样本拼凑在一起后,我得出了以下结论:
resizeCropPolygonImage()
function resizeCropPolygonImage($source, $dest = null,
$newWidth = null, $newHeight = null, $startX = 0, $startY = 0,
$points = array(), $numCoords = 2)
// Added in $numCoords in case we want to do 3D image processing in the future
// (currently we do not process anything other than 2D coordinates)
$points = array(100,115, 124,65, 192,65, 216,115, 192,165, 124,165);
$numPoints = count($points) / $numCoords;
// If there are not enough points to draw a polygon, then we can't perform any actions
if ($numPoints < 3)
return;
// Get the original image's info
list($width, $height, $file_type) = getimagesize($source);
/******* Here I am using a custom function to resize the image *********
******* keeping the aspect ratio. *********
******* You'll have to add in your own re-sizing logic *********
// Resize the source (using dummy vars because we don't want our
// start x & y to be overwritten)
scaleDimensions($width, $height, $newWidth, $newHeight, $dummyX = null, $dummyY = null);
For simplicity sake, I'll just set the width and height to the new width and height
*************************************************************************/
$width = $newWidth;
$height = $newHeight;
switch ($file_type)
case 1:
$srcImage = imagecreatefromgif($source);
if (function_exists(ImageGIF))
$imgType = "gif";
else
$imgType = "jpeg";
break;
case 2:
$srcImage = imagecreatefromjpeg($source);
$imgType = "jpeg";
break;
case 3:
$srcImage = imagecreatefrompng($source);
$imgType = "png";
break;
default:
return;
// Setup the merge image from the source image with scaling
$mergeImage = ImageCreateTrueColor($width, $height);
imagecopyresampled($mergeImage, $srcImage, 0, 0, 0, 0, $width, $height, imagesx($srcImage), imagesy($srcImage));
/******** This is probably the part that you're most interested in *******/
// Create the image we will use for the mask of the polygon shape and
// fill it with an uncommon color
$maskPolygon = imagecreatetruecolor($width, $height);
$borderColor = imagecolorallocate($maskPolygon, 1, 254, 255);
imagefill($maskPolygon, 0, 0, $borderColor);
// Add the transparent polygon mask
$transparency = imagecolortransparent($maskPolygon, imagecolorallocate($maskPolygon, 255, 1, 254));
imagesavealpha($maskPolygon, true);
imagefilledpolygon($maskPolygon, $points, $numPoints, $transparency);
// Apply the mask
imagesavealpha($mergeImage, true);
imagecopymerge($mergeImage, $maskPolygon, 0, 0, 0, 0, $width, $height, 100);
/******* Here I am using a custom function to get the outer *********
******* perimeter of the polygon. I'll add this one in below ********/
// Crop down to just the polygon area
$polygonPerimeter = getPolygonCropCorners($points, $numCoords);
$polygonX = $polygonPerimeter[0]['min'];
$polygonY = $polygonPerimeter[1]['min'];
$polygonWidth = $polygonPerimeter[0]['max'] - $polygonPerimeter[0]['min'];
$polygonHeight = $polygonPerimeter[1]['max'] - $polygonPerimeter[1]['min'];
// Create the final image
$destImage = ImageCreateTrueColor($polygonWidth, $polygonHeight);
imagesavealpha($destImage, true);
imagealphablending($destImage, true);
imagecopy($destImage, $mergeImage,
0, 0,
$polygonX, $polygonY,
$polygonWidth, $polygonHeight);
// Make the the border transparent (we're assuming there's a 2px buffer on all sides)
$borderRGB = imagecolorsforindex($destImage, $borderColor);
$borderTransparency = imagecolorallocatealpha($destImage, $borderRGB['red'],
$borderRGB['green'], $borderRGB['blue'], 127);
imagesavealpha($destImage, true);
imagealphablending($destImage, true);
imagefill($destImage, 0, 0, $borderTransparency);
if (!$dest)
// If no dest was given, then return to browser
header('Content-Type: image/png');
imagepng($destImage);
else
// Output image will always be png
$dest .= '.png';
// Save to destination
imagepng($destImage, $dest);
// Destroy remaining images
imagedestroy($maskPolygon);
imagedestroy($srcImage);
imagedestroy($destImage);
// Only return a value if we were given a destination file
if ($dest)
return $dest;
getPolygonCropCorners()
function getPolygonCropCorners($points, $numCoords)
$perimeter = array();
for ( $i = 0; $i < count($points); $i++ )
$axisIndex = $i % $numCoords;
if (count($perimeter) < $axisIndex)
$perimeter[] = array();
$min = isset($perimeter[$axisIndex]['min']) ? $perimeter[$axisIndex]['min'] : $points[$i];
$max = isset($perimeter[$axisIndex]['max']) ? $perimeter[$axisIndex]['max'] : $points[$i];
// Adding an extra pixel of buffer
$perimeter[$axisIndex]['min'] = min($min, $points[$i] - 2);
$perimeter[$axisIndex]['max'] = max($max, $points[$i] + 2);
return $perimeter;
使用这个功能,我可以把这张图片转过来
进入这个
它可能并不完整,但我认为这绝对是一个很好的起点。
编辑
09/19/2014 - 增加了边框的透明度【讨论】:
如果有任何白色区域并将点发送到您的函数,则有一些未合并的图片。例如:cdn.netmoda.com/items/1092799/cropped_0.jpg.png?i=4 对不起,我不太清楚你的意思。图片的哪一部分没有被合并?有前后照片吗? 您好,感谢您的评论。我解决了我的问题,但也有一个问题。裁剪后的图片边缘非常锐利。我怎样才能让它们更柔软? 我想我不能帮你解决这个问题。不幸的是,这超出了我对该主题的了解范围。如果找不到,请尝试搜索现有的 SO 票证并创建一个新票证。 非常感谢。您的课程可以节省大量时间。再次感谢。继续努力。【参考方案2】:您可以使用ImageArtist,这是我编写的 GD 包装器,可以让图像处理变得异常简单。
查看裁剪多边形的代码,您只需要以百分比或像素值的形式传递坐标
$pentagon = new PolygonShape("./morning.jpeg");
$pentagon->scale(60);
$pentagon->push(new Node(50,0, Node::$PERCENTAGE_METRICS));
$pentagon->push(new Node(75,50, Node::$PERCENTAGE_METRICS));
$pentagon->push(new Node(62.5,100, Node::$PERCENTAGE_METRICS));
$pentagon->push(new Node(37.5,100, Node::$PERCENTAGE_METRICS));
$pentagon->push(new Node(25,50, Node::$PERCENTAGE_METRICS));
$pentagon->build(); //this will build the polygon
$triangle->save("./finalImage.png",IMAGETYPE_PNG);
//see the documentation for many other methods available.
这是最终结果
【讨论】:
以上是关于如何裁剪多边形外的区域?的主要内容,如果未能解决你的问题,请参考以下文章