【问题标题】:Cropping images with html5 canvas in a non-rectangular shape and transforming使用 html5 画布以非矩形形状裁剪图像并进行转换
【发布时间】:2015-08-14 11:15:42
【问题描述】:

我是 html5 画布的新手,但我正在创建一个基于 html5 画布的图像裁剪器,其中包括下一个功能。

  • 应该将图像裁剪成多边形,但不一定是矩形。
  • 裁剪图像后,应将图像转换为矩形。

我尝试搜索任何满足这些功能的图像裁剪器,但找不到。

我想我可以设法制作调整大小处理程序和裁剪的东西,但我不知道要转换裁剪的图像。 有没有很好的示例或库可以做到这一点?


我正在添加图像以使事情变得清晰。 当您裁剪第一张图像时,结果应该是第二张图像。


添加!

我认为@markE 的解决方案会起作用,但在实施和测试了一些图像之后,我发现它不适用于非平行四边形。

如您所见,由于这种方法将矩形分成两个三角形,弯曲的角度和数量?两个三角形的结果不同。因此,裁剪后的图像显示为失真。 我正在想办法解决它。

【问题讨论】:

  • 我不明白你的第一个要求...所有正方形都是矩形?!
  • @markE mathsisfun.com/geometry/images/quadrilateral-class.gif 只有每个角都是90度的正方形才称为矩形。
  • 我相信你的意思是说“多边形”而不是“正方形”。 :-)
  • @TomKim 那么你最终解决了这个问题吗?
  • @uxder 我最终为该项目构建了自己的库。使用画布的 getContext('2d') 和 createImageData 方法。

标签: html canvas


【解决方案1】:

您要求的内容类似于 Photoshop 的 Perspective Crop Tool

这允许您接收未拉直、倾斜的图像并将其转换为直的、未失真的图像。

http://www.howtogeek.com/howto/30973/easily-straighten-crooked-photographs-in-photoshop/

左:不直、扭曲的图像,右:拉直、未扭曲的图像

您还可以像这样在 html5 画布中拉直和展开 4 边多边形:

  1. 创建第二个目标画布来保存拉直、未变形的图像。
  2. 将扭曲的 4 边多边形分成 2 个三角形。
  3. 计算将第一个扭曲三角形映射到非扭曲三角形所需的变换矩阵。变换矩阵使用其工具(缩放、旋转、倾斜、移动)从扭曲的源三角形中获取每个像素,并将该像素变换到未扭曲的目标三角形上。
  4. 剪切目标画布以仅在计算的目标三角形中绘制。
  5. 将源图像绘制到目标画布上。因为目标画布定义了一个剪切区域,所以图像只会被绘制到该剪切区域中。因为目标画布应用了变换,所以之前扭曲的三角形将被绘制为未扭曲的。
  6. 对第二个弯曲三角形重复步骤 #3-5。

因此,您的变形图像(左侧)可以不变形(如右侧所示):

这是 2 个未弯曲的三角形在缝合在一起形成 1 个未弯曲的矩形之前的样子:

这是示例代码和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvas1=document.getElementById("canvas1");
var ctx1=canvas1.getContext("2d");

// anchors defining the warped rectangle
var anchors={
  TL:{x:70,y:40},      // r
  TR:{x:377,y:30},     // g
  BR:{x:417,y:310},    // b
  BL:{x:70,y:335},     // gold
}

// cornerpoints defining the desire unwarped rectangle
var unwarped={
  TL:{x:0,y:0},        // r
  TR:{x:300,y:0},      // g
  BR:{x:300,y:300},    // b
  BL:{x:0,y:300},      // gold
}

// load example image
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/skewed1.png";
function start(){

  // set canvas sizes equal to image size
  cw=canvas.width=canvas1.width=img.width;
  ch=canvas.height=canvas1.height=img.height;

  // draw the example image on the source canvas
  ctx.drawImage(img,0,0);

  // unwarp the source rectangle and draw it to the destination canvas
  unwarp(anchors,unwarped,ctx1);

}


// unwarp the source rectangle
function unwarp(anchors,unwarped,context){

  // clear the destination canvas
  context.clearRect(0,0,context.canvas.width,context.canvas.height);

  // unwarp the bottom-left triangle of the warped polygon
  mapTriangle(context,
              anchors.TL,  anchors.BR,  anchors.BL,
              unwarped.TL, unwarped.BR, unwarped.BL
             );

  // eliminate slight space between triangles
  ctx1.translate(-1,1);

  // unwarp the top-right triangle of the warped polygon
  mapTriangle(context,
              anchors.TL,  anchors.TR,  anchors.BR,
              unwarped.TL, unwarped.TR, unwarped.BR
             );

}


// Perspective mapping: Map warped triangle into unwarped triangle
// Attribution: (SO user: 6502), http://stackoverflow.com/questions/4774172/image-manipulation-and-texture-mapping-using-html5-canvas/4774298#4774298
function mapTriangle(ctx,p0, p1, p2, p_0, p_1, p_2) {

  // break out the individual triangles x's & y's
  var x0=p_0.x, y0=p_0.y;
  var x1=p_1.x, y1=p_1.y;
  var x2=p_2.x, y2=p_2.y;
  var u0=p0.x,  v0=p0.y;
  var u1=p1.x,  v1=p1.y;
  var u2=p2.x,  v2=p2.y;

  // save the unclipped & untransformed destination canvas
  ctx.save();

  // clip the destination canvas to the unwarped destination triangle
  ctx.beginPath();
  ctx.moveTo(x0, y0);
  ctx.lineTo(x1, y1);
  ctx.lineTo(x2, y2);
  ctx.closePath();
  ctx.clip();

  // Compute matrix transform
  var delta   = u0 * v1 + v0 * u2 + u1 * v2 - v1 * u2 - v0 * u1 - u0 * v2;
  var delta_a = x0 * v1 + v0 * x2 + x1 * v2 - v1 * x2 - v0 * x1 - x0 * v2;
  var delta_b = u0 * x1 + x0 * u2 + u1 * x2 - x1 * u2 - x0 * u1 - u0 * x2;
  var delta_c = u0 * v1 * x2 + v0 * x1 * u2 + x0 * u1 * v2 - x0 * v1 * u2 - v0 * u1 * x2 - u0 * x1 * v2;
  var delta_d = y0 * v1 + v0 * y2 + y1 * v2 - v1 * y2 - v0 * y1 - y0 * v2;
  var delta_e = u0 * y1 + y0 * u2 + u1 * y2 - y1 * u2 - y0 * u1 - u0 * y2;
  var delta_f = u0 * v1 * y2 + v0 * y1 * u2 + y0 * u1 * v2 - y0 * v1 * u2 - v0 * u1 * y2 - u0 * y1 * v2;

  // Draw the transformed image
  ctx.transform(
    delta_a / delta, delta_d / delta,
    delta_b / delta, delta_e / delta,
    delta_c / delta, delta_f / delta
  );

  // draw the transformed source image to the destination canvas
  ctx.drawImage(img,0,0);

  // restore the context to it's unclipped untransformed state
  ctx.restore();
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4>Warped image transformed into an unwarped image.</h4>
<canvas id="canvas" width=300 height=300></canvas>
<canvas id="canvas1" width=300 height=300></canvas>

【讨论】:

  • 我尝试了一些示例并编辑了内容。请检查!
  • 如果我表现得粗鲁,我很抱歉。我从来没有这个意思。我只是对系统不熟悉。我会问一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-25
  • 1970-01-01
相关资源
最近更新 更多