【问题标题】:Combine two image with two point of each image with html5 canvas将两个图像与每个图像的两个点与html5画布结合起来
【发布时间】:2021-09-04 18:10:12
【问题描述】:

我尝试合并两张图片。

  1. 每张图片都有不同的大小和比例。
  2. 每张图片都有两个匹配点。
  3. 一张图片作为背景,另一张在其上绘制。

我想合并像这张示例图片这样的图像。 (黑色为背景)

我知道每个点的归一化值和每个图像的大小像这样

  • 黑色尺寸:500x500
  • 黑点:[0.15, 0.25], [0.74, 0.5]
  • 绿色尺寸:200x90
  • 绿色点:[0.05, 0.85], [0.86, 0.12]

我尝试与角度功能结合,但我没有用html5画布很好地做到这一点。 我怎样才能很好地匹配这些点?

【问题讨论】:

  • 数组中的点代表什么?不是像素,不是百分比。它们是什么?
  • 点均值归一化值

标签: javascript math html5-canvas


【解决方案1】:

您首先需要计算要应用于绿色矩形的变换,使其第一个点与黑色的第一个点重叠。

const translate = {
  x: black_points[ 0 ].x - green_points[ 0 ].x,
  y: black_points[ 0 ].y - green_points[ 0 ].y
};

然后你需要找到由两点组成的绿色“线”与黑色“线”方向相同的角度。
这可以通过找到两点之间的角度(使用Math.atan2())并简单地减去两条线的结果来完成。

const angle = getRotation( black_points ) - getRotation( green_points );

最后,您需要确定将绿线缩放到与黑线一样大需要多少。这就是简单的求它们各自距离的比值,可以用Math.hypot()计算。

const scale = getDistance( black_points) / getDistance( green_points );

但是,请注意,由于我们计算了相对于第一个点的旋转和缩放,我们需要在应用这些变换之前将变换原点移动到该点。

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

// we'll start by converting our relative points to absolute coords
const black_rect = { width: 500, height: 500 };
const black_points = [
  [0.15, 0.25],
  [0.74, 0.5]
].map( ([x, y]) => new DOMPoint( x * black_rect.width, y * black_rect.height ) );

const green_rect = { width: 200, height: 90 };
const green_points = [
  [0.05, 0.85],
  [0.86, 0.12]
].map( ([x, y]) => new DOMPoint( x * green_rect.width, y * green_rect.height ) );

// move the first green point so it overlaps the black one
const translate = {
  x: black_points[ 0 ].x - green_points[ 0 ].x,
  y: black_points[ 0 ].y - green_points[ 0 ].y
};
// find the direction so that there is a single vector 
const angle = getRotation( black_points ) - getRotation( green_points );
// by how much to stretch
const scale = getDistance( black_points) / getDistance( green_points );

// first we draw the "black" part untransformed
ctx.fillRect(0, 0, black_rect.width, black_rect.height);
ctx.fillStyle = "red";
black_points.forEach( ({x, y}) => ctx.arc( x, y, 5, 0, Math.PI * 2) );
ctx.fill();

// now we apply the transfrormation we found
// first make both first points overlap
ctx.translate( translate.x, translate.y );
// set the transformation origin on these first points
// because we calculated both the 'angle' and 'scale' relative to this position
ctx.translate( green_points[ 0 ].x, green_points[ 0 ].y );
ctx.rotate( angle );
ctx.scale( scale, scale );
// revert the transformation origin to top-left corner
ctx.translate( -green_points[ 0 ].x, -green_points[ 0 ].y );

// draw the "green" part
ctx.globalAlpha = .5;
ctx.fillStyle = "green";
ctx.fillRect( 0, 0, green_rect.width, green_rect.height );
ctx.beginPath();
ctx.fillStyle = "blue";
green_points.forEach( ({x, y}) => ctx.arc( x, y, 5, 0, Math.PI * 2 ));
ctx.fill();


function getRotation( [ point1, point2 ] ) {
  const dx = point1.x - point2.x;
  const dy = point1.y - point2.y;
  return Math.atan2(dy, dx);
}
function getDistance( [ point1, point2 ] ) {
  const dx = point1.x - point2.x;
  const dy = point1.y - point2.y;
  return Math.hypot( dy, dx );
}
<canvas width="800" height="800"></canvas>

【讨论】:

  • 啊!这太令人沮丧了!我刚刚完成了一个解决方案的工作,当我看到它出现时,我正要发布它。你比我快2分钟!由于我们的解决方案基本相同,请点赞!
猜你喜欢
  • 2014-11-29
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 2011-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多