将两个图像与每个图像的两个点与 html5 canvas

Combine two image with two point of each image with html5 canvas

我尝试合并两个图像。

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

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

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

我尝试结合angle函数,但是我用html5 canvas做的不好。 怎么才能匹配好这些点呢?

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

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>