1

背景:

该应用程序允许用户上传自己的照片,然后将一副眼镜戴在脸上,看看它的样子。在大多数情况下,它工作正常。用户选择两个瞳孔的位置后,我根据瞳孔距离与眼镜中心点之间已知距离的比率自动缩放图像。那里一切正常,但现在我需要自动将眼镜图像放在眼睛上。

我正在使用 KinectJS,但问题不在于该库或 javascript.. 它更多的是算法要求

我必须做什么:

  1. 瞳孔之间的距离(眼睛)
  2. 瞳孔之间的距离(眼镜)
  3. 眼镜宽度
  4. 眼镜高度
  5. 缩放比例

一些代码:

//.. code before here just zooms the image, etc..

//problem is here (this is wrong, but I need to know what is the right way to calculate this)
var newLeftEyeX = self.leftEyePosition.x * ratio;
var newLeftEyeY = self.leftEyePosition.y * ratio;

//create a blue dot for testing (remove later)
var newEyePosition = new Kinetic.Circle({
    radius: 3,
    fill: "blue",
    stroke: "blue",
    strokeWidth: 0,
    x: newLeftEyeX,
    y: newLeftEyeY
});
self.pointsLayer.add(newEyePosition);

var glassesWidth = glassesImage.getWidth();
var glassesHeight = glassesImage.getHeight();

// this code below works perfect, as I can see the glasses center over the blue dot created above
newGlassesPosition.x = newLeftEyeX - (glassesWidth / 4);
newGlassesPosition.y = newLeftEyeY - (glassesHeight / 2);

需要

一个数学天才给我算法来确定图像大小调整后新的左眼位置应该在哪里

更新

在过去 6 个小时左右研究了这个之后,我想我需要做一些“翻译变换”,但我看到的例子只允许通过 x 和 y 量来设置它。而我只会知道底层图像。这是我找到的示例(对我没有帮助):

http://tutorials.jenkov.com/html5-canvas/transformation.html

这是一些看起来很有趣的东西,但它适用于 Silverlight:

获取变换后的元素位置

有没有办法在 Html5 和/或 KinectJS 中做同样的事情?或者也许我在这里走错了路……有什么想法吗?

更新 2

我试过这个:

// if zoomFactor > 1, then picture got bigger, so...
if (zoomFactor > 1) {
    // if x = 10 (for example) and if zoomFactor = 2, that means new x should be 5
    // current x / zoomFactor => 10 / 2 = 5
    newLeftEyeX = self.leftEyePosition.x / zoomFactor;
    // same for y
    newLeftEyeY = self.leftEyePosition.y / zoomFactor;
}
else {
    // else picture got smaller, so...
    // if x = 10 (for example) and if zoomFactor = 0.5, that means new x should be 20
    // current x * (1 / zoomFactor) => 10 * (1 / 0.5) = 10 * 2 = 20
    newLeftEyeX = self.leftEyePosition.x * (1 / zoomFactor);
    // same for y
    newLeftEyeY = self.leftEyePosition.y * (1 / zoomFactor);
}

那没有用,所以我尝试了Rody Oldenhuis的建议的实现(感谢Rody):

var xFromCenter = self.leftEyePosition.x - self.xCenter;
var yFromCenter = self.leftEyePosition.y - self.yCenter;

var angle = Math.atan2(yFromCenter, xFromCenter);
var length = Math.hypotenuse(xFromCenter, yFromCenter);

var xNew = zoomFactor * length * Math.cos(angle);
var yNew = zoomFactor * length * Math.sin(angle);

newLeftEyeX = xNew + self.xCenter;
newLeftEyeY = yNew + self.yCenter;

但是,这仍然没有按预期工作。所以,我不确定目前的问题是什么。如果有人以前使用过 KinectJS 并且知道问题可能是什么,请告诉我。

更新 3

我在纸上检查了罗迪的计算,它们看起来很好,所以这里显然有其他东西把事情搞砸了。我在缩放因子 1 和 2 处得到了左瞳孔的坐标。有了这些坐标,也许有人可以找出问题所在是:

缩放系数 1:x = 239,y = 209

缩放系数 2:x = 201,y = 133

4

1 回答 1

3

好的,因为这是一个算法问题,我将保持这个通用性并且只编写伪代码。

如果我理解正确,您想要的是以下内容:

  1. 变换所有坐标,使坐标系的原点位于缩放中心(通常是中心像素)

  2. 计算从这个新原点到兴趣点的直线与正 x 轴的夹角。计算这条线的长度。

  3. 缩放后的新 x 和 y 坐标是通过拉长这条线来定义的,使得新线是缩放因子乘以原始线的长度。

  4. 将新找到的 x 和 y 坐标转换回对计算机有意义的坐标系(例如,左上像素 = 0,0)

  5. 对所有兴趣点重复。

在伪代码中(带有公式):

x_center = image_width/2
y_center = image_height/2

x_from_zoom_center = x_from_topleft - x_center
y_from_zoom_center = y_from_topleft - y_center

angle  = atan2(y_from_zoom_center, x_from_zoom_center)
length = hypot(x_from_zoom_center, y_from_zoom_center)

x_new = zoom_factor * length * cos(angle)
y_new = zoom_factor * length * sin(angle)

x_new_topleft = x_new + x_center
y_new_topleft = y_new + y_center

请注意,这假设用于长度和宽度的像素数在缩放后保持不变。另请注意,应该进行一些舍入(保持所有双精度,并且在所有计算后只舍入为 int)

在上面的代码中,atan2是四象限反正切,在大多数编程语言中都可用,并且hypot是简单sqrt(x*x + y*y)的,但计算得更仔细(例如,为了避免溢出等),在大多数编程语言中也可用。

这真的是你所追求的吗?

于 2012-08-10T08:40:32.593 回答