Rotate a face in JavaScript (Node.js 10)

Viewed 270

I am following a face recognition algorithm but I need to rotate all faces to align them vertically to its rectangle.

The face rectangle is not rotated (its angle is 0) and it contains the full face that has been recognised. The face sometimes is rotated "faceAngle" degrees, so what I have implement is a function that rotate it (the face) "-faceAngle" degrees with the center of the face rectangle as pivot point (the point of reference).

Pd: The face is identified by 20 landmarks.

This is how the face rectangle looks like: https://docs.microsoft.com/es-es/azure/cognitive-services/face/images/face.detection.jpg

Here is my code:

  function rotateFace(face) {
      /*
        This function rotate the face to the rectangle based on the head pose attributes
      */

      // Get the face information
      const { faceRectangle, faceLandmarks, faceAttributes } = face;

      // Head pose's roll value acts directly as the face angle.
      const faceAngle = faceAttributes.headPose.roll; // In degrees

      // The pivot point will be the center of the face rectangle
      const pivotPoint = {
        x: faceRectangle.width / 2,
        y: faceRectangle.height / 2,
      };

      // Rotate each face landmark '-faceAngle' degrees
      const rotatedLandmarks = {};
      for (const [landMark, point] of Object.entries(faceLandmarks)) {
        // Rotate the point and save it in the new rotated landMarks object
        rotatedLandmarks[landMark] = rotatePoint(pivotPoint, point, -faceAngle);
      }

      // Return the rotated face
      return { ...face, faceLandmarks: rotatedLandmarks };

      function rotatePoint(pivotPoint, point, angle) {
        const { x: px, y: py } = pivotPoint;
        const { x, y } = point;

        var radians = (Math.PI / 180) * angle,
          cos = Math.cos(radians),
          sin = Math.sin(radians),
          nx = cos * (x - px) + sin * (y - py) + px,
          ny = cos * (y - py) - sin * (x - px) + py;

        return { x: nx, y: ny };
      }
  }

The problem I am having is that, sometimes, some parts of the rotated face are outside the face rectangle... Does anybody knows what I am doing bad in my algorithm? Or any ideas how to make this easier?

I think the pivot point shouldn't be the one I choosed but it makes sense for my mind...

Thank you.

EXAMPLE

For this photo https://scstylecaster.files.wordpress.com/2017/03/emma-watson-1.jpg

I get this face rectangle:

faceRectangle: {
   top: 90,
   left: 309,
   width: 510,
   height: 510 
}

So the relative-to-rectangle face landmarks should be at the range [0, 510] for the X axis, and [0, 510] for the Y axis

But that I get is:

{
  "eyebrowRightInner": { "x": 257.16357408506883, "y": 37.89185642687593 },
  "underLipTop": { "y": 306.6951578378977, "x": 326.5280833858301 },
  "mouthRight": { "x": 413.55677612276986, "y": 257.5870460792551 },
  "eyebrowLeftInner": { "y": 67.10580836435113, "x": 168.71276847994784 },
  "noseTip": { "y": 206.5354065431846, "x": 289.9445594907593 },
  "noseRootLeft": { "y": 112.52684633627678, "x": 204.9452029765821 },
  "noseRightAlarTop": { "x": 311.41755898744964, "y": 159.77912041377596 },
  "pupilRight": { "x": 315.13546073674706, "y": 48.933158797745136 },
  "pupilLeft": { "x": 106.47397872844112, "y": 137.8818851860268 },
  "upperLipTop": { "y": 280.73055222306243, "x": 312.3126250651826 },
  "eyeRightOuter": { "y": 37.448988851675836, "x": 371.07188751438275 },
  "eyebrowRightOuter": { "y": -16.27549040986449, "x": 413.1946880869507 }, // <------------------ error
  "eyeLeftOuter": { "y": 154.79417336302782, "x": 82.3579154382175 },
  "upperLipBottom": { "y": 302.33231999033967, "x": 324.86506026034 },
  "noseLeftAlarOutTip": { "y": 244.55778079547065, "x": 220.11663487446322 },
  "noseLeftAlarTop": { "x": 220.08119281608163, "y": 200.35236547267908 },
  "eyeLeftBottom": { "y": 154.39022448200217, "x": 120.07378511268632 },
  "noseRightAlarOutTip": { "x": 350.8688839396136, "y": 182.97767553082463 },
  "eyebrowLeftOuter": { "x": 12.151092571862137, "y": 146.8442033623165 },
  "eyeRightBottom": { "x": 337.62439624997774, "y": 64.52859978162735 },
  "eyeLeftTop": { "y": 124.33543005444903, "x": 103.84081459224478 },
  "underLipBottom": { "y": 332.64619899450827, "x": 341.8614934073455 },
  "noseRootRight": { "y": 86.3352712525471, "x": 268.4137100854889 },
  "eyeLeftInner": { "x": 154.06657444677165, "y": 128.0195917006581 },
  "eyeRightInner": { "x": 294.24199118290403, "y": 71.94256839474764 },
  "eyeRightTop": { "x": 320.5652039630463, "y": 34.94002160494745 },
  "mouthLeft": { "y": 346.12770549550777, "x": 220.09672435462016 }
}
1 Answers

I have found the error... It was that the LandMarks were relative-to-image and not relative -to-rectangle, so I had to change them before rotating because the pivot point was relative-to-rectangle.

Just make sure you get the position of each landmark relative to the rectangle before rotating it. Other solution would be to take the center of the rectangle but relative-to-image instead of relative-to-rectangle, and use the original (relative-to-image) landmarks.

Related