1

バックグラウンド:

このアプリを使用すると、ユーザーは自分の写真をアップロードしてから、顔に眼鏡をかけてどのように見えるかを確認できます。ほとんどの場合、正常に動作しています。ユーザーが2つの瞳孔の位置を選択した後、瞳孔の距離と眼鏡の中心点間の既知の距離との比率に基づいて画像を自動ズームします。ここではすべて正常に機能していますが、メガネの画像を目の上に自動的に配置する必要があります。

私は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

Rodyの計算を紙で確認したところ、問題がないように見えたので、明らかに他の何かが混乱しています。ズーム係数1と2で左瞳孔の座標を取得しました。これらの座標を使用すると、誰かが問題を理解できる可能性があります。は:

ズーム率1:x = 239、y = 209

ズーム率2:x = 201、y = 133

4

1 に答える 1

3

OK、これはアルゴリズムの質問なので、これを一般的なものにして、擬似コードのみを記述します。

私はあなたを正しく理解しています、あなたが望むのは次のとおりです:

  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は、はほとんどのプログラミング言語で利用可能な4象限アークタンジェントであり、hypot単純sqrt(x*x + y*y)ですが、より慎重に計算され(たとえば、オーバーフローなどを回避するため)、ほとんどのプログラミング言語でも利用できます。

これは本当にあなたが求めていたものですか?

于 2012-08-10T08:40:32.593 に答える